792 lines
61 KiB
HTML
792 lines
61 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>VNOX</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||
<style>
|
||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||
:root{
|
||
--bg0:#0c0c0c;--bg1:#111111;--bg2:#181818;--bg3:#202020;--bg4:#2a2a2a;
|
||
--accent:#ff6b35;--accent2:#e85d28;
|
||
--border:#222222;--border2:#2e2e2e;
|
||
--text1:#f0f2f5;--text2:#9ca3af;--text3:#4a5568;
|
||
--green:#4ade80;--red:#f87171;--yellow:#fbbf24;--teal:#5bbf9f;
|
||
--font:'IBM Plex Sans',sans-serif;--mono:'IBM Plex Mono',monospace;
|
||
}
|
||
html,body{height:100%;overflow:hidden;background:var(--bg0);color:var(--text1);font-family:var(--font);font-size:14px;-webkit-font-smoothing:antialiased}
|
||
::-webkit-scrollbar{width:3px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--bg4);border-radius:4px}
|
||
|
||
/* ═══ LAYOUT ═══ */
|
||
.app{display:grid;grid-template-columns:56px 228px 1fr 252px;grid-template-rows:1fr 52px;height:100vh}
|
||
|
||
/* ═══ RAIL ═══ */
|
||
.rail{grid-column:1;grid-row:1/3;background:var(--bg1);border-right:1px solid var(--border);display:flex;flex-direction:column;align-items:center;padding:10px 0 14px;gap:6px;overflow:hidden}
|
||
.rail-logo{width:36px;height:36px;border-radius:10px;background:var(--accent);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:border-radius .2s,transform .1s;flex-shrink:0;margin-bottom:4px}
|
||
.rail-logo:hover{border-radius:14px;transform:scale(1.06)}
|
||
.rail-logo svg{width:18px;height:18px;fill:#fff}
|
||
.rail-sep{width:28px;height:1px;background:var(--border);flex-shrink:0;margin:2px 0}
|
||
.srv{width:36px;height:36px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:12px;cursor:pointer;transition:border-radius .2s,transform .1s;position:relative;flex-shrink:0}
|
||
.srv::before{content:'';position:absolute;left:-8px;top:50%;transform:translateY(-50%);width:3px;border-radius:0 3px 3px 0;background:var(--text1);transition:height .15s;height:0}
|
||
.srv:hover{border-radius:14px;transform:scale(1.05)}.srv:hover::before{height:8px}
|
||
.srv.active{border-radius:14px}.srv.active::before{height:20px}
|
||
.srv-a{background:#1e1e1e;color:#c88b5a;border:1px solid #2a2a2a}
|
||
.srv-b{background:#1e1a1e;color:#b07cc6;border:1px solid #2a242a}
|
||
.srv-add{background:transparent;color:var(--text3);font-size:18px;border:1px dashed var(--border2);margin-top:auto;margin-bottom:18px}
|
||
.srv-add:hover{background:var(--bg2);color:var(--green);border-color:rgba(74,222,128,.3)}
|
||
/* tooltip */
|
||
[data-tip]{position:relative}
|
||
[data-tip]:hover::after{content:attr(data-tip);position:absolute;left:calc(100% + 12px);top:50%;transform:translateY(-50%);background:var(--bg4);color:var(--text1);font-size:12px;white-space:nowrap;padding:5px 10px;border-radius:6px;border:1px solid var(--border2);pointer-events:none;z-index:200}
|
||
.rail-vnox{font-size:9px;font-weight:700;letter-spacing:.18em;color:var(--text3);font-family:var(--mono);margin-top:auto}
|
||
|
||
/* ═══ CHANNELS ═══ */
|
||
.channels{grid-column:2;grid-row:1;background:var(--bg1);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden}
|
||
.srv-hdr{padding:14px 14px 10px;border-bottom:1px solid var(--border);flex-shrink:0}
|
||
.srv-hdr-name{font-weight:700;font-size:14px;color:var(--text1)}
|
||
.srv-hdr-id{font-size:10px;color:var(--text3);font-family:var(--mono);margin-top:2px}
|
||
.ch-search{padding:8px 10px;flex-shrink:0}
|
||
.ch-search-inner{display:flex;align-items:center;gap:6px;background:var(--bg0);border:1px solid var(--border);border-radius:6px;padding:5px 10px;transition:border-color .15s}
|
||
.ch-search-inner:focus-within{border-color:var(--border2)}
|
||
.ch-search-inner svg{width:12px;height:12px;fill:var(--text3);flex-shrink:0}
|
||
.ch-search-input{background:none;border:none;outline:none;font-family:var(--font);font-size:12px;color:var(--text2);width:100%}
|
||
.ch-search-input::placeholder{color:var(--text3)}
|
||
.ch-scroll{flex:1;overflow-y:auto;padding:4px 8px 8px}
|
||
.ch-sec-hdr{display:flex;align-items:center;gap:5px;padding:8px 6px 3px;font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text3);cursor:pointer;border-radius:4px;transition:color .15s}
|
||
.ch-sec-hdr:hover{color:var(--text2)}
|
||
.ch-sec-hdr svg{width:11px;height:11px;fill:currentColor;flex-shrink:0}
|
||
.ch-item{display:flex;align-items:center;gap:7px;padding:6px 6px;border-radius:5px;cursor:pointer;color:var(--text3);font-size:13px;font-weight:500;transition:background .1s,color .1s;position:relative}
|
||
.ch-item:hover{background:var(--bg2);color:var(--text2)}
|
||
.ch-item.active{background:var(--bg3);color:var(--text1)}
|
||
.ch-item.active::before{content:'';position:absolute;left:-8px;top:4px;bottom:4px;width:2px;background:var(--accent);border-radius:0 2px 2px 0}
|
||
.ch-icon{flex-shrink:0;width:16px;text-align:center;font-size:11px}
|
||
.ch-badge{margin-left:auto;font-size:10px;font-family:var(--mono);padding:1px 5px;border-radius:8px;letter-spacing:.02em}
|
||
.ch-badge.ping{color:var(--green);background:rgba(74,222,128,.08)}
|
||
.ch-badge.unread{color:#fff;background:var(--accent);min-width:18px;text-align:center}
|
||
.ch-badge.count{color:var(--text3);background:var(--bg3)}
|
||
.vu-list{padding:2px 0 4px 20px}
|
||
.vu-row{display:flex;align-items:center;gap:7px;padding:3px 6px;border-radius:5px;cursor:pointer;font-size:12px;color:var(--text3);transition:background .1s}
|
||
.vu-row:hover{background:var(--bg2);color:var(--text2)}
|
||
.vu-av{width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:7px;font-weight:700;flex-shrink:0;position:relative;color:#fff}
|
||
.vu-dot{width:7px;height:7px;border-radius:50%;position:absolute;bottom:-1px;right:-1px;border:1px solid var(--bg1)}
|
||
.vu-speaking{font-size:8px;color:var(--green);margin-left:auto}
|
||
|
||
/* ═══ USERBAR ═══ */
|
||
.userbar{grid-column:2;grid-row:2;background:var(--bg1);border-right:1px solid var(--border);border-top:1px solid var(--border);display:flex;align-items:center;padding:0 8px;gap:8px}
|
||
.ub-av{width:30px;height:30px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;flex-shrink:0;cursor:pointer;position:relative;color:#fff;transition:transform .15s}
|
||
.ub-av:hover{transform:scale(1.08)}
|
||
.ub-status{width:9px;height:9px;border-radius:50%;position:absolute;bottom:-1px;right:-1px;border:2px solid var(--bg1)}
|
||
.ub-info{flex:1;min-width:0}
|
||
.ub-name{font-size:12px;font-weight:600;color:var(--text1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.ub-sub{font-size:10px;color:var(--text3);font-family:var(--mono)}
|
||
.ub-icons{display:flex;gap:2px}
|
||
.ub-btn{width:26px;height:26px;border-radius:5px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text3);transition:background .15s,color .15s}
|
||
.ub-btn:hover{background:var(--bg3);color:var(--text1)}
|
||
.ub-btn.muted{color:var(--red)}
|
||
.ub-btn svg{width:14px;height:14px;fill:currentColor}
|
||
|
||
/* ═══ MAIN ═══ */
|
||
.main{grid-column:3;grid-row:1/3;display:flex;flex-direction:column;background:var(--bg0);overflow:hidden}
|
||
.main-hdr{height:44px;flex-shrink:0;border-bottom:1px solid var(--border);display:flex;align-items:center;padding:0 16px;gap:8px;background:var(--bg0)}
|
||
.mh-icon{font-size:14px;font-weight:700;color:var(--text3)}
|
||
.mh-name{font-weight:600;font-size:14px;color:var(--text1)}
|
||
.mh-sep{width:1px;height:14px;background:var(--border2)}
|
||
.mh-desc{font-size:12px;color:var(--text3);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.mh-actions{display:flex;gap:2px}
|
||
.mh-btn{width:28px;height:28px;border-radius:5px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text3);transition:background .15s,color .15s}
|
||
.mh-btn:hover{background:var(--bg2);color:var(--text1)}
|
||
.mh-btn svg{width:14px;height:14px;fill:currentColor}
|
||
|
||
/* Messages */
|
||
.messages{flex:1;overflow-y:auto;padding:8px 0 4px}
|
||
.day-sep{display:flex;align-items:center;gap:10px;padding:10px 16px;font-size:10px;color:var(--text3);font-family:var(--mono);letter-spacing:.06em}
|
||
.day-sep::before,.day-sep::after{content:'';flex:1;height:1px;background:var(--border)}
|
||
.sys-msg{display:flex;align-items:center;gap:10px;padding:6px 16px;font-size:11px;color:var(--text3);font-family:var(--mono)}
|
||
.sys-msg::before,.sys-msg::after{content:'';flex:1;height:1px;background:var(--border)}
|
||
|
||
/* Message groups — bubble style */
|
||
.msg-group{padding:4px 16px;position:relative;transition:background .08s}
|
||
.msg-group:hover{background:rgba(255,255,255,.015)}
|
||
.msg-group.ns{margin-top:10px}
|
||
.msg-group:hover .msg-actions{opacity:1;pointer-events:all}
|
||
.msg-layout{display:flex;gap:12px;align-items:flex-start}
|
||
.msg-av{width:34px;height:34px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;cursor:pointer;color:#fff;transition:transform .1s;margin-top:1px}
|
||
.msg-av:hover{transform:scale(1.06)}
|
||
.msg-cont{flex:1;min-width:0;background:var(--bg2);border:1px solid var(--border);border-radius:4px 12px 12px 12px;padding:8px 12px}
|
||
.msg-hdr{display:flex;align-items:baseline;gap:8px;margin-bottom:4px}
|
||
.msg-author{font-size:13px;font-weight:600;cursor:pointer}
|
||
.msg-author:hover{text-decoration:underline}
|
||
.msg-time{font-size:10px;color:var(--text3);font-family:var(--mono)}
|
||
.msg-text{font-size:13px;color:var(--text2);line-height:1.6;word-break:break-word}
|
||
.msg-text a{color:var(--teal);text-decoration:none}
|
||
.msg-text a:hover{text-decoration:underline}
|
||
/* continuation messages in same group */
|
||
.msg-cont-inline{margin-left:46px;background:var(--bg2);border:1px solid var(--border);border-radius:4px 12px 12px 12px;padding:7px 12px;margin-top:3px}
|
||
/* floating actions */
|
||
.msg-actions{position:absolute;right:16px;top:-14px;background:var(--bg3);border:1px solid var(--border2);border-radius:7px;display:flex;gap:1px;padding:3px;opacity:0;pointer-events:none;transition:opacity .1s;z-index:10}
|
||
.ma-btn{width:26px;height:26px;border-radius:4px;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:12px;color:var(--text3);transition:background .1s,color .1s}
|
||
.ma-btn:hover{background:var(--bg4);color:var(--text1)}
|
||
/* sys msg inside group */
|
||
.msg-group.sys-g .msg-cont{background:transparent;border:none;padding:0}
|
||
.msg-group.sys-g .msg-av{background:var(--bg3) !important;color:var(--text3);font-size:14px}
|
||
|
||
/* Input */
|
||
.input-area{padding:0 12px 12px;flex-shrink:0}
|
||
.input-box{background:var(--bg2);border:1px solid var(--border2);border-radius:9px;overflow:hidden;transition:border-color .2s}
|
||
.input-box:focus-within{border-color:rgba(255,107,53,.3)}
|
||
.input-top{display:flex;align-items:center;padding:0 14px;gap:10px}
|
||
.input-ch{font-family:var(--mono);font-size:11px;color:var(--text3);flex-shrink:0;padding:11px 0;border-right:1px solid var(--border);padding-right:10px}
|
||
.input-field{flex:1;background:none;border:none;outline:none;font-family:var(--font);font-size:13px;color:var(--text1);padding:11px 0}
|
||
.input-field::placeholder{color:var(--text3)}
|
||
.input-actions{display:flex;gap:3px;padding:0 10px 8px;border-top:1px solid var(--border);margin-top:0}
|
||
.ia-btn{display:flex;align-items:center;gap:4px;padding:4px 8px;border-radius:5px;cursor:pointer;font-size:11px;color:var(--text3);transition:background .1s,color .1s}
|
||
.ia-btn:hover{background:var(--bg3);color:var(--text2)}
|
||
.ia-btn svg{width:12px;height:12px;fill:currentColor;flex-shrink:0}
|
||
.ia-right{margin-left:auto;display:flex;align-items:center;gap:4px}
|
||
.ia-send{background:var(--accent);color:#fff;border-radius:5px;padding:4px 12px;font-weight:600;font-size:11px;cursor:pointer;transition:background .15s}
|
||
.ia-send:hover{background:var(--accent2)}
|
||
.ia-enc{display:flex;align-items:center;gap:4px;font-size:10px;color:var(--text3);font-family:var(--mono);padding:4px 8px}
|
||
.ia-enc svg{width:11px;height:11px;fill:var(--green)}
|
||
|
||
/* ═══ MEMBERS ═══ */
|
||
.members{grid-column:4;grid-row:1/3;background:var(--bg1);border-left:1px solid var(--border);overflow-y:auto;padding:14px 8px;transition:width .2s,opacity .2s}
|
||
.members.hidden{display:none}
|
||
.mb-label{font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text3);padding:0 8px;margin-bottom:5px;font-family:var(--mono)}
|
||
.mb-section{margin-bottom:18px}
|
||
.mb-item{display:flex;align-items:center;gap:9px;padding:5px 8px;border-radius:6px;cursor:pointer;transition:background .1s}
|
||
.mb-item:hover{background:var(--bg2)}
|
||
.mb-av{width:30px;height:30px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;position:relative;color:#fff}
|
||
.mb-status{width:9px;height:9px;border-radius:50%;position:absolute;bottom:-1px;right:-1px;border:2px solid var(--bg1)}
|
||
.mb-name{font-size:13px;font-weight:500;color:var(--text2);transition:color .1s}
|
||
.mb-item:hover .mb-name{color:var(--text1)}
|
||
.mb-tag{font-size:10px;color:var(--text3);margin-top:1px;font-family:var(--mono)}
|
||
.st-on{background:var(--green)}.st-idle{background:var(--yellow)}.st-dnd{background:var(--red)}.st-off{background:var(--text3)}
|
||
|
||
/* Avatar color palette — 8 saturated */
|
||
.av1{background:#c0522a}.av2{background:#7a52c4}.av3{background:#3a9e5f}.av4{background:#c43a7a}.av5{background:#3a7ac4}.av6{background:#9e7a3a}.av7{background:#3a9e9e}.av8{background:#8a3ac4}
|
||
|
||
/* ═══ VOICE OVERLAY ═══ */
|
||
.voice-ov{position:fixed;inset:0;background:rgba(8,8,8,.96);backdrop-filter:blur(20px);display:none;z-index:50;flex-direction:column;align-items:center;justify-content:center;gap:24px}
|
||
.voice-ov.show{display:flex;animation:fadeIn .18s}
|
||
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
|
||
.vo-hdr{text-align:center}
|
||
.vo-title{font-size:20px;font-weight:700;letter-spacing:.02em}
|
||
.vo-meta{display:flex;align-items:center;justify-content:center;gap:14px;margin-top:6px;font-size:11px;font-family:var(--mono);color:var(--text3)}
|
||
.vo-meta-item{display:flex;align-items:center;gap:5px}
|
||
.vo-meta-item .dot{width:6px;height:6px;border-radius:50%;background:var(--green)}
|
||
/* Speaker grid — main speaker large, rest small */
|
||
.vo-grid{display:flex;flex-direction:column;align-items:center;gap:12px;width:100%;max-width:640px;padding:0 24px}
|
||
.vo-main{width:100%;max-width:500px;background:var(--bg2);border:2px solid var(--border2);border-radius:16px;padding:32px 24px;display:flex;flex-direction:column;align-items:center;gap:14px;transition:border-color .2s,box-shadow .2s;position:relative}
|
||
.vo-main.speaking{border-color:rgba(74,222,128,.5);box-shadow:0 0 32px rgba(74,222,128,.1)}
|
||
.vo-main-av{width:88px;height:88px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:700;color:#fff;border:3px solid transparent;transition:border-color .2s}
|
||
.vo-main.speaking .vo-main-av{border-color:var(--green)}
|
||
.vo-main-name{font-size:16px;font-weight:600;color:var(--text1)}
|
||
.vo-main-status{display:flex;align-items:center;gap:6px;font-size:11px;font-family:var(--mono);color:var(--text3)}
|
||
.vo-badge{padding:2px 8px;border-radius:4px;border:1px solid var(--border2);font-size:10px;font-family:var(--mono)}
|
||
.vo-small-row{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
|
||
.vo-small{background:var(--bg2);border:1px solid var(--border2);border-radius:12px;padding:14px 20px;display:flex;flex-direction:column;align-items:center;gap:8px;cursor:pointer;transition:border-color .2s,background .15s;min-width:110px}
|
||
.vo-small:hover{background:var(--bg3)}
|
||
.vo-small.speaking{border-color:rgba(74,222,128,.4)}
|
||
.vo-small-av{width:48px;height:48px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700;color:#fff;border:2px solid transparent;transition:border-color .2s}
|
||
.vo-small.speaking .vo-small-av{border-color:var(--green)}
|
||
.vo-small-name{font-size:12px;font-weight:600;color:var(--text2)}
|
||
.vo-small-icons{display:flex;gap:4px}
|
||
.vo-ico{width:18px;height:18px;border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:9px;background:var(--bg3);color:var(--text3)}
|
||
.vo-ico.muted{color:var(--red);background:rgba(248,113,113,.1)}
|
||
/* Controls */
|
||
.vo-controls{display:flex;gap:8px}
|
||
.vo-btn{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;background:var(--bg2);border:1px solid var(--border2);transition:background .15s,border-color .15s,transform .1s}
|
||
.vo-btn:hover{background:var(--bg3);transform:scale(1.06)}
|
||
.vo-btn svg{width:16px;height:16px;fill:var(--text2)}
|
||
.vo-btn.tog{background:rgba(248,113,113,.12);border-color:rgba(248,113,113,.3)}
|
||
.vo-btn.tog svg{fill:var(--red)}
|
||
.vo-btn.disc{background:var(--accent);border-color:var(--accent2)}
|
||
.vo-btn.disc svg{fill:#fff}
|
||
.vo-btn.disc:hover{background:var(--accent2)}
|
||
|
||
/* ═══ SETTINGS OVERLAY ═══ */
|
||
.settings-ov{position:fixed;inset:0;background:rgba(8,8,8,.7);backdrop-filter:blur(16px);display:none;z-index:60;align-items:center;justify-content:center}
|
||
.settings-ov.show{display:flex;animation:fadeIn .18s}
|
||
.s-modal{width:700px;max-height:88vh;background:var(--bg1);border:1px solid var(--border2);border-radius:14px;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 32px 80px rgba(0,0,0,.6)}
|
||
.s-hdr{height:52px;background:var(--bg0);border-bottom:1px solid var(--border);display:flex;align-items:center;padding:0 20px;gap:12px;flex-shrink:0}
|
||
.s-hdr-logo{font-size:14px;font-weight:700;letter-spacing:.1em;color:var(--accent);font-family:var(--mono)}
|
||
.s-hdr-node{font-size:11px;color:var(--text2);display:flex;align-items:center;gap:6px;font-family:var(--mono)}
|
||
.s-hdr-dot{width:6px;height:6px;border-radius:50%;background:var(--green)}
|
||
.s-badge{font-size:10px;padding:2px 7px;border-radius:4px;border:1px solid rgba(255,107,53,.25);background:rgba(255,107,53,.08);color:var(--accent);font-family:var(--mono)}
|
||
.s-close{margin-left:auto;width:28px;height:28px;border-radius:6px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text3);font-size:14px;transition:background .15s,color .15s}
|
||
.s-close:hover{background:var(--bg3);color:var(--text1)}
|
||
/* Tab nav */
|
||
.s-tabs{display:flex;gap:2px;padding:12px 20px;border-bottom:1px solid var(--border);flex-shrink:0;background:var(--bg1)}
|
||
.s-tab{display:flex;align-items:center;gap:7px;padding:7px 14px;border-radius:7px;font-size:13px;color:var(--text3);cursor:pointer;transition:background .1s,color .1s;font-weight:500}
|
||
.s-tab:hover{background:var(--bg2);color:var(--text2)}
|
||
.s-tab.active{background:var(--bg3);color:var(--text1)}
|
||
.s-tab svg{width:14px;height:14px;fill:currentColor;flex-shrink:0}
|
||
.s-content{flex:1;overflow-y:auto;padding:24px 28px}
|
||
.pg{display:none}.pg.active{display:block}
|
||
.sc-title{font-size:17px;font-weight:700;color:var(--text1);margin-bottom:3px}
|
||
.sc-sub{font-size:11px;color:var(--text3);margin-bottom:20px;font-family:var(--mono)}
|
||
.sc-group{margin-bottom:22px}
|
||
.sc-gl{font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text3);border-bottom:1px solid var(--border);padding-bottom:5px;margin-bottom:10px}
|
||
.sc-row{display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(255,255,255,.025);gap:12px}
|
||
.sc-rl{font-size:13px;color:var(--text2)}
|
||
.sc-rs{font-size:11px;color:var(--text3);margin-top:2px;font-family:var(--mono)}
|
||
.s-select{background:var(--bg2);border:1px solid var(--border2);border-radius:6px;color:var(--text2);font-family:var(--font);font-size:12px;padding:6px 28px 6px 10px;outline:none;cursor:pointer;min-width:150px;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%234a5568' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;transition:border-color .15s}
|
||
.s-select:focus{border-color:rgba(255,107,53,.4)}
|
||
.s-input{background:var(--bg2);border:1px solid var(--border2);border-radius:6px;color:var(--text2);font-family:var(--font);font-size:12px;padding:6px 10px;outline:none;width:100%;max-width:260px;transition:border-color .15s,color .15s}
|
||
.s-input:focus{border-color:rgba(255,107,53,.4);color:var(--text1)}
|
||
/* Sliders */
|
||
.s-slider{-webkit-appearance:none;width:160px;height:3px;border-radius:2px;background:var(--bg4);outline:none;cursor:pointer}
|
||
.s-slider::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--accent);cursor:pointer;box-shadow:0 0 6px rgba(255,107,53,.4)}
|
||
/* Toggle */
|
||
.toggle{position:relative;width:34px;height:18px;cursor:pointer;flex-shrink:0}
|
||
.toggle input{display:none}
|
||
.t-track{width:34px;height:18px;border-radius:9px;background:var(--bg4);border:1px solid var(--border2);transition:background .15s,border-color .15s}
|
||
.toggle input:checked+.t-track{background:rgba(255,107,53,.2);border-color:rgba(255,107,53,.35)}
|
||
.t-thumb{position:absolute;top:3px;left:3px;width:12px;height:12px;border-radius:50%;background:var(--text3);transition:left .15s cubic-bezier(.2,0,0,1.4),background .15s}
|
||
.toggle input:checked~.t-thumb{left:19px;background:var(--accent)}
|
||
/* Level bars */
|
||
.lvl-wrap{display:flex;align-items:center;gap:10px}
|
||
.lvl-bar{width:120px;height:3px;background:var(--bg4);border-radius:2px;overflow:hidden}
|
||
.lvl-fill{height:100%;border-radius:2px;transition:width .1s}
|
||
.lvl-fill.in{background:var(--accent)}.lvl-fill.out{background:var(--green)}
|
||
.lvl-val{font-size:11px;color:var(--text3);font-family:var(--mono);min-width:36px}
|
||
.key-badge{font-size:11px;color:var(--text3);border:1px solid var(--border2);padding:2px 8px;border-radius:4px;font-family:var(--mono);background:var(--bg2)}
|
||
|
||
/* ═══ CONNECT SCREEN ═══ */
|
||
.connect-scr{position:fixed;inset:0;background:var(--bg0);display:none;z-index:70;align-items:center;justify-content:center}
|
||
.connect-scr.show{display:flex;animation:fadeIn .2s}
|
||
.cn-bg{position:absolute;inset:0;background:radial-gradient(ellipse 50% 40% at 50% 50%,rgba(255,107,53,.05) 0%,transparent 70%);pointer-events:none}
|
||
.cn-box{width:340px;position:relative;z-index:1}
|
||
.cn-logo-wrap{display:flex;align-items:center;gap:10px;margin-bottom:8px}
|
||
.cn-logo-icon{width:36px;height:36px;border-radius:10px;background:var(--accent);display:flex;align-items:center;justify-content:center}
|
||
.cn-logo-icon svg{width:18px;height:18px;fill:#fff}
|
||
.cn-logo-text{font-size:22px;font-weight:700;letter-spacing:.12em;color:var(--text1);font-family:var(--mono)}
|
||
.cn-tagline{font-size:11px;color:var(--text3);margin-bottom:28px;font-family:var(--mono)}
|
||
.cn-field{margin-bottom:14px}
|
||
.cn-label{font-size:10px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.1em;margin-bottom:6px;display:block;font-family:var(--mono)}
|
||
.cn-input{width:100%;background:var(--bg1);border:1px solid var(--border2);border-radius:7px;color:var(--text1);font-family:var(--mono);font-size:13px;padding:10px 14px;outline:none;transition:border-color .15s}
|
||
.cn-input:focus{border-color:rgba(255,107,53,.4)}
|
||
.cn-row{display:flex;gap:8px;margin-top:20px}
|
||
.cn-btn{flex:1;background:var(--accent);border:none;border-radius:7px;color:#fff;font-family:var(--font);font-size:13px;font-weight:600;padding:10px;cursor:pointer;transition:background .15s,transform .1s}
|
||
.cn-btn:hover{background:var(--accent2);transform:translateY(-1px)}
|
||
.cn-btn-ghost{background:var(--bg2);border:1px solid var(--border2);border-radius:7px;color:var(--text2);font-family:var(--font);font-size:13px;padding:10px 16px;cursor:pointer;transition:background .15s}
|
||
.cn-btn-ghost:hover{background:var(--bg3)}
|
||
.cn-recent{margin-top:20px;border-top:1px solid var(--border);padding-top:14px}
|
||
.cn-recent-label{font-size:10px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.1em;margin-bottom:8px;font-family:var(--mono)}
|
||
.cn-srv{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:6px;cursor:pointer;transition:background .1s;border:1px solid transparent}
|
||
.cn-srv:hover{background:var(--bg2);border-color:var(--border)}
|
||
.cn-srv-av{width:28px;height:28px;border-radius:7px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#fff}
|
||
.cn-srv-name{font-size:13px;font-weight:600;color:var(--text2)}
|
||
.cn-srv-addr{font-size:10px;color:var(--text3);font-family:var(--mono)}
|
||
.cn-srv-ping{font-size:10px;font-family:var(--mono)}
|
||
|
||
/* ═══ PROFILE CARD ═══ */
|
||
.profile-ov{position:fixed;inset:0;background:rgba(8,8,8,.7);backdrop-filter:blur(12px);display:none;z-index:55;align-items:center;justify-content:center}
|
||
.profile-ov.show{display:flex;animation:fadeIn .18s}
|
||
.profile-card{width:300px;background:var(--bg1);border:1px solid var(--border2);border-radius:14px;overflow:hidden;box-shadow:0 24px 60px rgba(0,0,0,.5)}
|
||
.pc-banner{height:72px;background:linear-gradient(135deg,#1a1a1a,#2a2a2a);position:relative}
|
||
.pc-banner::after{content:'';position:absolute;inset:0;background:rgba(255,107,53,.06)}
|
||
.pc-av-wrap{position:absolute;bottom:-28px;left:16px}
|
||
.pc-av{width:56px;height:56px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:#fff;border:3px solid var(--bg1)}
|
||
.pc-body{padding:36px 16px 16px}
|
||
.pc-name{font-size:15px;font-weight:700;color:var(--text1)}
|
||
.pc-tag{font-size:11px;color:var(--text3);font-family:var(--mono);margin-top:2px}
|
||
.pc-role{display:inline-flex;align-items:center;gap:5px;margin-top:8px;padding:3px 8px;border-radius:4px;font-size:11px;font-weight:600;border:1px solid}
|
||
.pc-info{margin-top:12px;border-top:1px solid var(--border);padding-top:10px}
|
||
.pc-info-row{display:flex;justify-content:space-between;align-items:center;padding:4px 0;font-size:12px}
|
||
.pc-info-l{color:var(--text3);font-family:var(--mono)}
|
||
.pc-info-r{color:var(--text2)}
|
||
.pc-actions{display:flex;gap:6px;margin-top:14px;padding-top:12px;border-top:1px solid var(--border)}
|
||
.pc-btn{flex:1;padding:7px;border-radius:7px;font-size:12px;font-weight:600;cursor:pointer;text-align:center;transition:background .15s;border:1px solid var(--border2);color:var(--text2);background:var(--bg2)}
|
||
.pc-btn:hover{background:var(--bg3);color:var(--text1)}
|
||
.pc-btn.primary{background:var(--accent);border-color:var(--accent2);color:#fff}
|
||
.pc-btn.primary:hover{background:var(--accent2)}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- ═══ CONNECT SCREEN ═══ -->
|
||
<div class="connect-scr show" id="connectScr">
|
||
<div class="cn-bg"></div>
|
||
<div class="cn-box">
|
||
<div class="cn-logo-wrap">
|
||
<div class="cn-logo-icon"><svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z"/></svg></div>
|
||
<div class="cn-logo-text">VNOX</div>
|
||
</div>
|
||
<div class="cn-tagline">// secure voice & text · quic/v1</div>
|
||
<div class="cn-field"><label class="cn-label">Address</label><input class="cn-input" type="text" value="nightcore.lnex" placeholder="server.address"></div>
|
||
<div class="cn-field"><label class="cn-label">Username</label><input class="cn-input" type="text" value="nekit" placeholder="username"></div>
|
||
<div class="cn-field"><label class="cn-label">Password</label><input class="cn-input" type="password" placeholder="passphrase"></div>
|
||
<div class="cn-row">
|
||
<button class="cn-btn" onclick="document.getElementById('connectScr').classList.remove('show')">Connect</button>
|
||
<button class="cn-btn-ghost">Keypair</button>
|
||
</div>
|
||
<div class="cn-recent">
|
||
<div class="cn-recent-label">Recent</div>
|
||
<div class="cn-srv" onclick="document.getElementById('connectScr').classList.remove('show')">
|
||
<div class="cn-srv-av av1">NC</div>
|
||
<div style="flex:1"><div class="cn-srv-name">nightcore community</div><div class="cn-srv-addr">nightcore.lnex</div></div>
|
||
<div class="cn-srv-ping" style="color:var(--green)">24ms</div>
|
||
</div>
|
||
<div class="cn-srv">
|
||
<div class="cn-srv-av av2">VD</div>
|
||
<div style="flex:1"><div class="cn-srv-name">void.lnex</div><div class="cn-srv-addr">void.lnex</div></div>
|
||
<div class="cn-srv-ping" style="color:var(--yellow)">81ms</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ SETTINGS (modal overlay) ═══ -->
|
||
<div class="settings-ov" id="settingsOv">
|
||
<div class="s-modal">
|
||
<div class="s-hdr">
|
||
<div class="s-hdr-logo">VNOX</div>
|
||
<div style="width:1px;height:16px;background:var(--border2)"></div>
|
||
<div class="s-hdr-node"><div class="s-hdr-dot"></div>nightcore.lnex</div>
|
||
<div class="s-badge">quic/v1</div>
|
||
<div class="s-close" onclick="document.getElementById('settingsOv').classList.remove('show')">✕</div>
|
||
</div>
|
||
<div class="s-tabs">
|
||
<div class="s-tab active" onclick="switchTab('voice',this)">
|
||
<svg viewBox="0 0 16 16"><path d="M5 3a3 3 0 0 1 6 0v5a3 3 0 0 1-6 0V3z"/><path d="M3.5 6.5A.5.5 0 0 1 4 7v1a4 4 0 0 0 8 0V7a.5.5 0 0 1 1 0v1a5 5 0 0 1-4.5 4.975V15h3a.5.5 0 0 1 0 1h-7a.5.5 0 0 1 0-1h3v-2.025A5 5 0 0 1 3 8V7a.5.5 0 0 1 .5-.5z"/></svg>Audio
|
||
</div>
|
||
<div class="s-tab" onclick="switchTab('identity',this)">
|
||
<svg viewBox="0 0 16 16"><path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-5 6s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3z"/></svg>Identity
|
||
</div>
|
||
<div class="s-tab" onclick="switchTab('appearance',this)">
|
||
<svg viewBox="0 0 16 16"><path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm4 3a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zM5.5 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm.5 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/><path d="M16 8c0 3.15-1.866 2.585-3.567 2.07C11.42 9.763 10.465 9.5 10 9.5c-.943 0-2 .115-2 2.5a2.5 2.5 0 0 1-2.5 2.5C3.016 14.5 0 12.88 0 8a8 8 0 1 1 16 0z"/></svg>Appearance
|
||
</div>
|
||
<div class="s-tab" onclick="switchTab('network',this)">
|
||
<svg viewBox="0 0 16 16"><path d="M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1zM0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8z"/></svg>Network
|
||
</div>
|
||
<div class="s-tab" onclick="switchTab('advanced',this)">
|
||
<svg viewBox="0 0 16 16"><path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/></svg>Advanced
|
||
</div>
|
||
</div>
|
||
<div class="s-content">
|
||
<div class="pg active" id="pg-voice">
|
||
<div class="sc-title">Audio</div><div class="sc-sub">// input · output · encoding</div>
|
||
<div class="sc-group"><div class="sc-gl">Input</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Microphone</div><div class="sc-rs">Capture device</div></div><select class="s-select"><option>Shure MV7</option><option>HyperX QuadCast</option><option>Built-in Mic</option></select></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Input gain</div></div><div class="lvl-wrap"><input type="range" class="s-slider" min="0" max="100" value="72"><span class="lvl-val">72%</span></div></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Input level</div></div><div class="lvl-wrap"><div class="lvl-bar"><div class="lvl-fill in" id="lvl1" style="width:72%"></div></div><span class="lvl-val" id="lvlv1">-8 dB</span></div></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Noise gate</div><div class="sc-rs">Cut below threshold</div></div><label class="toggle"><input type="checkbox" checked><div class="t-track"></div><div class="t-thumb"></div></label></div>
|
||
<div class="sc-row"><div><div class="sc-rl">RNNoise</div><div class="sc-rs">ML noise suppression</div></div><label class="toggle"><input type="checkbox" checked><div class="t-track"></div><div class="t-thumb"></div></label></div>
|
||
</div>
|
||
<div class="sc-group"><div class="sc-gl">Encoding</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Codec</div></div><select class="s-select"><option>Opus 48kHz</option><option>Opus 24kHz</option></select></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Bitrate</div></div><select class="s-select"><option>96 kbps</option><option>64 kbps</option><option>128 kbps</option></select></div>
|
||
<div class="sc-row"><div><div class="sc-rl">FEC</div><div class="sc-rs">Forward error correction</div></div><label class="toggle"><input type="checkbox" checked><div class="t-track"></div><div class="t-thumb"></div></label></div>
|
||
<div class="sc-row"><div><div class="sc-rl">DTX</div><div class="sc-rs">Discontinuous tx</div></div><label class="toggle"><input type="checkbox"><div class="t-track"></div><div class="t-thumb"></div></label></div>
|
||
</div>
|
||
<div class="sc-group"><div class="sc-gl">Output</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Device</div></div><select class="s-select"><option>SteelSeries Arctis</option><option>Built-in Output</option></select></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Output volume</div></div><div class="lvl-wrap"><input type="range" class="s-slider" min="0" max="100" value="80"><span class="lvl-val">80%</span></div></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Output level</div></div><div class="lvl-wrap"><div class="lvl-bar"><div class="lvl-fill out" id="lvl2" style="width:55%"></div></div><span class="lvl-val">-14 dB</span></div></div>
|
||
</div>
|
||
</div>
|
||
<div class="pg" id="pg-identity">
|
||
<div class="sc-title">Identity</div><div class="sc-sub">// display · keypair</div>
|
||
<div class="sc-group"><div class="sc-gl">Display</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Username</div></div><input class="s-input" value="nekit"></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Status</div></div><select class="s-select"><option>Online</option><option>Away</option><option>Do not disturb</option></select></div>
|
||
</div>
|
||
<div class="sc-group"><div class="sc-gl">Keypair</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Public key</div><div class="sc-rs" style="font-family:var(--mono)">a1b2c3d4…9f0e</div></div></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Fingerprint</div><div class="sc-rs" style="font-family:var(--mono)">SHA256:xK7m…</div></div></div>
|
||
</div>
|
||
</div>
|
||
<div class="pg" id="pg-appearance">
|
||
<div class="sc-title">Appearance</div><div class="sc-sub">// theme · density</div>
|
||
<div class="sc-group"><div class="sc-gl">Theme</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Base theme</div></div><select class="s-select"><option>Dark Graphite</option></select></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Accent color</div></div><input type="color" value="#ff6b35" style="width:36px;height:28px;border:none;border-radius:5px;cursor:pointer;background:none"></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Compact messages</div></div><label class="toggle"><input type="checkbox"><div class="t-track"></div><div class="t-thumb"></div></label></div>
|
||
</div>
|
||
</div>
|
||
<div class="pg" id="pg-network">
|
||
<div class="sc-title">Network</div><div class="sc-sub">// transport · diagnostics</div>
|
||
<div class="sc-group"><div class="sc-gl">Transport</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Protocol</div></div><select class="s-select"><option>QUIC (LNEx v1)</option><option>TCP fallback</option></select></div>
|
||
<div class="sc-row"><div><div class="sc-rl">RTT</div></div><span style="font-family:var(--mono);font-size:12px;color:var(--green)">24ms</span></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Packet loss</div></div><span style="font-family:var(--mono);font-size:12px;color:var(--text3)">0.0%</span></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Jitter</div></div><span style="font-family:var(--mono);font-size:12px;color:var(--text3)">1.2ms</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="pg" id="pg-advanced">
|
||
<div class="sc-title">Advanced</div><div class="sc-sub">// debug · build</div>
|
||
<div class="sc-group"><div class="sc-gl">Debug</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Show packet stats</div></div><label class="toggle"><input type="checkbox"><div class="t-track"></div><div class="t-thumb"></div></label></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Verbose logging</div></div><label class="toggle"><input type="checkbox"><div class="t-track"></div><div class="t-thumb"></div></label></div>
|
||
</div>
|
||
<div class="sc-group"><div class="sc-gl">Build</div>
|
||
<div class="sc-row"><div><div class="sc-rl">Version</div></div><span class="key-badge">0.4.1-dev</span></div>
|
||
<div class="sc-row"><div><div class="sc-rl">Runtime</div></div><span style="font-size:11px;font-family:var(--mono);color:var(--text3)">Tokio 1.x · CPAL</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ VOICE OVERLAY ═══ -->
|
||
<div class="voice-ov" id="voiceOv">
|
||
<div class="vo-hdr">
|
||
<div class="vo-title">Lounge</div>
|
||
<div class="vo-meta">
|
||
<div class="vo-meta-item"><div class="dot"></div><span style="color:var(--green)">Excellent</span></div>
|
||
<span style="color:var(--border2)">·</span>
|
||
<span style="color:var(--green)">24ms</span><span style="color:var(--text3)">rtt</span>
|
||
<span style="color:var(--border2)">·</span>
|
||
<span>Opus 48kHz</span>
|
||
<span style="color:var(--border2)">·</span>
|
||
<span style="color:var(--text3)">0.0% loss</span>
|
||
</div>
|
||
</div>
|
||
<div class="vo-grid">
|
||
<!-- Main speaker (large) -->
|
||
<div class="vo-main speaking" id="voMain">
|
||
<div class="vo-main-av av1" id="voMainAv">NK</div>
|
||
<div class="vo-main-name" id="voMainName">nekit</div>
|
||
<div class="vo-main-status">
|
||
<div class="vo-badge" style="color:var(--green);border-color:rgba(74,222,128,.2);background:rgba(74,222,128,.05)">speaking</div>
|
||
<div class="vo-badge" style="color:var(--text3)">admin</div>
|
||
<div class="vo-badge" style="color:var(--accent);border-color:rgba(255,107,53,.2)">🔒 E2E</div>
|
||
</div>
|
||
</div>
|
||
<!-- Secondary speakers (small) -->
|
||
<div class="vo-small-row">
|
||
<div class="vo-small" onclick="focusUser('sylvans','av2','SY')">
|
||
<div class="vo-small-av av2">SY</div>
|
||
<div class="vo-small-name">sylvans</div>
|
||
<div class="vo-small-icons"><div class="vo-ico muted">🎤</div><div class="vo-ico">🎧</div></div>
|
||
</div>
|
||
<div class="vo-small" onclick="focusUser('morfey','av3','MF')">
|
||
<div class="vo-small-av av3">MF</div>
|
||
<div class="vo-small-name">morfey</div>
|
||
<div class="vo-small-icons"><div class="vo-ico">🎤</div><div class="vo-ico">🎧</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="vo-controls">
|
||
<div class="vo-btn tog" id="voMicBtn" title="Muted" onclick="this.classList.toggle('tog')">
|
||
<svg viewBox="0 0 16 16"><path d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325L6.188 3.61a.5.5 0 0 1 .53-.06z"/><path d="M10.707 11.182A4.486 4.486 0 0 0 12.025 8a4.486 4.486 0 0 0-1.318-3.182L9.99 5.525A3.489 3.489 0 0 1 11.025 8 3.49 3.49 0 0 1 9.99 10.475l.717.707z"/></svg>
|
||
</div>
|
||
<div class="vo-btn" title="Headphones" onclick="this.classList.toggle('tog')">
|
||
<svg viewBox="0 0 16 16"><path d="M8 3a5 5 0 0 0-5 5v1h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V8a6 6 0 1 1 12 0v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1V8a5 5 0 0 0-5-5z"/></svg>
|
||
</div>
|
||
<div class="vo-btn" title="Screen share">
|
||
<svg viewBox="0 0 16 16"><path d="M0 4s0-2 2-2h12s2 0 2 2v6s0 2-2 2h-4c0 .667.083 1.167.25 1.5H11a.5.5 0 0 1 0 1H5a.5.5 0 0 1 0-1h.75c.167-.333.25-.833.25-1.5H2s-2 0-2-2V4zm1.398-.855a.758.758 0 0 0-.254.302A1.46 1.46 0 0 0 1 4.01V10c0 .325.078.502.145.602.07.105.17.188.302.254a1.464 1.464 0 0 0 .538.143L2.01 11H14c.325 0 .502-.078.602-.145a.758.758 0 0 0 .254-.302 1.464 1.464 0 0 0 .143-.538L15 9.99V4c0-.325-.078-.502-.145-.602a.757.757 0 0 0-.302-.254A1.46 1.46 0 0 0 13.99 3H2c-.325 0-.502.078-.602.145z"/></svg>
|
||
</div>
|
||
<div class="vo-btn" title="Camera" onclick="this.classList.toggle('tog')">
|
||
<svg viewBox="0 0 16 16"><path d="M0 5a2 2 0 0 1 2-2h7.5a2 2 0 0 1 1.983 1.738l1.482-1.482A.5.5 0 0 1 14 3.5v9a.5.5 0 0 1-.85.354l-1.481-1.481A2 2 0 0 1 9.5 13H2a2 2 0 0 1-2-2V5z"/></svg>
|
||
</div>
|
||
<div class="vo-btn disc" title="Disconnect" onclick="document.getElementById('voiceOv').classList.remove('show')">
|
||
<svg viewBox="0 0 16 16" style="fill:#fff"><path d="M1.166 4.25c.08.03.15.08.2.14.8.5.15 1.07.15 1.14l-.4 1.22a1.1 1.1 0 0 0 .17 1.01l.06.08c.3.4.77.63 1.26.63h.87a1.1 1.1 0 0 0 .87-.43l.46-.62a.5.5 0 0 1 .4-.2h2a.5.5 0 0 1 .4.2l.46.62c.2.27.52.43.87.43h.87c.49 0 .96-.23 1.26-.63l.06-.08a1.1 1.1 0 0 0 .17-1.01l-.4-1.22c0-.07.07-.64.15-1.14.05-.06.12-.11.2-.14.34-.12.54-.47.46-.82-.27-1.2-1.6-2-3.3-2.12A15.3 15.3 0 0 0 8 2c-.83 0-1.63.05-2.33.14C4.04 2.27 2.7 3.07 2.43 4.27c-.08.35.12.7.46.82l.27.14z"/></svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ PROFILE CARD ═══ -->
|
||
<div class="profile-ov" id="profileOv">
|
||
<div class="profile-card">
|
||
<div class="pc-banner"><div class="pc-av-wrap"><div class="pc-av av1" id="pcAv">NK</div></div></div>
|
||
<div class="pc-body">
|
||
<div class="pc-name" id="pcName">nekit</div>
|
||
<div class="pc-tag" id="pcTag">nekit#0001 · nightcore.lnex</div>
|
||
<div class="pc-role" id="pcRole" style="color:#fb923c;border-color:rgba(251,146,60,.2);background:rgba(251,146,60,.05)">Admin</div>
|
||
<div class="pc-info">
|
||
<div class="pc-info-row"><span class="pc-info-l">status</span><span class="pc-info-r" style="color:var(--green)">● Online</span></div>
|
||
<div class="pc-info-row"><span class="pc-info-l">rtt</span><span class="pc-info-r" style="font-family:var(--mono)">24ms</span></div>
|
||
<div class="pc-info-row"><span class="pc-info-l">joined</span><span class="pc-info-r">Mar 2025</span></div>
|
||
<div class="pc-info-row"><span class="pc-info-l">encryption</span><span class="pc-info-r" style="color:var(--green)">🔒 E2E</span></div>
|
||
</div>
|
||
<div class="pc-actions">
|
||
<div class="pc-btn primary">Message</div>
|
||
<div class="pc-btn">Voice Invite</div>
|
||
<div class="pc-btn">Mute</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="position:absolute;inset:0;z-index:-1" onclick="document.getElementById('profileOv').classList.remove('show')"></div>
|
||
</div>
|
||
|
||
<!-- ═══ MAIN APP ═══ -->
|
||
<div class="app">
|
||
|
||
<!-- RAIL -->
|
||
<div class="rail">
|
||
<div class="rail-logo" data-tip="VNOX" onclick="document.getElementById('connectScr').classList.add('show')">
|
||
<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z"/></svg>
|
||
</div>
|
||
<div class="rail-sep"></div>
|
||
<div class="srv srv-a active" data-tip="nightcore.lnex">NC</div>
|
||
<div class="srv srv-b" data-tip="void.lnex">VD</div>
|
||
<div class="rail-sep"></div>
|
||
<div class="srv srv-add" data-tip="Add server">+</div>
|
||
<div class="rail-vnox">VNOX</div>
|
||
</div>
|
||
|
||
<!-- CHANNELS -->
|
||
<div class="channels">
|
||
<div class="srv-hdr">
|
||
<div class="srv-hdr-name">nightcore community</div>
|
||
<div class="srv-hdr-id">lnex://nc.a1b2c3d4</div>
|
||
</div>
|
||
<div class="ch-search">
|
||
<div class="ch-search-inner">
|
||
<svg viewBox="0 0 16 16"><path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/></svg>
|
||
<input class="ch-search-input" placeholder="Search channels…">
|
||
</div>
|
||
</div>
|
||
<div class="ch-scroll">
|
||
<div class="ch-sec-hdr">
|
||
<svg viewBox="0 0 16 16"><path d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v13.5a.5.5 0 0 1-.777.416L8 13.101l-5.223 2.815A.5.5 0 0 1 2 15.5V2zm2-1a1 1 0 0 0-1 1v12.566l4.723-2.482a.5.5 0 0 1 .554 0L13 14.566V2a1 1 0 0 0-1-1H4z"/></svg>
|
||
TEXT
|
||
</div>
|
||
<div class="ch-item active"><span class="ch-icon">#</span><span>general</span><span class="ch-badge ping">24ms</span></div>
|
||
<div class="ch-item"><span class="ch-icon">#</span><span>announcements</span><span class="ch-badge unread">3</span></div>
|
||
<div class="ch-item"><span class="ch-icon">#</span><span>tech-support</span><span class="ch-badge unread">1</span></div>
|
||
<div class="ch-item"><span class="ch-icon">#</span><span>off-topic</span></div>
|
||
<div class="ch-item"><span class="ch-icon">#</span><span>music-sharing</span></div>
|
||
<div class="ch-sec-hdr" style="margin-top:6px">
|
||
<svg viewBox="0 0 16 16"><path d="M5 3a3 3 0 0 1 6 0v5a3 3 0 0 1-6 0V3z"/><path d="M3.5 6.5A.5.5 0 0 1 4 7v1a4 4 0 0 0 8 0V7a.5.5 0 0 1 1 0v1a5 5 0 0 1-4.5 4.975V15h3a.5.5 0 0 1 0 1h-7a.5.5 0 0 1 0-1h3v-2.025A5 5 0 0 1 3 8V7a.5.5 0 0 1 .5-.5z"/></svg>
|
||
VOICE
|
||
</div>
|
||
<div class="ch-item"><span class="ch-icon" style="font-size:9px;color:var(--text3)">▷</span><span>Lobby</span></div>
|
||
<div class="ch-item" style="color:var(--text2)" onclick="document.getElementById('voiceOv').classList.add('show')">
|
||
<span class="ch-icon" style="font-size:9px;color:var(--green)">▶</span><span>Lounge</span><span class="ch-badge count">3</span>
|
||
</div>
|
||
<div class="vu-list">
|
||
<div class="vu-row"><div class="vu-av av1">NK<div class="vu-dot st-on"></div></div><span>nekit</span><span class="vu-speaking">●</span></div>
|
||
<div class="vu-row"><div class="vu-av av2">SY<div class="vu-dot st-on"></div></div><span>sylvans</span></div>
|
||
<div class="vu-row"><div class="vu-av av3">MF<div class="vu-dot st-on"></div></div><span>morfey</span></div>
|
||
</div>
|
||
<div class="ch-item"><span class="ch-icon" style="font-size:9px;color:var(--text3)">▷</span><span>Gaming</span></div>
|
||
<div class="ch-item"><span class="ch-icon" style="font-size:9px;color:var(--text3)">▷</span><span>Music</span></div>
|
||
<div class="ch-item"><span class="ch-icon" style="font-size:9px;color:var(--text3)">▷</span><span>AFK</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- USERBAR -->
|
||
<div class="userbar">
|
||
<div class="ub-av av1" onclick="showProfile('nekit','av1','NK','Admin','admin')">NK<div class="ub-status st-on"></div></div>
|
||
<div class="ub-info">
|
||
<div class="ub-name">nekit</div>
|
||
<div class="ub-sub"><span style="color:var(--green)">24ms</span> · 0.0%</div>
|
||
</div>
|
||
<div class="ub-icons">
|
||
<div class="ub-btn muted" title="Muted" onclick="this.classList.toggle('muted')">
|
||
<svg viewBox="0 0 16 16"><path d="M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325L6.188 3.61a.5.5 0 0 1 .53-.06z"/><path d="M10.707 11.182A4.486 4.486 0 0 0 12.025 8a4.486 4.486 0 0 0-1.318-3.182L9.99 5.525A3.489 3.489 0 0 1 11.025 8 3.49 3.49 0 0 1 9.99 10.475l.717.707z"/></svg>
|
||
</div>
|
||
<div class="ub-btn" title="Deafen" onclick="this.classList.toggle('muted')">
|
||
<svg viewBox="0 0 16 16"><path d="M8 3a5 5 0 0 0-5 5v1h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V8a6 6 0 1 1 12 0v5a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1V8a5 5 0 0 0-5-5z"/></svg>
|
||
</div>
|
||
<div class="ub-btn" title="Settings" onclick="document.getElementById('settingsOv').classList.add('show')">
|
||
<svg viewBox="0 0 16 16"><path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/></svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MAIN CHAT -->
|
||
<div class="main">
|
||
<div class="main-hdr">
|
||
<span class="mh-icon">#</span>
|
||
<span class="mh-name">general</span>
|
||
<div class="mh-sep"></div>
|
||
<span class="mh-desc">Общий чат для всех участников сервера.</span>
|
||
<div class="mh-actions">
|
||
<div class="mh-btn" title="Pinned"><svg viewBox="0 0 16 16"><path d="M4.146.146A.5.5 0 0 1 4.5 0h7a.5.5 0 0 1 .5.5c0 .68-.342 1.174-.646 1.479-.126.125-.25.224-.354.298v4.431l.078.048c.203.127.476.314.751.555C12.36 7.775 13 8.527 13 9.5a.5.5 0 0 1-.5.5h-4v4.5c0 .276-.224 2-.5 2s-.5-1.724-.5-2V10h-4a.5.5 0 0 1-.5-.5c0-.973.64-1.725 1.17-2.189A5.921 5.921 0 0 1 5 6.708V2.277a2.77 2.77 0 0 1-.354-.298C4.342 1.674 4 1.179 4 .5a.5.5 0 0 1 .146-.354z"/></svg></div>
|
||
<div class="mh-btn" title="Search"><svg viewBox="0 0 16 16"><path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/></svg></div>
|
||
<div class="mh-btn" title="Toggle members" onclick="toggleMb()"><svg viewBox="0 0 16 16"><path d="M15 14s1 0 1-1-1-4-5-4-5 3-5 4 1 1 1 1h8zm-7.978-1A.261.261 0 0 1 7 12.996c.001-.264.167-1.03.76-1.72C8.312 10.629 9.282 10 11 10c1.717 0 2.687.63 3.24 1.276.593.69.758 1.457.76 1.72l-.008.002-.014.002H7.022zM11 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0zM6.936 9.28a5.88 5.88 0 0 0-1.23-.247A7.35 7.35 0 0 0 5 9c-4 0-5 3-5 4 0 .667.333 1 1 1h4.216A2.238 2.238 0 0 1 5 13c0-1.01.377-2.042 1.09-2.904.243-.294.526-.569.846-.816zM4.92 10A5.493 5.493 0 0 0 4 13H1c0-.26.164-1.03.76-1.724.545-.636 1.492-1.256 3.16-1.275zM1.5 5.5a3 3 0 1 1 6 0 3 3 0 0 1-6 0zm3-2a2 2 0 1 0 0 4 2 2 0 0 0 0-4z"/></svg></div>
|
||
</div>
|
||
</div>
|
||
<div class="messages" id="msgs">
|
||
<div class="sys-msg">connected · nightcore.lnex · quic/v1</div>
|
||
<!-- Group 1: nekit (2 messages) -->
|
||
<div class="msg-group ns">
|
||
<div class="msg-layout">
|
||
<div class="msg-av av1" onclick="showProfile('nekit','av1','NK','Admin','admin')">NK</div>
|
||
<div class="msg-cont">
|
||
<div class="msg-hdr"><span class="msg-author" style="color:#c88b5a" onclick="showProfile('nekit','av1','NK','Admin','admin')">nekit</span><span class="msg-time">Сегодня, 14:32</span></div>
|
||
<div class="msg-text">Всем привет! Как у вас дела?</div>
|
||
</div>
|
||
</div>
|
||
<div class="msg-actions"><div class="ma-btn">↩</div><div class="ma-btn">☺</div><div class="ma-btn">⎘</div></div>
|
||
</div>
|
||
<!-- Group 2: morfey -->
|
||
<div class="msg-group ns">
|
||
<div class="msg-layout">
|
||
<div class="msg-av av4" onclick="showProfile('morfey','av4','MF','Admin','admin')">MF</div>
|
||
<div class="msg-cont">
|
||
<div class="msg-hdr"><span class="msg-author" style="color:#c43a7a" onclick="showProfile('morfey','av4','MF','Admin','admin')">morfey</span><span class="msg-time">14:33</span></div>
|
||
<div class="msg-text">Привет! Всё отлично, тестирую новый клиент 👌</div>
|
||
</div>
|
||
</div>
|
||
<div class="msg-actions"><div class="ma-btn">↩</div><div class="ma-btn">☺</div><div class="ma-btn">⎘</div></div>
|
||
</div>
|
||
<!-- Group 3: sylvans -->
|
||
<div class="msg-group ns">
|
||
<div class="msg-layout">
|
||
<div class="msg-av av2" onclick="showProfile('sylvans','av2','SY','Moderator','moderator')">SY</div>
|
||
<div class="msg-cont">
|
||
<div class="msg-hdr"><span class="msg-author" style="color:#9e7a9e" onclick="showProfile('sylvans','av2','SY','Moderator','moderator')">sylvans</span><span class="msg-time">14:34</span></div>
|
||
<div class="msg-text">Звук просто огонь, спасибо за апдейт!</div>
|
||
</div>
|
||
</div>
|
||
<div class="msg-actions"><div class="ma-btn">↩</div><div class="ma-btn">☺</div><div class="ma-btn">⎘</div></div>
|
||
</div>
|
||
<!-- Group 4: nekit (2 messages grouped) -->
|
||
<div class="msg-group ns">
|
||
<div class="msg-layout">
|
||
<div class="msg-av av1" onclick="showProfile('nekit','av1','NK','Admin','admin')">NK</div>
|
||
<div class="msg-cont">
|
||
<div class="msg-hdr"><span class="msg-author" style="color:#c88b5a">nekit</span><span class="msg-time">14:35</span></div>
|
||
<div class="msg-text">Рад, что нравится!</div>
|
||
</div>
|
||
</div>
|
||
<div class="msg-actions"><div class="ma-btn">↩</div><div class="ma-btn">☺</div><div class="ma-btn">⎘</div></div>
|
||
</div>
|
||
<div class="msg-group">
|
||
<div class="msg-cont-inline">
|
||
<div class="msg-text">Не забывайте читать <a href="#">#announcements</a> — важные апдейты по протоколу.</div>
|
||
</div>
|
||
<div class="msg-actions"><div class="ma-btn">↩</div><div class="ma-btn">☺</div><div class="ma-btn">⎘</div></div>
|
||
</div>
|
||
<div class="day-sep">today</div>
|
||
<!-- System event -->
|
||
<div class="msg-group ns sys-g">
|
||
<div class="msg-layout">
|
||
<div class="msg-av" style="background:var(--bg3);color:var(--text3);font-size:13px">⚙</div>
|
||
<div class="msg-cont">
|
||
<div class="msg-hdr"><span class="msg-author" style="color:var(--text3)">system</span><span class="msg-time">14:36</span></div>
|
||
<div class="msg-text" style="color:var(--text3);font-family:var(--mono);font-size:11px">Guest_42 joined · lnex://nc.a1b2c3d4</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Group 5: Guest_42 -->
|
||
<div class="msg-group ns">
|
||
<div class="msg-layout">
|
||
<div class="msg-av av6">G4</div>
|
||
<div class="msg-cont">
|
||
<div class="msg-hdr"><span class="msg-author" style="color:#9e7a3a">Guest_42</span><span class="msg-time">14:36</span></div>
|
||
<div class="msg-text">Всем ку!</div>
|
||
</div>
|
||
</div>
|
||
<div class="msg-actions"><div class="ma-btn">↩</div><div class="ma-btn">☺</div><div class="ma-btn">⎘</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="input-area">
|
||
<div class="input-box">
|
||
<div class="input-top">
|
||
<span class="input-ch">#general</span>
|
||
<input class="input-field" type="text" placeholder="Message #general…" id="msgInput" onkeydown="sendMsg(event)">
|
||
</div>
|
||
<div class="input-actions">
|
||
<div class="ia-btn"><svg viewBox="0 0 16 16"><path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/><path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/></svg>Attach</div>
|
||
<div class="ia-btn"><svg viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M4.285 9.567a.5.5 0 0 1 .683.183A3.498 3.498 0 0 0 8 11.5a3.498 3.498 0 0 0 3.032-1.75.5.5 0 1 1 .866.5A4.498 4.498 0 0 1 8 12.5a4.498 4.498 0 0 1-3.898-2.25.5.5 0 0 1 .183-.683zM7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/></svg>Emoji</div>
|
||
<div class="ia-right">
|
||
<div class="ia-enc"><svg viewBox="0 0 16 16"><path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/></svg>E2E</div>
|
||
<div class="ia-send" onclick="doSend()">Send</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MEMBERS -->
|
||
<div class="members" id="mbPanel">
|
||
<div class="mb-label" style="margin-bottom:12px">УЧАСТНИКИ — 12</div>
|
||
<div class="mb-section">
|
||
<div class="mb-label">ADMIN (2)</div>
|
||
<div class="mb-item" onclick="showProfile('nekit','av1','NK','Admin','admin')"><div class="mb-av av1">NK<div class="mb-status st-on"></div></div><div><div class="mb-name">nekit</div><div class="mb-tag" style="color:#fb923c">Admin</div></div></div>
|
||
<div class="mb-item" onclick="showProfile('morfey','av4','MF','Admin','admin')"><div class="mb-av av4">MF<div class="mb-status st-on"></div></div><div><div class="mb-name">morfey</div><div class="mb-tag" style="color:#fb923c">Admin</div></div></div>
|
||
</div>
|
||
<div class="mb-section">
|
||
<div class="mb-label">MODERATOR (1)</div>
|
||
<div class="mb-item" onclick="showProfile('sylvans','av2','SY','Moderator','moderator')"><div class="mb-av av2">SY<div class="mb-status st-on"></div></div><div><div class="mb-name">sylvans</div><div class="mb-tag" style="color:#a07cc6">Moderator</div></div></div>
|
||
</div>
|
||
<div class="mb-section">
|
||
<div class="mb-label">ONLINE (7)</div>
|
||
<div class="mb-item"><div class="mb-av av6">G4<div class="mb-status st-on"></div></div><div><div class="mb-name">Guest_42</div></div></div>
|
||
<div class="mb-item"><div class="mb-av av5">DM<div class="mb-status st-on"></div></div><div><div class="mb-name">diman</div></div></div>
|
||
<div class="mb-item"><div class="mb-av av7">RV<div class="mb-status st-idle"></div></div><div><div class="mb-name">reverse</div></div></div>
|
||
<div class="mb-item"><div class="mb-av av8">SH<div class="mb-status st-on"></div></div><div><div class="mb-name">shizo</div></div></div>
|
||
<div class="mb-item"><div class="mb-av av1">KT<div class="mb-status st-on"></div></div><div><div class="mb-name">kitsune</div></div></div>
|
||
<div class="mb-item"><div class="mb-av av3">LG<div class="mb-status st-dnd"></div></div><div><div class="mb-name">l1ght</div></div></div>
|
||
<div class="mb-item"><div class="mb-av av2">M4<div class="mb-status st-on"></div></div><div><div class="mb-name">m41k</div></div></div>
|
||
</div>
|
||
<div class="mb-section">
|
||
<div class="mb-label">OFFLINE (2)</div>
|
||
<div class="mb-item" style="opacity:.35"><div class="mb-av" style="background:var(--bg3);color:var(--text3);font-size:10px">GH<div class="mb-status st-off"></div></div><div><div class="mb-name" style="color:var(--text3)">ghost</div></div></div>
|
||
<div class="mb-item" style="opacity:.35"><div class="mb-av" style="background:var(--bg3);color:var(--text3);font-size:10px">OL<div class="mb-status st-off"></div></div><div><div class="mb-name" style="color:var(--text3)">oldman</div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Settings tabs
|
||
function switchTab(name, el) {
|
||
document.querySelectorAll('.pg').forEach(p => p.classList.remove('active'));
|
||
document.getElementById('pg-' + name).classList.add('active');
|
||
document.querySelectorAll('.s-tab').forEach(t => t.classList.remove('active'));
|
||
el.classList.add('active');
|
||
}
|
||
// Members toggle
|
||
function toggleMb() {
|
||
document.getElementById('mbPanel').classList.toggle('hidden');
|
||
}
|
||
// Send message
|
||
function sendMsg(e) { if(e.key === 'Enter') doSend(); }
|
||
function doSend() {
|
||
const inp = document.getElementById('msgInput');
|
||
const text = inp.value.trim(); if(!text) return; inp.value = '';
|
||
const area = document.getElementById('msgs');
|
||
const now = new Date();
|
||
const t = now.getHours().toString().padStart(2,'0') + ':' + now.getMinutes().toString().padStart(2,'0');
|
||
const g = document.createElement('div'); g.className = 'msg-group ns';
|
||
g.innerHTML = `<div class="msg-layout"><div class="msg-av av1">NK</div><div class="msg-cont"><div class="msg-hdr"><span class="msg-author" style="color:#c88b5a">nekit</span><span class="msg-time">${t}</span></div><div class="msg-text">${text.replace(/</g,'<')}</div></div></div><div class="msg-actions"><div class="ma-btn">↩</div><div class="ma-btn">☺</div><div class="ma-btn">⎘</div></div>`;
|
||
area.appendChild(g); area.scrollTop = area.scrollHeight;
|
||
}
|
||
// Profile card
|
||
const roleColors = {
|
||
admin: {color:'#fb923c',border:'rgba(251,146,60,.2)',bg:'rgba(251,146,60,.05)'},
|
||
moderator: {color:'#a07cc6',border:'rgba(160,124,198,.2)',bg:'rgba(160,124,198,.05)'},
|
||
member: {color:'var(--text3)',border:'var(--border)',bg:'transparent'}
|
||
};
|
||
function showProfile(name, avClass, initials, role, roleKey) {
|
||
const ov = document.getElementById('profileOv');
|
||
const av = document.getElementById('pcAv');
|
||
av.className = 'pc-av ' + avClass;
|
||
av.textContent = initials;
|
||
document.getElementById('pcName').textContent = name;
|
||
document.getElementById('pcTag').textContent = name + '#000' + (Math.floor(Math.random()*9)+1) + ' · nightcore.lnex';
|
||
const roleEl = document.getElementById('pcRole');
|
||
const rc = roleColors[roleKey] || roleColors.member;
|
||
roleEl.textContent = role;
|
||
roleEl.style.color = rc.color;
|
||
roleEl.style.borderColor = rc.border;
|
||
roleEl.style.background = rc.bg;
|
||
ov.classList.add('show');
|
||
}
|
||
// Voice focus
|
||
function focusUser(name, avClass, initials) {
|
||
document.getElementById('voMain').classList.add('speaking');
|
||
const av = document.getElementById('voMainAv');
|
||
av.className = 'vo-main-av ' + avClass;
|
||
av.textContent = initials;
|
||
document.getElementById('voMainName').textContent = name;
|
||
}
|
||
// Level bars animation
|
||
setInterval(() => {
|
||
const l1 = document.getElementById('lvl1'), l2 = document.getElementById('lvl2');
|
||
if(l1) l1.style.width = Math.max(5, Math.min(96, 68+(Math.random()-.5)*34))+'%';
|
||
if(l2) l2.style.width = Math.max(5, Math.min(88, 52+(Math.random()-.5)*28))+'%';
|
||
}, 150);
|
||
// Close settings/profile on backdrop click
|
||
document.getElementById('settingsOv').addEventListener('click', function(e) {
|
||
if(e.target === this) this.classList.remove('show');
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|