From 20093a664445a5293289dc3a0062f50277f4a061 Mon Sep 17 00:00:00 2001 From: iven Date: Sun, 1 Mar 2026 18:24:02 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=BB=84=E4=BB=B6=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E7=B3=BB=E7=BB=9F=E4=B8=BA=E7=8E=BB=E7=92=83=E6=80=81?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E9=A3=8E=E6=A0=BC=E5=B9=B6=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E5=8A=A8=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/openfang-api/static/css/components.css | 4525 +++++------------ crates/openfang-api/static/css/layout.css | 1166 +++-- crates/openfang-api/static/css/theme.css | 894 +++- crates/openfang-api/static/index_head.html | 40 +- crates/openfang-kernel/src/presence.rs | 34 +- 5 files changed, 2953 insertions(+), 3706 deletions(-) diff --git a/crates/openfang-api/static/css/components.css b/crates/openfang-api/static/css/components.css index bc17fa7..929a943 100644 --- a/crates/openfang-api/static/css/components.css +++ b/crates/openfang-api/static/css/components.css @@ -1,1062 +1,260 @@ -/* OpenFang Components — Premium design system */ +/* ═══════════════════════════════════════════════════════════════════════════ + OpenFang Components — Premium Glassmorphism Design System + ═══════════════════════════════════════════════════════════════════════════ + + Design Philosophy: + - Glassmorphism with frosted glass effects + - Soft shadows with colored glow accents + - Spring animations for premium feel + - WCAG AAA accessibility compliance + + ═══════════════════════════════════════════════════════════════════════════ */ + +/* ═══════════════════════════════════════════════════════════════════════════ + BUTTONS — Premium tactile interactions + ═══════════════════════════════════════════════════════════════════════════ */ -/* Buttons */ .btn { - padding: 8px 16px; + padding: 10px 18px; border: none; - border-radius: var(--radius-sm); + border-radius: var(--radius-md); cursor: pointer; font-family: var(--font-sans); font-size: 13px; font-weight: 600; - transition: all var(--transition-fast); + letter-spacing: -0.01em; + transition: + transform var(--transition-fast), + box-shadow var(--transition-fast), + background-color var(--transition-fast), + border-color var(--transition-fast); display: inline-flex; align-items: center; justify-content: center; - gap: 6px; + gap: 8px; white-space: nowrap; position: relative; - letter-spacing: -0.01em; + overflow: hidden; } -.btn:active { transform: scale(0.97); } -.btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; } +/* Ripple effect container */ +.btn::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient(circle, rgba(255,255,255,0.3) 0%, transparent 70%); + transform: scale(0); + opacity: 0; + transition: transform 0.5s, opacity 0.3s; +} + +.btn:active::before { + transform: scale(2.5); + opacity: 1; + transition: transform 0s, opacity 0s; +} + +.btn:active { + transform: scale(0.97); +} + +.btn:disabled { + opacity: 0.4; + cursor: not-allowed; + transform: none !important; +} + +.btn:disabled::before { + display: none; +} + +/* Primary button — Accent gradient */ .btn-primary { - background: var(--accent); - color: var(--bg-primary); - box-shadow: var(--shadow-xs), var(--shadow-inset); + background: var(--gradient-accent); + color: var(--text-on-accent); + box-shadow: var(--shadow-sm), var(--shadow-accent); + text-shadow: 0 1px 1px rgba(0,0,0,0.1); } -.btn-primary:hover { background: var(--accent-dim); box-shadow: var(--shadow-sm), var(--shadow-accent); transform: translateY(-1px); } -.btn-success { background: var(--success); color: #000; box-shadow: var(--shadow-xs); } -.btn-success:hover { background: var(--success-dim); box-shadow: var(--shadow-sm); transform: translateY(-1px); } -.btn-danger { background: var(--error); color: #fff; box-shadow: var(--shadow-xs); } -.btn-danger:hover { background: var(--error-dim); box-shadow: var(--shadow-sm); transform: translateY(-1px); } -.btn-ghost { - background: transparent; - color: var(--text-dim); - border: 1px solid var(--border); -} -.btn-ghost:hover { background: var(--surface2); color: var(--text); border-color: var(--border-light); transform: translateY(-1px); } -.btn-sm { padding: 5px 10px; font-size: 12px; } -.btn-block { width: 100%; } -/* Cards */ +.btn-primary:hover:not(:disabled) { + box-shadow: var(--shadow-md), var(--shadow-accent); + transform: translateY(-2px); + filter: brightness(1.05); +} + +.btn-primary:active:not(:disabled) { + transform: translateY(0) scale(0.98); + box-shadow: var(--shadow-sm), var(--shadow-accent); +} + +/* Success button */ +.btn-success { + background: var(--gradient-success); + color: #FFFFFF; + box-shadow: var(--shadow-sm), var(--shadow-success); +} + +.btn-success:hover:not(:disabled) { + box-shadow: var(--shadow-md), var(--shadow-success); + transform: translateY(-2px); + filter: brightness(1.05); +} + +/* Danger button */ +.btn-danger { + background: var(--error); + color: #FFFFFF; + box-shadow: var(--shadow-sm), var(--shadow-error); +} + +.btn-danger:hover:not(:disabled) { + background: var(--error-hover); + box-shadow: var(--shadow-md), var(--shadow-error); + transform: translateY(-2px); +} + +/* Ghost button — Glass effect */ +.btn-ghost { + background: var(--surface-glass); + backdrop-filter: blur(var(--glass-blur-subtle)); + -webkit-backdrop-filter: blur(var(--glass-blur-subtle)); + color: var(--text-secondary); + border: 1px solid var(--border); + box-shadow: var(--shadow-xs); +} + +.btn-ghost:hover:not(:disabled) { + background: var(--surface2); + color: var(--text); + border-color: var(--border-strong); + transform: translateY(-1px); + box-shadow: var(--shadow-sm); +} + +/* Button sizes */ +.btn-sm { + padding: 6px 12px; + font-size: 12px; + border-radius: var(--radius-sm); +} + +.btn-xs { + padding: 4px 8px; + font-size: 11px; + border-radius: var(--radius-xs); +} + +.btn-lg { + padding: 14px 24px; + font-size: 15px; + border-radius: var(--radius-lg); +} + +.btn-block { + width: 100%; +} + +/* Icon-only button */ +.btn-icon { + padding: 10px; + width: 40px; + height: 40px; +} + +.btn-icon.btn-sm { + width: 32px; + height: 32px; + padding: 6px; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + CARDS — Glassmorphism containers + ═══════════════════════════════════════════════════════════════════════════ */ + .card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 16px; - transition: border-color var(--transition-fast), transform 0.2s var(--ease-spring), box-shadow var(--transition-fast); - position: relative; - box-shadow: var(--shadow-xs), var(--shadow-inset); -} - -.card:hover { - border-color: var(--border-strong); - transform: translateY(-2px); - box-shadow: var(--shadow-md), var(--shadow-inset); -} -.card:focus-within { - border-color: var(--accent); - box-shadow: var(--shadow-md), var(--shadow-inset); -} -.card-header { font-size: 13px; font-weight: 600; margin-bottom: 8px; color: var(--text); } -.card-meta { font-size: 12px; color: var(--text-dim); } - -.card-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 16px; -} - -/* Glow effect on card hover */ -.card-glow { - overflow: hidden; -} -.card-glow::before { - content: ''; - position: absolute; - top: 0; left: 0; right: 0; bottom: 0; - background: radial-gradient(600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%), var(--accent-glow), transparent 40%); - opacity: 0; - transition: opacity 0.3s ease; - pointer-events: none; - border-radius: inherit; -} -.card-glow:hover::before { opacity: 1; } - -/* Badges */ -.badge { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 2px 8px; - border-radius: 20px; - font-size: 10px; - font-weight: 600; - letter-spacing: 0.5px; - text-transform: uppercase; -} - -.badge-running { background: rgba(74,222,128,0.12); color: var(--success); } -.badge-suspended { background: rgba(245,158,11,0.12); color: var(--warning); } -.badge-terminated { background: rgba(239,68,68,0.12); color: var(--error); } -.badge-created { background: rgba(59,130,246,0.12); color: var(--info); } -.badge-crashed { background: rgba(239,68,68,0.2); color: var(--error); } -.badge-connected { background: rgba(74,222,128,0.12); color: var(--success); } -.badge-disconnected { background: rgba(239,68,68,0.12); color: var(--error); } -.badge-success { background: rgba(74,222,128,0.12); color: var(--success); } -.badge-warn { background: rgba(250,204,21,0.15); color: var(--warning); } -.badge-error { background: rgba(239,68,68,0.12); color: var(--error); } -.badge-muted { background: rgba(148,163,184,0.12); color: var(--text-dim); } -.badge-info { background: rgba(59,130,246,0.12); color: var(--info); } -.badge-dim { background: rgba(148,163,184,0.08); color: var(--text-dim); font-size: 0.65rem; } -.text-danger { color: var(--error); } - -/* Tables */ -.table-wrap { - overflow-x: auto; - border: 1px solid var(--border); - border-radius: var(--radius-lg); - background: var(--surface); -} - -table { - width: 100%; - border-collapse: collapse; - font-size: 12px; -} - -th { - text-align: left; - padding: 10px 14px; - background: var(--surface3); - font-size: 10px; - text-transform: uppercase; - letter-spacing: 1px; - color: var(--text-dim); - font-weight: 600; - border-bottom: 1px solid var(--border); - white-space: nowrap; -} - -td { - padding: 10px 14px; - border-bottom: 1px solid var(--border); - vertical-align: top; -} - -tr:last-child td { border-bottom: none; } -tr:hover td { background: var(--surface2); } - -/* Forms */ -.form-group { - margin-bottom: 14px; -} - -.form-group label { - display: block; - font-size: 11px; - font-weight: 600; - color: var(--text-dim); - margin-bottom: 4px; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.form-input, .form-select, .form-textarea { - width: 100%; - padding: 9px 12px; - background: var(--bg); - color: var(--text); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - font-family: var(--font-sans); - font-size: 13px; - transition: border-color 0.2s var(--ease-smooth), box-shadow 0.2s var(--ease-smooth); -} - -.form-input:focus, .form-select:focus, .form-textarea:focus { - outline: none; - border-color: var(--accent); - box-shadow: 0 0 0 3px var(--accent-glow); -} - -.form-textarea { - resize: vertical; - min-height: 80px; -} - -.form-select { cursor: pointer; } - -.form-checkbox { - display: flex; - align-items: center; - gap: 8px; - font-size: 12px; - cursor: pointer; -} - -.form-checkbox input[type="checkbox"] { - accent-color: var(--accent); -} - -/* Modals */ -.modal-overlay { - position: fixed; - inset: 0; - background: rgba(8,7,6,0.8); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; - backdrop-filter: blur(8px); - animation: fadeIn 0.15s var(--ease-smooth); -} - -.modal { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-xl); - padding: 24px; - max-width: 600px; - width: 90%; - max-height: 80vh; - overflow-y: auto; - box-shadow: var(--shadow-xl); - animation: scaleIn 0.2s var(--ease-spring); -} - -.modal-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 16px; -} - -.modal-header h3 { font-size: 15px; } - -.modal-close { - background: none; - border: none; - color: var(--text-muted); - cursor: pointer; - font-size: 18px; - padding: 4px; - transition: color 0.15s; -} - -.modal-close:hover { color: var(--text); } - -/* Settings option cards */ -.setting-option-card:hover { border-color: var(--text-muted) !important; } -.setting-option-selected { border-color: var(--primary) !important; background: rgba(99, 102, 241, 0.08); } - -/* Messages / Chat */ -.chat-wrapper { - display: flex; - flex-direction: column; - flex: 1; - min-height: 0; - overflow: hidden; -} - -.messages { - flex: 1; - overflow-y: auto; - padding: 20px 24px; - scroll-behavior: smooth; - overscroll-behavior: contain; -} - -.message { - margin-bottom: 20px; - animation: slideUp 0.25s var(--ease-smooth); - display: flex; - gap: 12px; - align-items: flex-start; + padding: var(--card-padding); position: relative; + transition: + transform var(--transition-fast), + box-shadow var(--transition-fast), + border-color var(--transition-fast); } -.message:hover .message-actions { opacity: 1; pointer-events: auto; } - -@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } - -.message.user { - flex-direction: row-reverse; +/* Glass card variant */ +.card-glass { + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur)); + -webkit-backdrop-filter: blur(var(--glass-blur)); + border: 1px solid var(--glass-border); } -.message-avatar { - width: 30px; - height: 30px; - border-radius: 50%; - overflow: hidden; - flex-shrink: 0; - background: var(--surface); - border: 1px solid var(--border); - display: flex; - align-items: center; - justify-content: center; - margin-top: 2px; -} - -.message-avatar img { - width: 18px; - height: 18px; - object-fit: contain; -} - -.message-body { - min-width: 0; - max-width: 100%; - flex: 1; - position: relative; -} - -.message-bubble { - padding: 10px 14px; - border-radius: var(--radius-lg); - font-size: 13.5px; - line-height: 1.65; - word-break: break-word; -} - -.message.user .message-bubble { - background: var(--user-bg); - border: 1px solid rgba(255,92,0,0.12); - border-bottom-right-radius: var(--radius-sm); -} -.message.agent .message-bubble { - background: var(--agent-bg); - border: 1px solid var(--border-subtle); - border-bottom-left-radius: var(--radius-sm); - padding: 10px 14px; -} -.message.system .message-bubble { - background: var(--surface3); - border: 1px solid var(--border); - font-size: 12px; - border-radius: var(--radius-md); -} -.message.system { - max-width: 600px; -} -.message.thinking .message-bubble { animation: pulse 1.5s infinite; } - -/* Streaming indicator — pulsing left border */ -.message.streaming .message-bubble { +/* Card with accent border */ +.card-accent { border-left: 3px solid var(--accent); - animation: stream-pulse 2s ease-in-out infinite; -} -@keyframes stream-pulse { - 0%, 100% { border-left-color: var(--accent); box-shadow: -2px 0 8px var(--accent-glow); } - 50% { border-left-color: var(--accent-dim); box-shadow: none; } } -/* Message timestamp + meta */ -.message-time { - font-size: 10px; - color: var(--text-muted); - margin-top: 4px; - padding-left: 2px; - opacity: 0; - transition: opacity 0.15s; - user-select: none; -} -.message:hover .message-time { opacity: 0.7; } -.message-meta { - font-size: 10px; - color: var(--text-muted); - margin-top: 2px; - padding-left: 2px; - opacity: 0.6; - font-family: var(--font-mono); +.card-accent-success { + border-left-color: var(--success); } -/* Message hover actions (copy button) */ -.message-actions { - position: absolute; - top: -4px; - right: 0; - display: flex; - gap: 2px; - opacity: 0; - pointer-events: none; - transition: opacity 0.15s; - z-index: 2; -} -.message.user .message-actions { right: auto; left: 0; } -.message-action-btn { - width: 28px; - height: 28px; - border-radius: var(--radius-sm); - border: 1px solid var(--border); - background: var(--surface); - color: var(--text-dim); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.15s; - box-shadow: var(--shadow-xs); -} -.message-action-btn:hover { - background: var(--surface2); - color: var(--text); - border-color: var(--border-light); -} -.message-action-btn.copied { - color: var(--success); - border-color: var(--success); -} - -/* Typing indicator dots */ -.typing-dots { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 4px 0; -} -.typing-dots span { - width: 6px; - height: 6px; - border-radius: 50%; - background: var(--text-dim); - animation: typing-bounce 1.4s ease-in-out infinite; -} -.typing-dots span:nth-child(2) { animation-delay: 0.16s; } -.typing-dots span:nth-child(3) { animation-delay: 0.32s; } -@keyframes typing-bounce { - 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; } - 30% { transform: translateY(-4px); opacity: 1; } -} - -/* Voice recording */ -.btn-recording { - background: rgba(239, 68, 68, 0.15) !important; - color: var(--danger) !important; - animation: recording-pulse 1s ease-in-out infinite; -} -.recording-dot { - display: inline-block; - width: 8px; - height: 8px; - border-radius: 50%; - background: var(--danger); - animation: recording-pulse 1s ease-in-out infinite; -} -.recording-indicator { - display: flex; - align-items: center; - gap: 6px; - padding: 0 4px; - flex-shrink: 0; -} -@keyframes recording-pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.4; } -} - -/* Audio player in tool card */ -.audio-player { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 10px; - background: var(--surface2); - border-radius: var(--radius-sm); - border: 1px solid var(--border-subtle); -} - -/* Canvas panel */ -.canvas-panel { - border: 1px solid var(--border); - border-radius: 8px; - margin: 8px 0; - overflow: hidden; -} -.canvas-panel iframe { - width: 100%; - min-height: 300px; - border: none; - background: #fff; - resize: vertical; - overflow: auto; -} - -/* Queue indicator badge */ -.queue-badge { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 2px 8px; - border-radius: 10px; - background: var(--accent-subtle); - color: var(--accent); - font-size: 11px; - font-weight: 600; - font-family: var(--font-mono); - animation: fadeIn 0.2s; -} - -/* Session switcher */ -.session-count-badge { - position: absolute; - top: -2px; - right: -2px; - width: 14px; - height: 14px; - border-radius: 50%; - background: var(--accent); - color: var(--bg-primary); - font-size: 9px; - font-weight: 700; - display: flex; - align-items: center; - justify-content: center; - line-height: 1; -} -.session-dropdown { - position: absolute; - top: 100%; - right: 0; - z-index: 100; - width: 240px; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-md); - box-shadow: 0 4px 12px rgba(0,0,0,0.3); - overflow: hidden; -} -.session-dropdown-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 8px 12px; - border-bottom: 1px solid var(--border); -} -.session-item { - display: flex; - align-items: center; - gap: 8px; - padding: 8px 12px; - cursor: pointer; - transition: background 0.1s; -} -.session-item:hover { background: var(--surface2); } -.session-item.active { background: var(--accent-subtle); cursor: default; } -.session-dot { - width: 6px; - height: 6px; - border-radius: 50%; - background: var(--text-muted); - flex-shrink: 0; -} -.session-dot.active { background: var(--success); } - -/* Chat search bar */ -.chat-search-bar { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 12px; - background: var(--surface2); - border-bottom: 1px solid var(--border); - flex-shrink: 0; -} -.chat-search-input { - flex: 1; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - padding: 4px 10px; - font-size: 13px; - color: var(--text); - outline: none; - font-family: var(--font-sans); -} -.chat-search-input:focus { - border-color: var(--accent); - box-shadow: 0 0 0 2px var(--accent-subtle); -} -mark.search-highlight { - background: var(--warning, #f59e0b); - color: #000; - border-radius: 2px; - padding: 0 1px; -} - -/* Markdown in messages */ -.message-bubble.markdown-body { - font-family: var(--font-sans); -} - -.message-bubble.markdown-body code { - font-family: var(--font-mono); - background: var(--surface2); - padding: 1px 5px; - border-radius: 3px; - font-size: 0.9em; - color: var(--accent-light); -} - -.message-bubble.markdown-body pre { - background: var(--bg); - border: 1px solid var(--border); - border-radius: var(--radius-md); - padding: 14px; - overflow-x: auto; - margin: 8px 0; - position: relative; -} - -.message-bubble.markdown-body pre code { - background: none; - padding: 0; - font-size: 12px; - color: var(--text); -} - -.copy-btn { - position: absolute; - top: 6px; - right: 6px; - padding: 3px 8px; - font-size: 10px; - font-family: var(--font-mono); - background: var(--surface2); - color: var(--text-muted); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - cursor: pointer; - transition: all 0.15s; -} - -.copy-btn:hover { color: var(--text); background: var(--surface); border-color: var(--border-light); } - -/* Tool call cards — premium design with category icons */ -.tool-card { - background: var(--surface); - border: 1px solid var(--border); - border-left: 3px solid var(--accent); - border-radius: var(--radius-md); - margin: 8px 0; - overflow: hidden; - box-shadow: var(--shadow-xs); - transition: border-color var(--transition-fast), box-shadow var(--transition-fast); - animation: slideUp 0.2s var(--ease-smooth); -} - -.tool-card:hover { box-shadow: var(--shadow-sm); } - -.tool-card-error { +.card-accent-error { border-left-color: var(--error); - background: var(--error-subtle); } -/* Tool category colors */ -.tool-card[data-tool^="file_"], -.tool-card[data-tool^="directory_"] { border-left-color: #60A5FA; } -.tool-card[data-tool^="web_"], -.tool-card[data-tool^="link_"] { border-left-color: #34D399; } -.tool-card[data-tool^="shell"], -.tool-card[data-tool^="exec_"] { border-left-color: #FBBF24; } -.tool-card[data-tool^="agent_"] { border-left-color: #A78BFA; } -.tool-card[data-tool^="memory_"], -.tool-card[data-tool^="knowledge_"] { border-left-color: #F472B6; } -.tool-card[data-tool^="cron_"], -.tool-card[data-tool^="schedule_"] { border-left-color: #FB923C; } -.tool-card[data-tool^="browser_"], -.tool-card[data-tool^="playwright_"] { border-left-color: #2DD4BF; } -.tool-card[data-tool^="container_"], -.tool-card[data-tool^="docker_"] { border-left-color: #38BDF8; } -.tool-card[data-tool^="image_"], -.tool-card[data-tool^="tts_"] { border-left-color: #E879F9; } -.tool-card[data-tool^="hand_"] { border-left-color: var(--accent); } +.card-accent-info { + border-left-color: var(--info); +} -.tool-card-header { - display: flex; - align-items: center; - gap: 8px; - padding: 8px 12px; +/* Interactive card */ +.card-interactive { cursor: pointer; - font-size: 12px; - color: var(--text-dim); - transition: background var(--transition-fast); } -.tool-card-header:hover { background: var(--surface2); } - -/* Tool icon — SVG category icon before tool name */ -.tool-card-icon { - width: 16px; - height: 16px; - flex-shrink: 0; - opacity: 0.7; +.card-interactive:hover { + transform: translateY(-3px); + box-shadow: var(--shadow-lg); + border-color: var(--border-strong); } -.tool-card-name { +/* Card header */ +.card-header { + font-size: 14px; font-weight: 600; color: var(--text); - font-family: var(--font-mono); - font-size: 11.5px; -} - -.tool-card-spinner { - width: 14px; height: 14px; - border: 2px solid var(--border); - border-top-color: var(--accent); - border-radius: 50%; - animation: spin 0.8s linear infinite; - flex-shrink: 0; -} - -.tool-icon-ok { - color: var(--success); - font-size: 14px; - font-weight: 700; - flex-shrink: 0; -} - -.tool-icon-err { - color: var(--error); - font-size: 14px; - font-weight: 700; - flex-shrink: 0; -} - -.tool-expand-chevron { - font-size: 10px; - color: var(--text-muted); - flex-shrink: 0; - transition: transform var(--transition-fast); -} - -.tool-card-body { - padding: 10px 12px; - border-top: 1px solid var(--border); - font-size: 12px; - max-height: 400px; - overflow-y: auto; - background: var(--bg); - animation: slideDown 0.15s var(--ease-smooth); -} - -.tool-section-label { - font-size: 10px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--text-muted); - margin-bottom: 4px; -} - -.tool-pre { - margin: 0; - padding: 6px 10px; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - font-size: 11px; - font-family: var(--font-mono); - white-space: pre-wrap; - word-break: break-word; - max-height: 200px; - overflow-y: auto; - color: var(--text); - line-height: 1.5; -} - -/* Smart collapse — short results inline, long results preview */ -.tool-pre-short { max-height: 44px; overflow: hidden; } -.tool-pre-medium { max-height: 120px; } - -.tool-pre-error { - color: var(--error); - border-color: var(--error); - background: var(--error-subtle); -} - -/* Chat input — always pinned at bottom, premium compose area */ -.input-area { - flex-shrink: 0; - padding: 12px 24px 16px; - border-top: 1px solid var(--border); - background: linear-gradient(to top, var(--bg-primary) 0%, var(--bg-primary) 60%, transparent 100%); - display: flex; - flex-direction: column; - gap: 0; - position: relative; -} - -.input-area textarea { - flex: 1; - background: var(--surface); - color: var(--text); - border: 1px solid var(--border); - border-radius: 16px; - padding: 12px 16px; - font-family: var(--font-sans); - font-size: 14px; - resize: none; - min-height: 44px; - max-height: 150px; - line-height: 1.5; - transition: border-color 0.2s var(--ease-smooth), box-shadow 0.2s var(--ease-smooth), background 0.2s; -} - -.input-area textarea:focus { - outline: none; - border-color: var(--accent); - box-shadow: 0 0 0 3px var(--accent-glow); - background: var(--bg-elevated); -} - -.input-area textarea.streaming-active { - border-color: var(--border-light); -} - -.input-row { - display: flex; - align-items: flex-end; - gap: 8px; - width: 100%; -} - -.btn-send { - width: 40px; - height: 40px; - border-radius: 50%; - border: none; - background: var(--accent); - color: var(--bg-primary); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - transition: all 0.2s var(--ease-spring); - box-shadow: var(--shadow-sm), var(--shadow-accent); -} -.btn-send:hover { background: var(--accent-dim); transform: scale(1.05); box-shadow: var(--shadow-md), var(--shadow-accent); } -.btn-send:active { transform: scale(0.92); } -.btn-send:disabled { opacity: 0.3; cursor: not-allowed; transform: none; box-shadow: none; } - -/* Stop button variant during streaming */ -.btn-stop { - width: 40px; - height: 40px; - border-radius: 50%; - border: 2px solid var(--error); - background: var(--error-subtle); - color: var(--error); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - transition: all 0.2s var(--ease-spring); -} -.btn-stop:hover { background: var(--error); color: #fff; transform: scale(1.05); } -.btn-stop:active { transform: scale(0.92); } - -.input-footer { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 6px; - min-height: 18px; - padding: 0 4px; -} - -/* Slash command menu */ -.slash-menu { - position: absolute; - bottom: 100%; - left: 0; - right: 0; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-md); - margin-bottom: 4px; - max-height: 200px; - overflow-y: auto; - z-index: 50; - box-shadow: var(--shadow-md); -} - -.slash-menu-item { - padding: 8px 14px; - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid var(--border); - transition: background 0.1s; -} - -.slash-menu-item:last-child { border-bottom: none; } -.slash-menu-item:hover, .slash-menu-item.slash-active { background: var(--surface2); } - -/* Sidebar footer */ -.sidebar-footer { - padding: 8px 0; - border-top: 1px solid var(--border); -} - -/* Copy button copied state */ -.copy-btn.copied { - color: var(--success); - border-color: var(--success); -} - -/* Empty state — premium with subtle illustration */ -.empty-state { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - color: var(--text-dim); - padding: 80px 20px; - text-align: center; - animation: fadeIn 0.4s var(--ease-smooth); -} - -.empty-state .logo { - font-size: 36px; - color: var(--accent); - font-weight: 700; - letter-spacing: 6px; margin-bottom: 12px; -} - -.empty-state .logo-img { - width: 80px; - height: 80px; - margin-bottom: 16px; - opacity: 0.4; - transition: opacity 0.3s; -} - -.empty-state:hover .logo-img { opacity: 0.6; } - -.empty-state-icon { - width: 64px; - height: 64px; - border-radius: 50%; - background: var(--accent-subtle); display: flex; align-items: center; - justify-content: center; - margin-bottom: 16px; - color: var(--accent); - font-size: 28px; + gap: 8px; } -.empty-state h3 { - font-size: 16px; - font-weight: 600; - color: var(--text); - margin-bottom: 8px; +/* Card shine effect on hover */ +.card-shine { + overflow: hidden; } -.empty-state p { font-size: 14px; max-width: 400px; line-height: 1.6; color: var(--text-dim); margin-bottom: 16px; } - -.empty-state .btn { margin-top: 4px; } - -/* Spinner */ -.spinner { - width: 20px; height: 20px; - border: 2px solid var(--border); - border-top-color: var(--accent); - border-radius: 50%; - animation: spin 0.8s linear infinite; -} - -/* Toggle switch */ -.toggle { - position: relative; - width: 36px; - height: 20px; - background: var(--border); - border-radius: 10px; - cursor: pointer; - transition: background 0.2s; -} - -.toggle.active { background: var(--accent); } - -.toggle::after { +.card-shine::after { content: ''; position: absolute; - top: 2px; - left: 2px; - width: 16px; - height: 16px; - background: #fff; - border-radius: 50%; - transition: transform 0.2s; + inset: 0; + background: var(--gradient-card-shine); + background-size: 200% 100%; + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; } -.toggle.active::after { transform: translateX(16px); } - -/* Search input */ -.search-input { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 12px; - background: var(--bg); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - transition: border-color 0.2s; +.card-shine:hover::after { + opacity: 1; + animation: shimmer 1s ease-out; } -.search-input:focus-within { border-color: var(--accent); } +/* ═══════════════════════════════════════════════════════════════════════════ + STAT CARDS — Metrics display + ═══════════════════════════════════════════════════════════════════════════ */ -.search-input input { - background: none; - border: none; - color: var(--text); - font-family: var(--font-mono); - font-size: 12px; - outline: none; - flex: 1; -} - -.search-clear-btn { - background: none; - border: none; - color: var(--text-muted); - cursor: pointer; - font-size: 18px; - line-height: 1; - padding: 0 4px; - transition: color 0.15s; -} -.search-clear-btn:hover { color: var(--text); } - -/* Tabs */ -.tabs { - display: flex; - gap: 0; - border-bottom: 1px solid var(--border); - margin-bottom: 16px; -} - -.tab { - padding: 8px 16px; - font-size: 12px; - color: var(--text-muted); - cursor: pointer; - border-bottom: 2px solid transparent; - transition: all 0.2s; -} - -.tab:hover { color: var(--text); } -.tab.active { color: var(--accent); border-bottom-color: var(--accent); } - -/* Stats row */ .stats-row { display: flex; gap: 16px; @@ -1064,2308 +262,1413 @@ mark.search-highlight { flex-wrap: wrap; } +.stats-row-lg { + gap: 20px; +} + .stat-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 16px 20px; - min-width: 140px; flex: 1; - box-shadow: var(--shadow-xs); - transition: transform 0.2s var(--ease-spring), box-shadow var(--transition-fast), border-color var(--transition-fast); + min-width: 120px; + position: relative; + overflow: hidden; + transition: + transform var(--transition-fast), + box-shadow var(--transition-fast), + border-color var(--transition-fast); } .stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); - border-color: var(--border-light); +} + +/* Stat card with glass effect */ +.stat-card-glass { + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur)); + -webkit-backdrop-filter: blur(var(--glass-blur)); + border: 1px solid var(--glass-border); +} + +/* Large stat card */ +.stat-card-lg { + padding: 20px 24px; + border-radius: var(--radius-xl); } .stat-value { - font-size: 24px; - font-weight: 700; - color: var(--accent); font-family: var(--font-mono); + font-size: 26px; + font-weight: 700; + color: var(--text); + line-height: 1.2; letter-spacing: -0.02em; } +.stat-value-success { + color: var(--success); +} + +.stat-value-accent { + color: var(--accent); +} + .stat-label { - font-size: 11px; + font-size: 12px; color: var(--text-dim); - text-transform: uppercase; - letter-spacing: 0.5px; margin-top: 4px; font-weight: 500; } -/* Theme switcher — 3-mode pill (Light / System / Dark) */ -.theme-switcher { +/* Stat card glow effect */ +.stat-card-glow { + position: relative; +} + +.stat-card-glow::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, var(--accent-glow), transparent); + opacity: 0; + transition: opacity 0.3s; +} + +.stat-card-glow:hover::before { + opacity: 1; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + BADGES — Status indicators + ═══════════════════════════════════════════════════════════════════════════ */ + +.badge { display: inline-flex; - border-radius: var(--radius-sm); + align-items: center; + gap: 4px; + padding: 4px 10px; + border-radius: var(--radius-full); + font-size: 11px; + font-weight: 600; + letter-spacing: 0.03em; + text-transform: uppercase; + white-space: nowrap; + transition: all var(--transition-fast); +} + +/* Badge variants */ +.badge-running { + background: var(--success-subtle); + color: var(--success); + border: 1px solid rgba(34, 197, 94, 0.2); +} + +.badge-suspended { + background: var(--warning-subtle); + color: var(--warning); + border: 1px solid rgba(245, 158, 11, 0.2); +} + +.badge-crashed, .badge-error { + background: var(--error-subtle); + color: var(--error); + border: 1px solid rgba(239, 68, 68, 0.2); +} + +.badge-idle, .badge-dim { + background: var(--surface2); + color: var(--text-dim); border: 1px solid var(--border); - overflow: hidden; } -.theme-opt { - cursor: pointer; - padding: 4px 8px; + +.badge-info { + background: var(--info-subtle); + color: var(--info); + border: 1px solid rgba(59, 130, 246, 0.2); +} + +.badge-success { + background: var(--success-subtle); + color: var(--success-dim); + border: 1px solid rgba(34, 197, 94, 0.2); +} + +.badge-warning { + background: var(--warning-subtle); + color: var(--warning-dim); + border: 1px solid rgba(245, 158, 11, 0.2); +} + +/* Accent badge */ +.badge-accent { + background: var(--accent-subtle); + color: var(--accent); + border: 1px solid rgba(255, 92, 0, 0.2); +} + +/* Badge with glow */ +.badge-glow { + box-shadow: 0 0 12px currentColor; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + FORM ELEMENTS — Modern inputs + ═══════════════════════════════════════════════════════════════════════════ */ + +.form-input, +.form-select, +.form-textarea { + width: 100%; + padding: 12px 16px; + border: 1px solid var(--border); + border-radius: var(--radius-md); + background: var(--surface); + color: var(--text); + font-family: var(--font-sans); font-size: 14px; - background: none; - border: none; - color: var(--text-muted); - transition: all 0.2s; - line-height: 1; -} -.theme-opt:hover { color: var(--text-primary); background: var(--bg-hover); } -.theme-opt.active { color: var(--accent); background: var(--accent-glow); } - -/* Utility */ -.flex { display: flex; } -.flex-col { flex-direction: column; } -.items-center { align-items: center; } -.justify-between { justify-content: space-between; } -.gap-2 { gap: 8px; } -.gap-3 { gap: 12px; } -.gap-4 { gap: 16px; } -.mt-2 { margin-top: 8px; } -.mt-4 { margin-top: 16px; } -.mb-2 { margin-bottom: 8px; } -.mb-4 { margin-bottom: 16px; } -.text-dim { color: var(--text-dim); } -.text-sm { font-size: 11px; } -.text-xs { font-size: 10px; } -.font-bold { font-weight: 600; } -.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.hidden { display: none !important; } - -/* Agent card actions */ -.agent-card-actions { - display: flex; - gap: 6px; - margin-top: 12px; - padding-top: 10px; - border-top: 1px solid var(--border); + transition: + border-color var(--transition-fast), + box-shadow var(--transition-fast), + background-color var(--transition-fast); } -/* Agent picker in chat empty state */ -.agent-pick-card { - cursor: pointer; - margin-bottom: 8px; - padding: 12px; - transition: border-color 0.15s, background 0.15s; +.form-input:hover, +.form-select:hover, +.form-textarea:hover { + border-color: var(--border-strong); } -.agent-pick-card:hover { + +.form-input:focus, +.form-select:focus, +.form-textarea:focus { + outline: none; border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-glow); +} + +.form-input::placeholder, +.form-textarea::placeholder { + color: var(--text-muted); +} + +/* Input with icon */ +.form-input-icon { + position: relative; +} + +.form-input-icon .form-input { + padding-left: 40px; +} + +.form-input-icon svg { + position: absolute; + left: 14px; + top: 50%; + transform: translateY(-50%); + color: var(--text-muted); + pointer-events: none; +} + +/* Input group */ +.input-group { + display: flex; + gap: 0; +} + +.input-group .form-input, +.input-group .btn { + border-radius: 0; +} + +.input-group .form-input:first-child, +.input-group .btn:first-child { + border-top-left-radius: var(--radius-md); + border-bottom-left-radius: var(--radius-md); +} + +.input-group .form-input:last-child, +.input-group .btn:last-child { + border-top-right-radius: var(--radius-md); + border-bottom-right-radius: var(--radius-md); +} + +/* Form label */ +.form-label { + display: block; + font-size: 13px; + font-weight: 500; + color: var(--text-secondary); + margin-bottom: 6px; +} + +/* Form helper text */ +.form-helper { + font-size: 12px; + color: var(--text-muted); + margin-top: 4px; +} + +/* Form error state */ +.form-error .form-input, +.form-error .form-select, +.form-error .form-textarea { + border-color: var(--error); +} + +.form-error-text { + font-size: 12px; + color: var(--error); + margin-top: 4px; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + TOGGLE SWITCHES + ═══════════════════════════════════════════════════════════════════════════ */ + +.toggle { + position: relative; + width: 44px; + height: 24px; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: var(--radius-full); + cursor: pointer; + transition: all var(--transition-fast); +} + +.toggle::after { + content: ''; + position: absolute; + top: 2px; + left: 2px; + width: 18px; + height: 18px; + background: var(--text-dim); + border-radius: 50%; + transition: all var(--transition-fast); + box-shadow: var(--shadow-sm); +} + +.toggle.active { + background: var(--accent); + border-color: var(--accent); +} + +.toggle.active::after { + left: 22px; + background: #FFFFFF; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + MODALS — Glass overlay dialogs + ═══════════════════════════════════════════════════════════════════════════ */ + +.modal-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + z-index: var(--z-modal-backdrop); + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + animation: fadeIn 0.2s ease; +} + +.modal { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-2xl); + padding: 24px; + max-width: 500px; + width: 100%; + max-height: calc(100vh - 40px); + overflow-y: auto; + box-shadow: var(--shadow-2xl); + animation: springIn 0.4s var(--ease-spring); + position: relative; + z-index: var(--z-modal); +} + +.modal-glass { + background: var(--glass-bg-strong); + backdrop-filter: blur(var(--glass-blur-strong)); + -webkit-backdrop-filter: blur(var(--glass-blur-strong)); + border: 1px solid var(--glass-border); +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; +} + +.modal-title { + font-size: 18px; + font-weight: 600; + color: var(--text); +} + +.modal-close { + background: transparent; + border: none; + color: var(--text-dim); + cursor: pointer; + padding: 4px; + border-radius: var(--radius-sm); + transition: all var(--transition-fast); +} + +.modal-close:hover { + color: var(--text); background: var(--surface2); } -/* Detail modal grid */ +.modal-footer { + display: flex; + gap: 12px; + justify-content: flex-end; + margin-top: 24px; + padding-top: 20px; + border-top: 1px solid var(--border); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + TOASTS — Notification messages + ═══════════════════════════════════════════════════════════════════════════ */ + +.toast-container { + position: fixed; + bottom: 24px; + right: 24px; + z-index: var(--z-toast); + display: flex; + flex-direction: column; + gap: 12px; +} + +.toast { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + padding: 14px 20px; + box-shadow: var(--shadow-lg); + display: flex; + align-items: center; + gap: 12px; + animation: slideLeft 0.4s var(--ease-spring); + min-width: 280px; + max-width: 400px; +} + +.toast-glass { + background: var(--glass-bg-strong); + backdrop-filter: blur(var(--glass-blur)); + -webkit-backdrop-filter: blur(var(--glass-blur)); + border: 1px solid var(--glass-border); +} + +.toast-success { + border-left: 3px solid var(--success); +} + +.toast-error { + border-left: 3px solid var(--error); +} + +.toast-warning { + border-left: 3px solid var(--warning); +} + +.toast-info { + border-left: 3px solid var(--info); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + TABS — Navigation tabs + ═══════════════════════════════════════════════════════════════════════════ */ + +.tabs { + display: flex; + gap: 4px; + background: var(--surface2); + padding: 4px; + border-radius: var(--radius-lg); + border: 1px solid var(--border); +} + +.tab { + padding: 10px 18px; + border-radius: var(--radius-md); + font-size: 13px; + font-weight: 500; + color: var(--text-dim); + cursor: pointer; + transition: all var(--transition-fast); + border: none; + background: transparent; +} + +.tab:hover { + color: var(--text); +} + +.tab.active { + background: var(--surface); + color: var(--text); + box-shadow: var(--shadow-sm); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + TOOLTIPS + ═══════════════════════════════════════════════════════════════════════════ */ + +.tooltip { + position: relative; +} + +.tooltip::after { + content: attr(data-tooltip); + position: absolute; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%) translateY(4px); + background: var(--text); + color: var(--bg-primary); + padding: 6px 12px; + border-radius: var(--radius-sm); + font-size: 12px; + font-weight: 500; + white-space: nowrap; + opacity: 0; + visibility: hidden; + transition: all var(--transition-fast); + z-index: var(--z-tooltip); + box-shadow: var(--shadow-md); +} + +.tooltip:hover::after { + opacity: 1; + visibility: visible; + transform: translateX(-50%) translateY(0); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + DROPDOWNS + ═══════════════════════════════════════════════════════════════════════════ */ + +.dropdown { + position: relative; + display: inline-block; +} + +.dropdown-menu { + position: absolute; + top: calc(100% + 4px); + left: 0; + min-width: 180px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + padding: 6px; + z-index: var(--z-dropdown); + animation: slideDown 0.2s var(--ease-smooth); +} + +.dropdown-menu-glass { + background: var(--glass-bg-strong); + backdrop-filter: blur(var(--glass-blur)); + -webkit-backdrop-filter: blur(var(--glass-blur)); + border: 1px solid var(--glass-border); +} + +.dropdown-item { + padding: 10px 14px; + border-radius: var(--radius-md); + font-size: 13px; + color: var(--text-secondary); + cursor: pointer; + transition: all var(--transition-fast); + display: flex; + align-items: center; + gap: 10px; +} + +.dropdown-item:hover { + background: var(--surface2); + color: var(--text); +} + +.dropdown-divider { + height: 1px; + background: var(--border); + margin: 6px 0; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + DETAIL GRID — Key-value displays + ═══════════════════════════════════════════════════════════════════════════ */ + .detail-grid { display: flex; flex-direction: column; - gap: 0; + gap: 2px; } + .detail-row { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; - border-bottom: 1px solid var(--border); + border-bottom: 1px solid var(--border-subtle); + gap: 16px; } -.detail-row:last-child { border-bottom: none; } + +.detail-row:last-child { + border-bottom: none; +} + .detail-label { - font-size: 11px; - font-weight: 600; - color: var(--text-dim); - text-transform: uppercase; - letter-spacing: 0.5px; -} -.detail-value { font-size: 12px; + color: var(--text-dim); + flex-shrink: 0; +} + +.detail-value { + font-size: 13px; color: var(--text); text-align: right; + word-break: break-word; } -/* Channel icon */ -.channel-icon { - display: inline-flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; - border-radius: var(--radius-sm); - background: var(--surface2); - font-size: 10px; - font-weight: 700; - color: var(--text-dim); - flex-shrink: 0; -} - -/* Setup guide steps */ -.setup-steps { - margin: 0; - padding-left: 20px; - list-style: decimal; -} -.setup-steps li { - padding: 4px 0; - color: var(--text-dim); - line-height: 1.5; -} - -/* Config code block */ -.config-block { - background: var(--bg); - border: 1px solid var(--border); - border-radius: var(--radius-md); - padding: 12px; - font-size: 11px; - font-family: var(--font-mono); - white-space: pre-wrap; - color: var(--accent-light); - overflow-x: auto; - margin: 0; -} - -/* Security Dashboard */ -.security-hero { - display: flex; - align-items: center; - gap: 20px; - padding: 24px; - background: linear-gradient(135deg, var(--surface) 0%, var(--surface2) 100%); - border: 1px solid var(--border); - border-left: 4px solid var(--success); - border-radius: var(--radius-lg); - margin-bottom: 24px; -} - -.security-hero-shield { - font-size: 48px; - color: var(--success); - flex-shrink: 0; - text-shadow: 0 0 20px rgba(74,222,128,0.3); -} - -.security-hero-title { - font-size: 18px; - font-weight: 700; - margin-bottom: 6px; - letter-spacing: 0.5px; -} - -.security-hero-desc { - font-size: 12px; - color: var(--text-dim); - line-height: 1.6; - max-width: 600px; -} - -.security-section { - margin-bottom: 24px; -} - -.security-section-header { - display: flex; - align-items: center; - gap: 12px; - margin-bottom: 14px; - padding-bottom: 10px; - border-bottom: 1px solid var(--border); -} - -.security-shield { - display: flex; - align-items: center; - justify-content: center; - width: 36px; - height: 36px; - border-radius: var(--radius-sm); - font-size: 20px; - flex-shrink: 0; -} - -.shield-core { - background: rgba(74,222,128,0.1); - color: var(--success); -} - -.shield-config { - background: rgba(255,92,0,0.1); - color: var(--accent); -} - -.shield-monitor { - background: rgba(59,130,246,0.1); - color: var(--info); -} - -.security-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); - gap: 12px; -} - -.security-grid-sm { - grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); -} - -.security-card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 14px; - transition: border-color 0.2s; -} - -.security-card:hover { - border-color: var(--border-light); -} - -.security-card-name { - font-size: 13px; - font-weight: 600; -} - -.security-card-desc { - font-size: 11px; - color: var(--text-dim); - line-height: 1.6; - margin-bottom: 8px; -} - -.security-card-threat { - display: flex; - gap: 6px; - align-items: baseline; - color: var(--text-dim); - background: rgba(239,68,68,0.05); - padding: 6px 10px; - border-radius: var(--radius-sm); -} - -.security-card-value { - font-size: 10px; - color: var(--accent-light); - background: var(--bg); - padding: 6px 10px; - border-radius: var(--radius-sm); - font-family: var(--font-mono); -} - -.security-card-mini { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-md); - padding: 10px 12px; -} - -/* Security badges */ -.sec-badge { - display: inline-flex; - align-items: center; - padding: 2px 8px; - border-radius: 20px; - font-size: 9px; - font-weight: 700; - letter-spacing: 0.8px; - white-space: nowrap; -} - -.sec-badge-core { - background: rgba(74,222,128,0.12); - color: var(--success); -} - -.sec-badge-config { - background: rgba(255,92,0,0.12); - color: var(--accent); -} - -.sec-badge-monitor { - background: rgba(59,130,246,0.12); - color: var(--info); -} - -.sec-badge-warn { - background: rgba(239,68,68,0.15); - color: var(--error); -} - -/* Overview dashboard — premium stat cards */ -.stats-row-lg { gap: 16px; } -.stat-card-lg { - padding: 24px 28px; - min-width: 140px; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); - transition: transform 0.3s var(--ease-spring), box-shadow var(--transition-fast); - position: relative; - overflow: hidden; -} -.stat-card-lg::after { - content: ''; - position: absolute; - top: 0; left: 0; - width: 100%; height: 3px; - background: linear-gradient(90deg, var(--accent), var(--accent-light)); - opacity: 0; - transition: opacity var(--transition-fast); -} -.stat-card-lg:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); } -.stat-card-lg:hover::after { opacity: 1; } -.stat-card-lg .stat-value { font-size: 26px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; } -.stat-card-lg .stat-label { font-size: 11px; margin-top: 2px; font-weight: 500; } - -.overview-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 16px; - margin-top: 16px; -} +/* ═══════════════════════════════════════════════════════════════════════════ + HEALTH INDICATORS + ═══════════════════════════════════════════════════════════════════════════ */ .health-indicator { display: inline-flex; align-items: center; gap: 6px; - font-size: 12px; + padding: 4px 12px; + border-radius: var(--radius-full); + font-size: 11px; font-weight: 600; - padding: 5px 14px; - border-radius: 20px; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +.health-ok { + background: var(--success-subtle); + color: var(--success); +} + +.health-down { + background: var(--error-subtle); + color: var(--error); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + PROGRESS BAR + ═══════════════════════════════════════════════════════════════════════════ */ + +.progress-bar { + height: 6px; + background: var(--surface2); + border-radius: var(--radius-full); + overflow: hidden; +} + +.progress-bar-fill { + height: 100%; + background: var(--gradient-accent); + border-radius: var(--radius-full); + transition: width 0.4s var(--ease-smooth); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + QUICK ACTION CARDS + ═══════════════════════════════════════════════════════════════════════════ */ + +.quick-action-card { + display: flex; + align-items: center; + gap: 14px; + padding: 16px 20px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + cursor: pointer; transition: all var(--transition-fast); } -.health-indicator::before { - content: ''; - width: 8px; - height: 8px; - border-radius: 50%; - display: inline-block; -} -.health-indicator.health-ok { color: var(--success); background: var(--success-subtle); } -.health-indicator.health-ok::before { background: var(--success); animation: pulse-ring 2s infinite; } -.health-indicator.health-down { color: var(--error); background: var(--error-subtle); } -.health-indicator.health-down::before { background: var(--error); } -/* Focus mode toggle */ -.focus-toggle { - font-size: 11px; - letter-spacing: 0.3px; +.quick-action-card:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-md); + border-color: var(--border-strong); } -/* Logs page */ -.log-entry { padding: 4px 0; border-bottom: 1px solid var(--border); font-size: 11px; } -.log-entry:last-child { border-bottom: none; } -.log-level { display: inline-block; width: 44px; font-weight: 600; font-size: 10px; } -.log-level-info { color: var(--info); } -.log-level-warn { color: var(--warning, #f59e0b); } -.log-level-error { color: var(--error); } -.log-timestamp { color: var(--text-muted); font-size: 10px; margin-right: 8px; } - -/* Live log streaming indicator */ -.live-indicator { - display: inline-flex; +.quick-action-icon { + width: 40px; + height: 40px; + border-radius: var(--radius-md); + display: flex; align-items: center; - gap: 6px; - font-size: 11px; - font-weight: 600; - font-family: var(--font-mono); - padding: 3px 10px; - border-radius: 12px; - letter-spacing: 0.5px; - text-transform: uppercase; -} - -.live-dot { - width: 8px; - height: 8px; - border-radius: 50%; - display: inline-block; + justify-content: center; flex-shrink: 0; } -.live-indicator.live { - color: var(--success); - background: rgba(74,222,128,0.1); -} -.live-indicator.live .live-dot { - background: var(--success); - animation: live-pulse 1.5s ease-in-out infinite; - box-shadow: 0 0 6px rgba(74,222,128,0.4); -} - -.live-indicator.polling { - color: var(--warning, #f59e0b); - background: rgba(245,158,11,0.1); -} -.live-indicator.polling .live-dot { - background: var(--warning, #f59e0b); -} - -.live-indicator.paused { - color: var(--text-muted); - background: rgba(148,163,184,0.1); -} -.live-indicator.paused .live-dot { - background: var(--text-muted); -} - -.live-indicator.disconnected { - color: var(--error); - background: rgba(239,68,68,0.1); -} -.live-indicator.disconnected .live-dot { - background: var(--error); -} - -@keyframes live-pulse { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.4; transform: scale(0.85); } -} - -/* Trigger cards */ -.trigger-type { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } - -/* Session cards */ -.session-card { cursor: pointer; transition: border-color var(--transition-fast); } -.session-card:hover { border-color: var(--accent); } - -/* ── Toast Notifications ── */ -.toast-container { - position: fixed; - bottom: 20px; - right: 20px; - z-index: 9999; - display: flex; - flex-direction: column; - gap: 8px; - pointer-events: none; - max-width: 420px; -} - -.toast { - display: flex; - align-items: center; - gap: 10px; - padding: 12px 16px; - border-radius: var(--radius-md); - background: var(--surface); - border: 1px solid var(--border); - border-left: 4px solid var(--info); - backdrop-filter: blur(8px); - box-shadow: var(--shadow-md); - font-size: 12px; - font-family: var(--font-mono); +.quick-action-label { + font-size: 14px; + font-weight: 600; color: var(--text); - pointer-events: auto; - animation: toastIn 0.3s ease; - cursor: pointer; } -.toast-msg { flex: 1; line-height: 1.5; } -.toast-close { background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 16px; padding: 0 2px; flex-shrink: 0; } -.toast-close:hover { color: var(--text); } +.quick-action-desc { + font-size: 12px; + color: var(--text-dim); + margin-top: 2px; +} -.toast-success { border-left-color: var(--success); } -.toast-error { border-left-color: var(--error); } -.toast-warn { border-left-color: var(--warning, #f59e0b); } -.toast-info { border-left-color: var(--info); } +/* ═══════════════════════════════════════════════════════════════════════════ + EMPTY STATES + ═══════════════════════════════════════════════════════════════════════════ */ -.toast-dismiss { animation: toastOut 0.3s ease forwards; } +.empty-state { + text-align: center; + padding: 48px 24px; +} -@keyframes toastIn { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: translateX(0); } } -@keyframes toastOut { from { opacity: 1; transform: translateX(0); } to { opacity: 0; transform: translateX(40px); } } - -/* ── Confirm Modal ── */ -.confirm-overlay { - position: fixed; - inset: 0; - background: rgba(8,7,6,0.75); +.empty-state-icon { + width: 64px; + height: 64px; + margin: 0 auto 16px; + border-radius: var(--radius-lg); + background: var(--surface2); display: flex; align-items: center; justify-content: center; - z-index: 10000; - backdrop-filter: blur(4px); - animation: fadeIn 0.15s ease; + color: var(--text-dim); } -.confirm-modal { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 24px; - max-width: 400px; - width: 90%; - box-shadow: var(--shadow-glow); -} - -.confirm-title { - font-size: 15px; - font-weight: 700; +.empty-state h3 { + font-size: 16px; + color: var(--text-secondary); margin-bottom: 8px; } -.confirm-message { - font-size: 12px; - color: var(--text-dim); - line-height: 1.6; - margin-bottom: 20px; -} - -.confirm-actions { - display: flex; - gap: 8px; - justify-content: flex-end; -} - -/* ── Loading & Error States ── */ -.loading-state { - display: flex; - align-items: center; - justify-content: center; - gap: 12px; - padding: 60px; - color: var(--text-dim); +.empty-state p { font-size: 13px; - animation: fadeInLoading 0.01s ease-out 350ms both; + color: var(--text-dim); + max-width: 300px; + margin: 0 auto; } -@keyframes fadeInLoading { - from { opacity: 0; } - to { opacity: 1; } -} +/* ═══════════════════════════════════════════════════════════════════════════ + ERROR STATES + ═══════════════════════════════════════════════════════════════════════════ */ .error-state { - display: flex; - flex-direction: column; - align-items: center; - gap: 12px; - padding: 60px; text-align: center; -} - -.error-icon { - width: 40px; - height: 40px; - border-radius: 50%; - background: rgba(239,68,68,0.1); - color: var(--error); - display: flex; - align-items: center; - justify-content: center; - font-size: 20px; - font-weight: 700; -} - -.error-state p { - font-size: 13px; - color: var(--text-dim); - max-width: 360px; - line-height: 1.6; -} - -/* ── Onboarding Banner ── */ -.onboarding-banner { - background: linear-gradient(135deg, var(--surface) 0%, var(--surface2) 100%); - border: 1px solid var(--accent); - border-left: 4px solid var(--accent); + padding: 32px; + background: var(--error-subtle); + border: 1px solid rgba(239, 68, 68, 0.2); border-radius: var(--radius-lg); - padding: 20px 24px; +} + +.error-state h3 { + color: var(--error); + font-size: 16px; + margin-bottom: 8px; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + ONBOARDING BANNER + ═══════════════════════════════════════════════════════════════════════════ */ + +.onboarding-banner { + background: var(--gradient-accent-subtle); + border: 1px solid var(--accent-glass); + border-radius: var(--radius-xl); + padding: 24px; margin-bottom: 20px; } .onboarding-banner h3 { - font-size: 16px; - font-weight: 700; - color: var(--accent); + font-size: 18px; + color: var(--text); margin-bottom: 8px; } -.onboarding-banner ol { - padding-left: 20px; - margin: 8px 0 16px; -} - -.onboarding-banner li { - padding: 4px 0; +.onboarding-banner p { color: var(--text-dim); - line-height: 1.6; - font-size: 12px; -} - -.onboarding-banner code { - background: var(--bg); - padding: 2px 6px; - border-radius: 3px; - font-size: 11px; - color: var(--accent-light); -} - -/* ── Improved Empty States ── */ -.empty-state-action { margin-top: 16px; } -.empty-state h4 { font-size: 14px; color: var(--text); margin-bottom: 4px; } -.empty-state .hint { font-size: 11px; color: var(--text-muted); max-width: 360px; line-height: 1.6; } - -/* ── Connection Reconnecting ── */ -.conn-reconnecting { - animation: pulse 1.5s infinite; - color: var(--warning, #f59e0b); - font-size: 11px; -} - -/* ── Info Cards (explainer pattern) ── */ -.info-card { - background: linear-gradient(135deg, var(--surface) 0%, var(--surface2) 100%); - border: 1px solid var(--border); - border-left: 3px solid var(--accent); - border-radius: var(--radius-lg); - padding: 16px 20px; margin-bottom: 16px; } -.info-card h4 { - font-size: 13px; - font-weight: 700; - margin-bottom: 4px; -} +/* ═══════════════════════════════════════════════════════════════════════════ + SETUP CHECKLIST + ═══════════════════════════════════════════════════════════════════════════ */ -.info-card p { - font-size: 12px; - color: var(--text-dim); - line-height: 1.6; - margin: 0; -} - -.info-card ul { - margin: 6px 0 0; - padding-left: 18px; -} - -.info-card li { - font-size: 12px; - color: var(--text-dim); - line-height: 1.6; - padding: 1px 0; -} - -/* ── Unconfigured card (dashed border) ── */ -.card-unconfigured { - border-style: dashed; - opacity: 0.8; -} - -.card-unconfigured:hover { - opacity: 1; - border-color: var(--accent); -} - -/* ── Runtime badges (skill types) ── */ -.runtime-badge { - display: inline-flex; - align-items: center; - padding: 2px 6px; - border-radius: 3px; - font-size: 9px; - font-weight: 700; - letter-spacing: 0.5px; - text-transform: uppercase; - font-family: var(--font-mono); -} - -.runtime-badge-py { background: rgba(59,130,246,0.12); color: var(--info); } -.runtime-badge-js { background: rgba(250,204,21,0.15); color: var(--warning); } -.runtime-badge-wasm { background: rgba(168,85,247,0.12); color: #a855f7; } -.runtime-badge-prompt { background: rgba(74,222,128,0.12); color: var(--success); } - -/* ── Category badges ── */ -.category-badge { - display: inline-flex; - align-items: center; - padding: 2px 8px; - border-radius: 20px; - font-size: 10px; - font-weight: 600; - letter-spacing: 0.3px; - background: rgba(148,163,184,0.1); - color: var(--text-dim); -} - -/* ── Tier badges ── */ -.tier-badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 20px; font-size: 9px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; } -.tier-frontier { background: rgba(168,85,247,0.12); color: #a855f7; } -.tier-smart { background: rgba(59,130,246,0.12); color: var(--info); } -.tier-balanced { background: rgba(74,222,128,0.12); color: var(--success); } -.tier-fast { background: rgba(250,204,21,0.15); color: var(--warning); } - -/* ── Auth status badges ── */ -.auth-configured { background: rgba(74,222,128,0.12); color: var(--success); } -.auth-not-set { background: rgba(250,204,21,0.15); color: var(--warning); } -.auth-no-key { background: rgba(148,163,184,0.12); color: var(--text-dim); } - -/* ── Provider cards ── */ -.provider-card { - transition: border-color 0.2s, box-shadow 0.2s; -} -.provider-card.configured { border-left: 3px solid var(--success); } -.provider-card.not-configured { border-left: 3px solid var(--warning); } -.provider-card.no-key { border-left: 3px solid var(--text-muted); } - -/* ── Filter pills ── */ -.filter-pills { - display: flex; - gap: 6px; - flex-wrap: wrap; - margin-bottom: 16px; -} - -.filter-pill { - padding: 4px 12px; - border-radius: 20px; - font-size: 11px; - font-weight: 600; - cursor: pointer; - border: 1px solid var(--border); - background: transparent; - color: var(--text-dim); - transition: all 0.15s; - font-family: var(--font-mono); -} - -.filter-pill:hover { border-color: var(--accent); color: var(--text); } -.filter-pill.active { background: var(--accent); color: var(--bg-primary); border-color: var(--accent); } - -/* ── Difficulty badges ── */ -.difficulty-badge { - display: inline-flex; - align-items: center; - gap: 4px; - font-size: 10px; - color: var(--text-dim); -} - -.difficulty-easy { color: var(--success); } -.difficulty-medium { color: var(--warning); } -.difficulty-hard { color: var(--error); } - -/* ── Provider key input ── */ -.key-input-group { - display: flex; - gap: 6px; - margin-top: 8px; -} - -.key-input-group input { - flex: 1; - padding: 6px 10px; - background: var(--bg); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - font-family: var(--font-mono); - font-size: 11px; - color: var(--text); -} - -.key-input-group input:focus { - outline: none; - border-color: var(--accent); -} - -/* ── Cost Dashboard Charts ── */ - -.cost-charts-row { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; -} - -@media (max-width: 768px) { - .cost-charts-row { - grid-template-columns: 1fr; - } -} - -.cost-chart-panel { - min-height: 200px; -} - -/* Donut chart */ -.donut-chart-wrap { - display: flex; - align-items: center; - gap: 20px; - padding: 12px 0; - flex-wrap: wrap; -} - -.donut-chart { - flex-shrink: 0; -} - -.donut-segment { - transition: opacity 0.2s; - cursor: default; -} - -.donut-segment:hover { - opacity: 0.75; -} - -/* Donut legend */ -.donut-legend { - display: flex; - flex-direction: column; - gap: 6px; - min-width: 140px; -} - -.donut-legend-item { - display: flex; - align-items: center; - gap: 6px; - font-size: 11px; - font-family: var(--font-mono); -} - -.donut-legend-swatch { - width: 10px; - height: 10px; - border-radius: 2px; - flex-shrink: 0; -} - -.donut-legend-label { - flex: 1; - color: var(--text); - font-weight: 600; -} - -.donut-legend-pct { - color: var(--text-dim); - font-size: 10px; - min-width: 28px; - text-align: right; -} - -.donut-legend-cost { - font-size: 10px; - min-width: 48px; - text-align: right; -} - -/* Bar chart */ -.bar-chart { - padding: 12px 0; - overflow-x: auto; -} - -.bar-chart svg { - display: block; - margin: 0 auto; -} - -.cost-bar { - transition: opacity 0.2s; - cursor: default; -} - -.cost-bar:hover { - opacity: 1 !important; - filter: brightness(1.15); -} - -/* ── Browser Viewer ── */ -.browser-viewer { - background: var(--surface); - border: 1px solid var(--border); - border-radius: 12px; - max-width: 900px; - width: 90vw; - max-height: 85vh; - overflow: auto; - box-shadow: 0 20px 60px rgba(0,0,0,0.5); -} - -.browser-viewer-header { - display: flex; - align-items: center; - gap: 8px; - padding: 12px 16px; - border-bottom: 1px solid var(--border); - background: var(--surface-alt, var(--surface)); - border-radius: 12px 12px 0 0; -} - -.browser-url-bar { - flex: 1; - display: flex; - align-items: center; - gap: 6px; - background: var(--bg); - padding: 6px 12px; - border-radius: 6px; - font-family: var(--font-mono); - font-size: 13px; - min-width: 0; -} - -.browser-dot { - width: 10px; - height: 10px; - border-radius: 50%; - flex-shrink: 0; -} - -.browser-dot.red { background: #ff5f57; } -.browser-dot.yellow { background: #febc2e; } -.browser-dot.green { background: #28c840; } - -.browser-url { - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - color: var(--text-dim); - min-width: 0; -} - -.browser-viewer-body { - padding: 16px; -} - -.browser-screenshot { - margin-bottom: 12px; - background: var(--bg); - border-radius: 6px; - padding: 4px; - border: 1px solid var(--border); -} - -.browser-screenshot img { - max-width: 100%; - border-radius: 4px; - display: block; -} - -.browser-info { - padding: 8px 0; -} - -/* ── Setup Wizard ── */ - -.wizard-progress { - display: flex; - align-items: center; - justify-content: center; - gap: 0; - margin-bottom: 32px; - padding: 20px 0 16px; - position: relative; -} - -.wizard-progress-step { - display: flex; - flex-direction: column; - align-items: center; - gap: 6px; - cursor: pointer; - position: relative; - z-index: 2; - flex: 1; - max-width: 120px; - transition: opacity 0.2s; -} - -.wizard-progress-step:hover { opacity: 0.8; } - -.wizard-progress-circle { - width: 32px; - height: 32px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 12px; - font-weight: 700; - font-family: var(--font-mono); - border: 2px solid var(--border); - background: var(--surface); - color: var(--text-dim); - transition: all 0.3s ease; -} - -.wizard-progress-step.wiz-active .wizard-progress-circle { - border-color: var(--accent); - background: var(--accent); - color: var(--bg-primary); - box-shadow: 0 0 0 4px var(--accent-glow); -} - -.wizard-progress-step.wiz-done .wizard-progress-circle { - border-color: var(--success); - background: var(--success); - color: #000; -} - -.wizard-progress-label { - font-size: 10px; - font-weight: 600; - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.5px; - transition: color 0.2s; -} - -.wizard-progress-step.wiz-active .wizard-progress-label { - color: var(--accent); -} - -.wizard-progress-step.wiz-done .wizard-progress-label { - color: var(--success); -} - -.wizard-progress-line { - position: absolute; - top: 36px; - left: 10%; - right: 10%; - height: 2px; - background: var(--border); - z-index: 1; -} - -.wizard-progress-line-fill { - height: 100%; - background: var(--success); - transition: width 0.4s ease; - border-radius: 1px; -} - -.wizard-step { - animation: fadeIn 0.3s ease; -} - -.wizard-card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 24px; - margin-bottom: 16px; -} - -.wizard-nav { - display: flex; - justify-content: space-between; - align-items: center; - padding: 16px 0; - border-top: 1px solid var(--border); - margin-top: 8px; -} - -/* Wizard provider selection card */ -.wizard-provider-card { - transition: border-color 0.2s, box-shadow 0.2s, background 0.2s; -} - -.wizard-provider-selected { - border-color: var(--accent) !important; - box-shadow: 0 0 0 1px var(--accent-glow); - background: rgba(255,92,0,0.04); -} - -/* Wizard template selection card */ -.wizard-template-card { - transition: border-color 0.2s, box-shadow 0.2s, background 0.2s; -} - -.wizard-template-selected { - border-color: var(--accent) !important; - box-shadow: 0 0 0 1px var(--accent-glow); - background: rgba(255,92,0,0.04); -} - -/* Responsive wizard */ -@media (max-width: 600px) { - .wizard-progress-label { display: none; } - .wizard-progress-step { max-width: 48px; } - .wizard-progress-circle { width: 28px; height: 28px; font-size: 11px; } - .wizard-progress-line { top: 34px; } - .wizard-card { padding: 16px; } -} - -/* ── Page Transition Animation ── */ -@keyframes slideIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } -.page-body { animation: slideIn 0.2s ease; } - -/* ── Skeleton Loading Placeholder ── */ -@keyframes shimmer { 0% { background-position: -200px 0; } 100% { background-position: calc(200px + 100%) 0; } } -.skeleton { - background: linear-gradient(90deg, var(--surface2) 25%, var(--surface) 37%, var(--surface2) 63%); - background-size: 200px 100%; - animation: shimmer 1.5s ease-in-out infinite; - border-radius: var(--radius-sm); -} - -/* ── File Attachment Drop Zone ── */ -.drop-zone { - border: 2px dashed var(--border); - border-radius: var(--radius-lg); - padding: 24px; - text-align: center; - transition: all 0.2s; -} -.drop-zone.active { - border-color: var(--accent); - background: var(--accent-glow); -} -.drop-zone-text { font-size: 12px; color: var(--text-dim); } -.file-preview { display: flex; gap: 8px; flex-wrap: wrap; padding: 8px 0; } -.file-thumb { - position: relative; - width: 64px; - height: 64px; - border-radius: var(--radius-sm); - overflow: hidden; - border: 1px solid var(--border); -} -.file-thumb img { width: 100%; height: 100%; object-fit: cover; } -.file-thumb .remove { - position: absolute; - top: 2px; - right: 2px; - width: 18px; - height: 18px; - border-radius: 50%; - background: var(--error); - color: #fff; - border: none; - cursor: pointer; - font-size: 10px; - display: flex; - align-items: center; - justify-content: center; -} -.file-name { - font-size: 11px; - color: var(--text-dim); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - max-width: 60px; - text-align: center; -} - -/* ── Approval Badge & Page Styles ── */ -.approval-card { border-left: 3px solid var(--warning); } -.approval-card.approved { border-left-color: var(--success); } -.approval-card.rejected { border-left-color: var(--error); } -.approval-card.expired { border-left-color: var(--text-muted); opacity: 0.7; } -.approval-timer { - font-size: 11px; - color: var(--warning); - font-weight: 600; - font-variant-numeric: tabular-nums; -} -.approval-actions { display: flex; gap: 8px; margin-top: 12px; } - -/* ── Agent Identity Styles ── */ -.agent-emoji { font-size: 20px; line-height: 1; flex-shrink: 0; } -.agent-avatar { - width: 32px; - height: 32px; - border-radius: 50%; - object-fit: cover; - border: 1px solid var(--border); - flex-shrink: 0; -} -.agent-identity { display: flex; align-items: center; gap: 8px; } -.agent-color-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } - -/* ── Message Grouping Styles ── */ -.message.grouped { margin-top: -14px; } -.message.grouped .message-avatar { visibility: hidden; } -.message.grouped .message-meta { display: none; } -.message.grouped .message-time { display: none; } - -/* ── Inline Image Preview in Messages ── */ -.message-image { - max-width: 300px; - max-height: 200px; - border-radius: var(--radius-md); - border: 1px solid var(--border); - cursor: pointer; - transition: transform 0.15s; - margin: 8px 0; -} -.message-image:hover { transform: scale(1.02); } -.message-file-link { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 6px 12px; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-sm); - font-size: 11px; - color: var(--text-dim); - text-decoration: none; - transition: border-color 0.15s; - margin: 4px 0; -} -.message-file-link:hover { border-color: var(--accent); color: var(--text); } - -/* ── Setup Checklist Progress Bar ── */ -.progress-bar { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; } -.progress-bar-fill { height: 100%; border-radius: 3px; background: var(--accent); transition: width 0.3s ease; } - -/* ── Tool Badge ── */ -.tool-badge { font-size: 10px; padding: 2px 6px; border-radius: 3px; background: var(--surface2); color: var(--text-dim); display: inline-block; margin: 1px; } - -/* ── Try-It Mini Chat ── */ -.tryit-messages { max-height: 200px; overflow-y: auto; margin: 12px 0; } -.tryit-msg { padding: 6px 10px; border-radius: 6px; margin: 4px 0; font-size: 12px; line-height: 1.5; word-break: break-word; } -.tryit-msg-user { background: var(--accent); color: var(--bg-primary); margin-left: 40px; } -.tryit-msg-agent { background: var(--surface2); margin-right: 40px; } - -/* ── Suggested Message Chips ── */ -.suggest-chip { display: inline-block; padding: 4px 10px; border: 1px solid var(--border); border-radius: 12px; font-size: 11px; cursor: pointer; transition: all 0.15s; background: transparent; color: var(--text-dim); font-family: var(--font-mono); } -.suggest-chip:hover { border-color: var(--accent); color: var(--accent); } - -/* ── Setup Checklist Card ── */ -.setup-checklist { margin-bottom: 20px; } -.setup-checklist-item { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 12px; } -.setup-checklist-item:last-child { border-bottom: none; } -.setup-checklist-icon { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; flex-shrink: 0; border: 2px solid var(--border); color: var(--text-dim); } -.setup-checklist-icon.done { background: var(--success); border-color: var(--success); color: #000; } - -/* ── Channel Setup Steps Indicator ── */ -.channel-steps { display: flex; align-items: center; gap: 0; margin-bottom: 20px; } -.channel-step-item { display: flex; align-items: center; gap: 6px; flex: 1; } -.channel-step-num { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; border: 2px solid var(--border); color: var(--text-dim); flex-shrink: 0; transition: all 0.2s; } -.channel-step-num.active { border-color: var(--accent); background: var(--accent); color: var(--bg-primary); } -.channel-step-num.done { border-color: var(--success); background: var(--success); color: #000; } -.channel-step-label { font-size: 11px; color: var(--text-dim); } -.channel-step-label.active { color: var(--accent); font-weight: 600; } -.channel-step-label.done { color: var(--success); } -.channel-step-line { flex: 1; height: 2px; background: var(--border); margin: 0 8px; } -.channel-step-line.done { background: var(--success); } - -/* ── Chat Tip Bar ── */ -.tip-bar { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 4px 8px; font-size: 11px; color: var(--text-muted); transition: opacity 0.3s; } -.tip-bar-dismiss { background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 14px; padding: 0 4px; line-height: 1; } -.tip-bar-dismiss:hover { color: var(--text); } - -/* ── Wizard Category Filter ── */ -.wizard-category-pills { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 16px; } -.wizard-category-pill { padding: 4px 12px; border-radius: 20px; font-size: 11px; font-weight: 600; cursor: pointer; border: 1px solid var(--border); background: transparent; color: var(--text-dim); transition: all 0.15s; font-family: var(--font-mono); } -.wizard-category-pill:hover { border-color: var(--accent); color: var(--text); } -.wizard-category-pill.active { background: var(--accent); color: var(--bg-primary); border-color: var(--accent); } - -/* ── Capability Preview Panel ── */ -.capability-preview { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px; margin-top: 12px; } -.capability-preview-title { font-size: 11px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; } - -/* ── Ready Panel (Channel step 3) ── */ -.ready-panel { text-align: center; padding: 24px 16px; } -.ready-panel-icon { font-size: 48px; color: var(--success); margin-bottom: 8px; } -.ready-panel-title { font-size: 15px; font-weight: 700; margin-bottom: 6px; } -.ready-panel-desc { font-size: 12px; color: var(--text-dim); line-height: 1.6; } - -/* ── Wizard Step Indicator ── */ -.wizard-steps { - display: flex; - align-items: center; - justify-content: center; - gap: 8px; +.setup-checklist { margin-bottom: 20px; +} + +.setup-checklist-item { + display: flex; + align-items: center; + gap: 10px; padding: 8px 0; -} -.wizard-dot { - width: 28px; - height: 28px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 12px; - font-weight: 700; - border: 2px solid var(--border); - color: var(--text-dim); - background: var(--surface); - transition: all 0.2s ease; -} -.wizard-dot.active { - border-color: var(--accent); - color: var(--accent); - background: var(--accent-subtle); - box-shadow: 0 0 0 3px var(--accent-subtle); -} -.wizard-dot.done { - border-color: var(--success); - color: var(--success); - background: var(--success-subtle, rgba(34, 197, 94, 0.1)); -} -.wizard-dot + .wizard-dot::before { - content: ''; - display: block; - width: 16px; - height: 2px; - background: var(--border); - position: relative; - left: -12px; -} - -/* ── Emoji Grid ── */ -.emoji-grid { - display: grid; - grid-template-columns: repeat(8, 1fr); - gap: 4px; -} -.emoji-grid-item { - width: 36px; - height: 36px; - border: 1px solid var(--border); - border-radius: var(--radius-sm); - background: var(--surface); - cursor: pointer; - font-size: 18px; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.15s ease; -} -.emoji-grid-item:hover { - border-color: var(--accent); - background: var(--surface2); - transform: scale(1.1); -} -.emoji-grid-item.active { - border-color: var(--accent); - background: var(--accent-subtle); - box-shadow: 0 0 0 2px var(--accent-subtle); -} - -/* ── Personality Pills ── */ -.personality-pill { - padding: 8px 16px; - border: 1px solid var(--border); - border-radius: 20px; - background: var(--surface); - color: var(--text-dim); font-size: 13px; - font-weight: 500; - cursor: pointer; - transition: all 0.2s ease; -} -.personality-pill:hover { - border-color: var(--accent); - color: var(--text); - transform: translateY(-1px); -} -.personality-pill.active { - border-color: var(--accent); - background: var(--accent); - color: var(--bg-primary); - box-shadow: 0 0 12px var(--accent-subtle); + color: var(--text-secondary); } -/* ── File List ── */ -.file-list-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px 14px; - border: 1px solid var(--border); - border-radius: var(--radius-sm); - margin-bottom: 6px; - cursor: pointer; - transition: all 0.15s ease; - background: var(--surface); -} -.file-list-item:hover { - border-color: var(--accent); - background: var(--surface2); -} - -/* ── File Editor ── */ -.file-editor { - font-family: var(--font-mono); - font-size: 13px; - line-height: 1.5; - padding: 12px; - border: 1px solid var(--border); - border-radius: var(--radius-md); - background: var(--bg-primary); - color: var(--text); - tab-size: 2; - white-space: pre; - overflow-wrap: normal; - overflow-x: auto; -} -.file-editor:focus { - outline: none; - border-color: var(--accent); - box-shadow: 0 0 0 2px var(--accent-subtle); -} - -/* ── Stat Value Semantic Colors ── */ -.stat-value-success { color: var(--success) !important; } -.stat-value-warning { color: var(--warning) !important; } -.stat-value-error { color: var(--error) !important; } -.stat-value-accent { color: var(--accent) !important; } - -/* ── Additional Skeleton Variants ── */ -.skeleton-stat { height: 88px; border-radius: var(--radius-lg); background: linear-gradient(90deg, var(--surface) 25%, var(--surface2) 50%, var(--surface) 75%); background-size: 200% 100%; animation: shimmer 1.5s ease-in-out infinite; } -.skeleton-table { height: 200px; border-radius: var(--radius-lg); width: 100%; background: linear-gradient(90deg, var(--surface) 25%, var(--surface2) 50%, var(--surface) 75%); background-size: 200% 100%; animation: shimmer 1.5s ease-in-out infinite; } -.skeleton-row { display: flex; gap: 16px; margin-bottom: 12px; } - -/* ── Enhanced Empty State ── */ -.empty-state svg, .empty-state-icon svg { opacity: 0.3; } -.empty-state-cta { margin-top: 16px; } - -/* ── Nav Section Collapsible ── */ -.nav-section-title { - cursor: pointer; - user-select: none; - display: flex; - align-items: center; - justify-content: space-between; -} -.nav-section-chevron { - font-size: 8px; - transition: transform var(--transition-fast); - color: var(--text-muted); -} - -/* ── Settings Secondary Tabs ── */ -.tab-secondary { font-size: 11px; opacity: 0.7; } -.tab-secondary:hover, .tab-secondary.active { opacity: 1; } -.tabs-separator { flex: 1; min-width: 16px; } - -/* ── Quick Action Cards ── */ -.quick-action-card { - display: flex; - align-items: center; - gap: 12px; - padding: 14px 16px; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - cursor: pointer; - transition: all var(--transition-fast); - box-shadow: var(--shadow-xs), var(--shadow-inset); -} -.quick-action-card:hover { - border-color: var(--border-strong); - transform: translateY(-2px); - box-shadow: var(--shadow-md), var(--shadow-inset); -} -.quick-action-card .quick-action-icon { - width: 36px; height: 36px; - border-radius: var(--radius-md); - display: flex; align-items: center; justify-content: center; - flex-shrink: 0; -} -.quick-action-card .quick-action-label { font-size: 13px; font-weight: 600; } -.quick-action-card .quick-action-desc { font-size: 11px; color: var(--text-dim); } - -/* ── Hand Setup Wizard ── */ -.hand-wizard { - max-width: 680px; - width: 95vw; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-xl); - box-shadow: var(--shadow-lg); - max-height: 90vh; - overflow-y: auto; - padding: 0; -} -.hand-wizard-header { - display: flex; - align-items: flex-start; - gap: 12px; - padding: 20px 24px 12px; - border-bottom: 1px solid var(--border); - position: relative; -} -.hand-wizard-header .wizard-icon { font-size: 2rem; line-height: 1; } -.hand-wizard-header .wizard-title { font-size: 16px; font-weight: 700; margin: 0; } -.hand-wizard-header .wizard-subtitle { font-size: 12px; color: var(--text-dim); margin-top: 2px; } -.hand-wizard-header .wizard-close { - position: absolute; - top: 16px; - right: 16px; - background: none; - border: none; - color: var(--text-dim); - font-size: 20px; - cursor: pointer; - padding: 4px; - line-height: 1; -} -.hand-wizard-header .wizard-close:hover { color: var(--text); } -.hand-wizard-body { padding: 20px 24px; } - -/* Step Progress Indicator */ -.hand-steps { - display: flex; - align-items: center; - justify-content: center; - gap: 0; - padding: 16px 24px 0; -} -.hand-step-item { - display: flex; - align-items: center; - gap: 8px; -} -.hand-step-num { - width: 28px; - height: 28px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 12px; - font-weight: 700; - border: 2px solid var(--border); - color: var(--text-dim); - background: var(--bg-primary); - transition: all 0.2s; - flex-shrink: 0; -} -.hand-step-item.active .hand-step-num { - border-color: var(--accent); - background: var(--accent); - color: var(--bg-primary); -} -.hand-step-item.done .hand-step-num { - border-color: var(--success); - background: var(--success); - color: #000; -} -.hand-step-label { - font-size: 12px; - font-weight: 600; - color: var(--text-dim); - white-space: nowrap; -} -.hand-step-item.active .hand-step-label { color: var(--text); } -.hand-step-item.done .hand-step-label { color: var(--success); } -.hand-step-line { - width: 40px; - height: 2px; - background: var(--border); - margin: 0 8px; - flex-shrink: 0; -} -.hand-step-line.done { background: var(--success); } - -/* Dependency Cards */ -.dep-card { - background: var(--bg-primary); - border: 1px solid var(--border); - border-left: 3px solid var(--warning); - border-radius: var(--radius-md); - padding: 14px 16px; - margin-bottom: 10px; - transition: border-color 0.2s; -} -.dep-card.dep-met { border-left-color: var(--success); } -.dep-card.dep-missing { border-left-color: var(--warning); } -.dep-card-header { - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 6px; -} -.dep-status-icon { - width: 24px; - height: 24px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 12px; - font-weight: 700; - flex-shrink: 0; -} -.dep-status-icon.met { background: rgba(52, 211, 153, 0.15); color: var(--success); } -.dep-status-icon.missing { background: rgba(251, 191, 36, 0.15); color: var(--warning); } -.dep-status-icon.checking { animation: depPulse 1.2s ease-in-out infinite; } -.dep-card-title { font-size: 13px; font-weight: 600; } -.dep-card-desc { font-size: 11px; color: var(--text-dim); margin-bottom: 8px; } -.dep-time-badge { - display: inline-block; - padding: 2px 8px; - font-size: 10px; - font-weight: 600; - background: var(--surface2); - border-radius: 10px; - color: var(--text-dim); - margin-left: 8px; -} -.dep-met-msg { - display: flex; - align-items: center; - gap: 6px; - font-size: 12px; - color: var(--success); - padding: 4px 0; -} - -/* Platform Install Selector */ -.install-block { - background: var(--bg-primary); - border: 1px solid var(--border); - border-radius: var(--radius-md); - overflow: hidden; - margin-top: 8px; -} -.install-platform-pills { - display: flex; - gap: 0; - border-bottom: 1px solid var(--border); - padding: 0; -} -.install-platform-pill { - padding: 6px 14px; - font-size: 11px; - font-weight: 600; - cursor: pointer; - color: var(--text-dim); - border: none; - background: none; - transition: all 0.15s; - border-bottom: 2px solid transparent; -} -.install-platform-pill:hover { color: var(--text); background: var(--surface2); } -.install-platform-pill.active { - color: var(--accent); - border-bottom-color: var(--accent); - background: var(--surface); -} -.install-cmd { - display: flex; - align-items: center; - justify-content: space-between; - padding: 10px 12px; - font-family: var(--font-mono); - font-size: 12px; - color: var(--text); - gap: 8px; -} -.install-cmd code { - flex: 1; - overflow-x: auto; - white-space: nowrap; -} -.copy-btn { - padding: 4px 10px; - font-size: 11px; - font-weight: 600; - border: 1px solid var(--border); - border-radius: var(--radius-sm); - background: var(--surface); - color: var(--text-dim); - cursor: pointer; - white-space: nowrap; - transition: all 0.15s; -} -.copy-btn:hover { background: var(--surface2); color: var(--text); } -.copy-btn.copied { background: var(--success); color: #000; border-color: var(--success); } - -/* API Key Steps */ -.api-key-steps { - list-style: none; - counter-reset: api-step; - padding: 0; - margin: 8px 0 0; -} -.api-key-steps li { - counter-increment: api-step; - display: flex; - align-items: flex-start; - gap: 10px; - font-size: 12px; - color: var(--text-dim); - padding: 5px 0; - line-height: 1.5; -} -.api-key-steps li::before { - content: counter(api-step); +.setup-checklist-icon { width: 20px; height: 20px; border-radius: 50%; + border: 2px solid var(--border-strong); display: flex; align-items: center; justify-content: center; - font-size: 10px; - font-weight: 700; - background: var(--surface2); - color: var(--text-dim); + font-size: 11px; flex-shrink: 0; - margin-top: 1px; + transition: all var(--transition-fast); } -/* Dependency Progress Bar */ -.dep-progress { - margin-top: 16px; - padding-top: 12px; - border-top: 1px solid var(--border); -} -.dep-progress-label { - font-size: 12px; - font-weight: 600; - margin-bottom: 6px; - display: flex; - justify-content: space-between; -} -.dep-progress-bar { - height: 6px; - background: var(--surface2); - border-radius: 3px; - overflow: hidden; -} -.dep-progress-fill { - height: 100%; +.setup-checklist-icon.done { background: var(--success); - border-radius: 3px; - transition: width 0.4s ease; + border-color: var(--success); + color: #FFFFFF; } -/* Auto-Install Progress */ -.install-progress-panel { - background: var(--surface1); +/* ═══════════════════════════════════════════════════════════════════════════ + UTILITY CLASSES + ═══════════════════════════════════════════════════════════════════════════ */ + +/* Text colors */ +.text-dim { color: var(--text-dim); } +.text-muted { color: var(--text-muted); } +.text-accent { color: var(--accent); } +.text-success { color: var(--success); } +.text-error { color: var(--error); } +.text-warning { color: var(--warning); } +.text-info { color: var(--info); } + +/* Font sizes */ +.text-xs { font-size: 11px; } +.text-sm { font-size: 12px; } +.text-base { font-size: 14px; } +.text-lg { font-size: 16px; } +.text-xl { font-size: 18px; } +.text-2xl { font-size: 22px; } + +/* Font weights */ +.font-normal { font-weight: 400; } +.font-medium { font-weight: 500; } +.font-semibold { font-weight: 600; } +.font-bold { font-weight: 700; } +.font-mono { font-family: var(--font-mono); } + +/* Flexbox */ +.flex { display: flex; } +.flex-col { flex-direction: column; } +.items-center { align-items: center; } +.justify-center { justify-content: center; } +.justify-between { justify-content: space-between; } +.justify-end { justify-content: flex-end; } +.flex-wrap { flex-wrap: wrap; } +.flex-1 { flex: 1; } +.flex-grow { flex-grow: 1; } +.flex-shrink-0 { flex-shrink: 0; } + +/* Gap */ +.gap-1 { gap: 4px; } +.gap-2 { gap: 8px; } +.gap-3 { gap: 12px; } +.gap-4 { gap: 16px; } +.gap-6 { gap: 24px; } +.gap-8 { gap: 32px; } + +/* Margin */ +.m-0 { margin: 0; } +.mt-1 { margin-top: 4px; } +.mt-2 { margin-top: 8px; } +.mt-3 { margin-top: 12px; } +.mt-4 { margin-top: 16px; } +.mb-1 { margin-bottom: 4px; } +.mb-2 { margin-bottom: 8px; } +.mb-3 { margin-bottom: 12px; } +.mb-4 { margin-bottom: 16px; } +.ml-1 { margin-left: 4px; } +.ml-2 { margin-left: 8px; } +.mr-1 { margin-right: 4px; } +.mr-2 { margin-right: 8px; } +.mx-auto { margin-left: auto; margin-right: auto; } + +/* Padding */ +.p-0 { padding: 0; } +.p-1 { padding: 4px; } +.p-2 { padding: 8px; } +.p-3 { padding: 12px; } +.p-4 { padding: 16px; } +.p-6 { padding: 24px; } +.px-2 { padding-left: 8px; padding-right: 8px; } +.px-3 { padding-left: 12px; padding-right: 12px; } +.px-4 { padding-left: 16px; padding-right: 16px; } +.py-1 { padding-top: 4px; padding-bottom: 4px; } +.py-2 { padding-top: 8px; padding-bottom: 8px; } +.py-3 { padding-top: 12px; padding-bottom: 12px; } +.py-4 { padding-top: 16px; padding-bottom: 16px; } + +/* Width */ +.w-full { width: 100%; } +.max-w-sm { max-width: 24rem; } +.max-w-md { max-width: 28rem; } +.max-w-lg { max-width: 32rem; } +.max-w-xl { max-width: 36rem; } + +/* Border radius */ +.rounded { border-radius: var(--radius-md); } +.rounded-lg { border-radius: var(--radius-lg); } +.rounded-xl { border-radius: var(--radius-xl); } +.rounded-full { border-radius: var(--radius-full); } + +/* Display */ +.hidden { display: none; } +.block { display: block; } +.inline { display: inline; } +.inline-flex { display: inline-flex; } + +/* Position */ +.relative { position: relative; } +.absolute { position: absolute; } +.fixed { position: fixed; } + +/* Overflow */ +.overflow-hidden { overflow: hidden; } +.overflow-auto { overflow: auto; } +.overflow-scroll { overflow: scroll; } + +/* Border */ +.border { border: 1px solid var(--border); } +.border-0 { border: none; } +.border-t { border-top: 1px solid var(--border); } +.border-b { border-bottom: 1px solid var(--border); } +.border-l { border-left: 1px solid var(--border); } +.border-r { border-right: 1px solid var(--border); } + +/* ═══════════════════════════════════════════════════════════════════════════ + MESSAGE BUBBLES — Chat messages + ═══════════════════════════════════════════════════════════════════════════ */ + +.message-bubble { + padding: 12px 16px; + border-radius: var(--radius-lg); + background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius); - padding: 12px; - margin-bottom: 12px; + font-size: 14px; + line-height: 1.6; + word-wrap: break-word; + overflow-wrap: break-word; } -.install-progress-header { - margin-bottom: 8px; + +.message.user .message-bubble { + background: var(--accent-subtle); + border-color: rgba(255, 92, 0, 0.15); } -.install-results-list { + +.message.agent .message-bubble { + background: var(--surface); +} + +.message-time { + font-size: 10px; + color: var(--text-muted); + font-family: var(--font-mono); + margin-top: 4px; +} + +.message-meta { + font-size: 10px; + color: var(--text-muted); + padding: 2px 8px; + background: var(--surface2); + border-radius: var(--radius-full); +} + +/* Typing indicator dots */ +.typing-dots { display: flex; - flex-direction: column; gap: 4px; + padding: 4px 0; } -.install-result-row { + +.typing-dots span { + width: 6px; + height: 6px; + background: var(--text-dim); + border-radius: 50%; + animation: typing-bounce 1.4s ease-in-out infinite; +} + +.typing-dots span:nth-child(2) { animation-delay: 0.2s; } +.typing-dots span:nth-child(3) { animation-delay: 0.4s; } + +@keyframes typing-bounce { + 0%, 60%, 100% { transform: translateY(0); } + 30% { transform: translateY(-4px); } +} + +/* ═══════════════════════════════════════════════════════════════════════════ + TOOL CARDS — Tool execution display + ═══════════════════════════════════════════════════════════════════════════ */ + +.tool-card { + margin: 8px 0; + background: var(--surface2); + border: 1px solid var(--border); + border-radius: var(--radius-md); + overflow: hidden; + font-size: 12px; + transition: all var(--transition-fast); +} + +.tool-card:hover { + border-color: var(--border-strong); +} + +.tool-card-error { + border-color: rgba(239, 68, 68, 0.3); + background: var(--error-subtle); +} + +.tool-card-header { display: flex; align-items: center; gap: 8px; - padding: 6px 8px; - border-radius: var(--radius-sm); - background: var(--bg-primary); -} -.install-result-row.dep-met { color: var(--green); } -.install-result-row.dep-missing { color: var(--red); } -.install-result-icon { - width: 16px; - text-align: center; - font-weight: bold; - flex-shrink: 0; + padding: 10px 14px; + cursor: pointer; + transition: background var(--transition-fast); } -/* Small spinner */ -.spinner-sm { +.tool-card-header:hover { + background: var(--surface3); +} + +.tool-card-name { + font-family: var(--font-mono); + font-weight: 600; + color: var(--text); + font-size: 12px; +} + +.tool-card-icon { + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; + color: var(--accent); +} + +.tool-icon-ok { + color: var(--success); + font-size: 12px; + font-weight: bold; +} + +.tool-icon-err { + color: var(--error); + font-size: 12px; + font-weight: bold; +} + +.tool-card-spinner { width: 14px; height: 14px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; - animation: spin 0.6s linear infinite; - flex-shrink: 0; -} -@keyframes spin { - to { transform: rotate(360deg); } + animation: spin 0.8s linear infinite; } -/* Launch Summary */ -.launch-summary { - background: var(--bg-primary); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 20px; - text-align: center; +.tool-expand-chevron { + font-size: 8px; + color: var(--text-muted); + transition: transform var(--transition-fast); } -.launch-summary-icon { font-size: 3rem; margin-bottom: 8px; } -.launch-summary-title { font-size: 16px; font-weight: 700; margin-bottom: 16px; } -.launch-summary-rows { - text-align: left; - margin: 0 auto; - max-width: 400px; -} -.launch-summary-row { - display: flex; - justify-content: space-between; - align-items: center; - padding: 6px 0; - font-size: 12px; - border-bottom: 1px solid var(--border); -} -.launch-summary-row:last-child { border-bottom: none; } -.launch-summary-row .row-label { color: var(--text-dim); } -.launch-summary-row .row-value { font-weight: 600; } -.launch-summary-row .row-check { color: var(--success); } -/* Wizard Navigation */ -.hand-wizard-nav { - display: flex; - justify-content: space-between; - align-items: center; - padding: 16px 24px 20px; +.tool-card-body { + padding: 12px 14px; border-top: 1px solid var(--border); - gap: 12px; -} -.hand-wizard-nav .btn-launch { - padding: 10px 24px; - font-size: 14px; - font-weight: 700; + background: var(--surface); } -@keyframes depPulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.4; } -} - -/* ── Workflow Visual Builder ─────────────────────────── */ -.wf-builder-layout { - display: flex; - height: calc(100vh - 120px); - gap: 0; - border: 1px solid var(--border); - border-radius: 8px; - overflow: hidden; - background: var(--bg-secondary); -} -.wf-palette { - width: 200px; - min-width: 200px; - padding: 12px; - background: var(--card-bg); - border-right: 1px solid var(--border); - overflow-y: auto; - flex-shrink: 0; -} -.wf-palette-title { - font-size: 13px; - font-weight: 700; - margin-bottom: 4px; - color: var(--text); -} -.wf-palette-node { - display: flex; - align-items: center; - gap: 8px; - padding: 6px 8px; - margin-bottom: 4px; - border-radius: 6px; - background: var(--bg-secondary); - cursor: grab; - transition: background 0.15s; - user-select: none; -} -.wf-palette-node:hover { background: var(--hover); } -.wf-palette-node:active { cursor: grabbing; } -.wf-palette-icon { - width: 22px; - height: 22px; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-size: 11px; - font-weight: 700; - flex-shrink: 0; -} -.wf-canvas-wrap { - flex: 1; - position: relative; - overflow: hidden; -} -.wf-canvas { - width: 100%; - height: 100%; - background: var(--bg-secondary); - cursor: default; -} -.wf-canvas .wf-node { cursor: grab; } -.wf-canvas .wf-node:active { cursor: grabbing; } -.wf-port { - cursor: crosshair; - transition: r 0.15s, fill 0.15s; -} -.wf-port:hover { - r: 8; - fill: var(--accent); -} -.wf-zoom-controls { - position: absolute; - top: 8px; - right: 8px; - display: flex; - align-items: center; - gap: 2px; - background: var(--card-bg); - border: 1px solid var(--border); - border-radius: 6px; - padding: 2px 4px; - z-index: 10; -} -.wf-canvas-hint { - position: absolute; - bottom: 16px; - left: 50%; - transform: translateX(-50%); - background: var(--card-bg); - border: 1px solid var(--border); - border-radius: 8px; - padding: 8px 16px; - font-size: 12px; +.tool-section-label { + font-size: 10px; + font-weight: 600; color: var(--text-dim); - pointer-events: none; - z-index: 5; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 4px; } -.wf-editor-panel { - width: 240px; - min-width: 240px; - padding: 12px; - background: var(--card-bg); - border-left: 1px solid var(--border); - overflow-y: auto; - flex-shrink: 0; -} -.wf-editor-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 12px; - padding-bottom: 8px; - border-bottom: 1px solid var(--border); -} -.wf-conn-hint { - position: fixed; - bottom: 16px; - left: 50%; - transform: translateX(-50%); - display: flex; - align-items: center; - gap: 8px; - background: var(--card-bg); - border: 1px solid var(--border); - border-radius: 8px; - padding: 6px 12px; - z-index: 100; - box-shadow: 0 4px 12px rgba(0,0,0,0.3); -} -.wf-toml-preview { - background: var(--bg-secondary); - border: 1px solid var(--border); - border-radius: 6px; - padding: 12px; - font-size: 11px; + +.tool-pre { font-family: var(--font-mono); + font-size: 11px; + line-height: 1.5; + color: var(--text-secondary); + background: var(--surface2); + padding: 10px 12px; + border-radius: var(--radius-sm); + overflow-x: auto; white-space: pre-wrap; - color: var(--text); - max-height: 400px; + word-break: break-word; + max-height: 300px; overflow-y: auto; } -.flex-col { flex-direction: column; } + +.tool-pre-error { + color: var(--error); + background: var(--error-subtle); +} + +.tool-pre-short { max-height: 100px; } +.tool-pre-medium { max-height: 200px; } /* ═══════════════════════════════════════════════════════════════════════════ - UI/UX Pro Max Component Enhancements + INPUT AREA — Message input ═══════════════════════════════════════════════════════════════════════════ */ -/* Ensure all interactive elements have cursor-pointer */ -.btn, .nav-item, .tab, .badge[onclick], .filter-pill, .wizard-category-pill, -.personality-pill, .emoji-grid-item, .file-list-item, .quick-action-card, -.session-item, .slash-menu-item, .channel-step-item, .wizard-progress-step, -.install-platform-pill, .copy-btn, .toast, .drop-zone, .suggest-chip { - cursor: pointer; +.input-row { + display: flex; + align-items: flex-end; + gap: 10px; } -/* Enhanced button states */ -.btn:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - box-shadow: 0 0 0 4px var(--accent-glow); +.input-row textarea { + flex: 1; + resize: none; + border: 1px solid var(--border); + border-radius: var(--radius-lg); + padding: 12px 16px; + font-family: var(--font-sans); + font-size: 14px; + line-height: 1.5; + background: var(--surface); + color: var(--text); + transition: all var(--transition-fast); + min-height: 46px; + max-height: 150px; } -/* Button loading state with spinner */ -.btn.loading { - position: relative; - color: transparent; - pointer-events: none; -} -.btn.loading::after { - content: ''; - position: absolute; - width: 16px; - height: 16px; - border: 2px solid rgba(255,255,255,0.3); - border-top-color: #fff; - border-radius: 50%; - animation: spin 0.6s linear infinite; -} - -/* Ripple effect for buttons and cards */ -.ripple { - position: relative; - overflow: hidden; -} -.ripple::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - background: rgba(255,255,255,0.2); - border-radius: 50%; - transform: translate(-50%, -50%); - transition: width 0.4s ease, height 0.4s ease; -} -.ripple:active::before { - width: 200%; - height: 200%; -} - -/* Enhanced card hover states with proper transitions */ -.card, .stat-card, .stat-card-lg, .quick-action-card, -.provider-card, .security-card, .wizard-provider-card, .wizard-template-card { - transition: transform 0.2s var(--ease-smooth), - box-shadow 0.2s var(--ease-smooth), - border-color 0.2s var(--ease-smooth); -} - -/* Card selection state */ -.card.selected, .stat-card.selected { - border-color: var(--accent); - box-shadow: 0 0 0 2px var(--accent-glow), var(--shadow-md); -} - -/* Improved focus states for form elements */ -.form-input:focus, .form-select:focus, .form-textarea:focus, -.search-input:focus-within, .chat-search-input:focus, -.key-input-group input:focus, .file-editor:focus { +.input-row textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); - transition: border-color 0.15s ease, box-shadow 0.15s ease; } -/* Enhanced modal animations */ -.modal-overlay { - animation: fadeIn 0.15s ease; -} -.modal { - animation: scaleIn 0.2s var(--ease-spring); +.input-row textarea::placeholder { + color: var(--text-muted); } -/* Toast improvements with better accessibility */ -.toast { +.input-row textarea.streaming-active { + opacity: 0.7; +} + +.btn-send { + width: 46px; + height: 46px; + border: none; + border-radius: var(--radius-lg); + background: var(--gradient-accent); + color: var(--text-on-accent); cursor: pointer; - transition: transform 0.2s ease, opacity 0.2s ease; -} -.toast:hover { - transform: translateX(-4px); + display: flex; + align-items: center; + justify-content: center; + transition: all var(--transition-fast); + box-shadow: var(--shadow-accent); } -/* Improved badge hover states */ -.badge[onclick]:hover { - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(0,0,0,0.1); - transition: transform 0.15s ease, box-shadow 0.15s ease; +.btn-send:hover:not(:disabled) { + transform: scale(1.05); + box-shadow: var(--shadow-lg), var(--shadow-accent); } -/* Enhanced toggle switch accessibility */ -.toggle { +.btn-send:disabled { + opacity: 0.4; + cursor: not-allowed; + transform: none; +} + +.btn-stop { + width: 46px; + height: 46px; + border: none; + border-radius: var(--radius-lg); + background: var(--error); + color: #FFFFFF; cursor: pointer; -} -.toggle:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - box-shadow: 0 0 0 4px var(--accent-glow); + display: flex; + align-items: center; + justify-content: center; + transition: all var(--transition-fast); + box-shadow: var(--shadow-error); } -/* Tab keyboard navigation */ -.tab { - cursor: pointer; -} -.tab:focus-visible { - outline: 2px solid var(--accent); - outline-offset: -2px; - border-radius: var(--radius-sm); +.btn-stop:hover { + background: var(--error-hover); } -/* Filter pill enhanced states */ -.filter-pill:focus-visible, -.wizard-category-pill:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; +.input-footer { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 8px; + min-height: 20px; } -/* Skeleton loading with proper animation */ -.skeleton { - background: linear-gradient( - 90deg, - var(--surface) 25%, - var(--surface2) 37%, - var(--surface) 63% - ); - background-size: 200% 100%; - animation: shimmer 1.5s ease-in-out infinite; -} +/* ═══════════════════════════════════════════════════════════════════════════ + SLASH COMMAND MENU + ═══════════════════════════════════════════════════════════════════════════ */ -/* Empty state improvements */ -.empty-state { - animation: fadeIn 0.3s ease; -} -.empty-state-icon { - animation: scaleIn 0.3s var(--ease-spring); -} - -/* Progress bar animation */ -.progress-bar-fill { - transition: width 0.3s ease; -} - -/* Typing indicator bounce */ -@keyframes typing-bounce { - 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; } - 30% { transform: translateY(-4px); opacity: 1; } -} - -/* Message streaming indicator */ -@keyframes stream-pulse { - 0%, 100% { border-left-color: var(--accent); box-shadow: -2px 0 8px var(--accent-glow); } - 50% { border-left-color: var(--accent-dim); box-shadow: none; } -} - -/* Live pulse animation for indicators */ -@keyframes live-pulse { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.4; transform: scale(0.85); } -} - -/* Spin animation for loading states */ -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* Pulse ring for status indicators */ -@keyframes pulse-ring { - 0% { box-shadow: 0 0 0 0 currentColor; } - 70% { box-shadow: 0 0 0 4px transparent; } - 100% { box-shadow: 0 0 0 0 transparent; } -} - -/* Improved dropdown menus */ -.session-dropdown, .slash-menu { - animation: slideDown 0.15s ease; + position: absolute; + bottom: 100%; + left: 0; + right: 0; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + margin-bottom: 8px; + max-height: 200px; + overflow-y: auto; + z-index: var(--z-dropdown); } -/* Dropdown item keyboard navigation */ -.session-item:focus-visible, -.slash-menu-item:focus-visible { - outline: none; +.slash-menu-item { + display: flex; + flex-direction: column; + gap: 2px; + padding: 10px 14px; + cursor: pointer; + transition: background var(--transition-fast); +} + +.slash-menu-item:hover, +.slash-menu-item.slash-active { background: var(--surface2); } -/* Scrollbar hover state */ -::-webkit-scrollbar-thumb:hover { - background: var(--border-light); +/* ═══════════════════════════════════════════════════════════════════════════ + RECORDING INDICATORS + ═══════════════════════════════════════════════════════════════════════════ */ + +.recording-dot { + width: 12px; + height: 12px; + background: var(--error); + border-radius: 50%; + animation: pulse-ring 1s infinite; } -/* Selection styling */ -::selection { - background: var(--accent); - color: var(--bg-primary); +.recording-indicator { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 12px; + background: var(--error-subtle); + border-radius: var(--radius-full); } -/* Print optimization */ -@media print { - .sidebar, .sidebar-overlay, .mobile-menu-btn, - .toast-container, .btn, .modal-overlay { - display: none !important; - } - .main-content { - margin: 0; - max-width: 100%; - } - body { - background: #fff; - color: #000; - } +.btn-recording { + background: var(--error-subtle) !important; + color: var(--error) !important; } -/* Reduced motion support */ -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - } +/* ═══════════════════════════════════════════════════════════════════════════ + TIP BAR + ═══════════════════════════════════════════════════════════════════════════ */ + +.tip-bar { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 10px; + background: var(--surface2); + border-radius: var(--radius-full); } -/* High contrast mode support */ -@media (prefers-contrast: high) { - .card, .modal, .btn, input, select, textarea { - border-width: 2px; - } - .badge { - border: 1px solid currentColor; - } +.tip-bar-dismiss { + background: transparent; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 14px; + line-height: 1; + padding: 0 4px; } -/* Touch device optimizations */ -@media (pointer: coarse) { - .btn, .nav-item, .tab, .badge[onclick], .toggle, - .filter-pill, .wizard-category-pill, .personality-pill { - min-height: 44px; - min-width: 44px; - } +.tip-bar-dismiss:hover { + color: var(--text); } -/* Tooltip styles (for future use) */ -[data-tooltip] { - position: relative; +/* ═══════════════════════════════════════════════════════════════════════════ + AUDIO PLAYER + ═══════════════════════════════════════════════════════════════════════════ */ + +.audio-player { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 14px; + background: var(--surface2); + border-radius: var(--radius-md); } -[data-tooltip]::after { - content: attr(data-tooltip); - position: absolute; - bottom: 100%; - left: 50%; - transform: translateX(-50%); - padding: 6px 10px; + +/* ═══════════════════════════════════════════════════════════════════════════ + AGENT CHIP — Agent selector cards + ═══════════════════════════════════════════════════════════════════════════ */ + +.agent-chip { + cursor: pointer; + display: flex; + align-items: center; + gap: 12px; + padding: 14px 20px; background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius-sm); - font-size: 11px; - white-space: nowrap; - opacity: 0; - visibility: hidden; - transition: opacity 0.15s, visibility 0.15s; - z-index: var(--z-tooltip, 700); - box-shadow: var(--shadow-md); -} -[data-tooltip]:hover::after { - opacity: 1; - visibility: visible; + border-radius: var(--radius-lg); + transition: all var(--transition-fast); + min-width: 220px; } -/* Visually hidden but accessible */ -.visually-hidden { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; +.agent-chip:hover { + border-color: var(--accent); + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + MARKDOWN BODY — Rendered markdown styles + ═══════════════════════════════════════════════════════════════════════════ */ + +.markdown-body { + line-height: 1.6; + color: var(--text); +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3 { + margin-top: 1.2em; + margin-bottom: 0.6em; + font-weight: 600; + line-height: 1.3; +} + +.markdown-body h1 { font-size: 1.4em; } +.markdown-body h2 { font-size: 1.2em; } +.markdown-body h3 { font-size: 1.1em; } + +.markdown-body p { + margin-bottom: 0.8em; +} + +.markdown-body code { + font-family: var(--font-mono); + font-size: 0.9em; + padding: 2px 6px; + background: var(--surface2); + border-radius: var(--radius-sm); +} + +.markdown-body pre { + margin: 1em 0; + padding: 12px 16px; + background: var(--surface2); + border-radius: var(--radius-md); + overflow-x: auto; +} + +.markdown-body pre code { + padding: 0; + background: transparent; +} + +.markdown-body ul, +.markdown-body ol { + margin: 0.8em 0; + padding-left: 1.5em; +} + +.markdown-body li { + margin: 0.4em 0; +} + +.markdown-body blockquote { + margin: 1em 0; + padding: 8px 16px; + border-left: 3px solid var(--accent); + background: var(--surface2); + color: var(--text-dim); +} + +.markdown-body a { + color: var(--accent); + text-decoration: none; +} + +.markdown-body a:hover { + text-decoration: underline; +} + +.markdown-body table { + width: 100%; + border-collapse: collapse; + margin: 1em 0; +} + +.markdown-body th, +.markdown-body td { + padding: 8px 12px; + border: 1px solid var(--border); + text-align: left; +} + +.markdown-body th { + background: var(--surface2); + font-weight: 600; +} + +.markdown-body hr { + border: none; + border-top: 1px solid var(--border); + margin: 1.5em 0; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + SPINNER UTILITY + ═══════════════════════════════════════════════════════════════════════════ */ + +.spinner { + width: 16px; + height: 16px; + border: 2px solid var(--border); + border-top-color: var(--accent); + border-radius: 50%; + animation: spin 0.8s linear infinite; + display: inline-block; } diff --git a/crates/openfang-api/static/css/layout.css b/crates/openfang-api/static/css/layout.css index 02e2560..be99267 100644 --- a/crates/openfang-api/static/css/layout.css +++ b/crates/openfang-api/static/css/layout.css @@ -1,54 +1,121 @@ -/* OpenFang Layout — Grid + Sidebar + Responsive */ -/* Enhanced with UI/UX Pro Max guidelines */ +/* ═══════════════════════════════════════════════════════════════════════════ + OpenFang Layout — Premium Glassmorphism Grid System + ═══════════════════════════════════════════════════════════════════════════ + + Architecture: + - CSS Grid + Flexbox hybrid + - Glassmorphism sidebar with blur effects + - 5-level responsive breakpoints + - Safe area support for mobile + + ═══════════════════════════════════════════════════════════════════════════ */ + +/* ═══════════════════════════════════════════════════════════════════════════ + APP LAYOUT — Main container + ═══════════════════════════════════════════════════════════════════════════ */ .app-layout { display: flex; height: 100vh; overflow: hidden; + position: relative; } -/* Sidebar */ +/* ═══════════════════════════════════════════════════════════════════════════ + SIDEBAR — Glassmorphism navigation + ═══════════════════════════════════════════════════════════════════════════ */ + .sidebar { width: var(--sidebar-width); - background: var(--bg-primary); - border-right: 1px solid var(--border); + background: var(--glass-bg-strong); + backdrop-filter: blur(var(--glass-blur-strong)); + -webkit-backdrop-filter: blur(var(--glass-blur-strong)); + border-right: 1px solid var(--glass-border); display: flex; flex-direction: column; flex-shrink: 0; - transition: width var(--transition-normal); - z-index: var(--z-fixed, 300); + transition: width var(--transition-spring); + z-index: var(--z-sticky); + position: relative; } +/* Sidebar glow line */ +.sidebar::before { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 1px; + height: 100%; + background: linear-gradient( + 180deg, + transparent 0%, + var(--accent-glow) 20%, + var(--accent-glow) 80%, + transparent 100% + ); + opacity: 0.5; +} + +/* Collapsed sidebar */ .sidebar.collapsed { width: var(--sidebar-collapsed); } .sidebar.collapsed .sidebar-label, .sidebar.collapsed .sidebar-header-text, -.sidebar.collapsed .nav-label { display: none; } +.sidebar.collapsed .nav-label { + display: none; +} -.sidebar.collapsed .nav-item { justify-content: center; padding: 12px 0; } +.sidebar.collapsed .nav-item { + justify-content: center; + padding: 12px; +} + +.sidebar.collapsed .sidebar-status { + padding: 8px 12px; + justify-content: center; +} + +.sidebar.collapsed .sidebar-header { + padding: 12px; + justify-content: center; +} + +.sidebar.collapsed .theme-switcher { + display: none; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + SIDEBAR HEADER — Logo and branding + ═══════════════════════════════════════════════════════════════════════════ */ .sidebar-header { - padding: 16px; - border-bottom: 1px solid var(--border); + padding: 16px 18px; + border-bottom: 1px solid var(--border-subtle); display: flex; align-items: center; justify-content: space-between; - min-height: 60px; + min-height: 64px; + position: sticky; + top: 0; + background: var(--glass-bg-strong); + z-index: 10; } .sidebar-logo { display: flex; align-items: center; - gap: 10px; + gap: 12px; } .sidebar-logo img { - width: 28px; - height: 28px; - opacity: 0.8; - transition: opacity 0.2s, transform 0.2s; + width: 32px; + height: 32px; + opacity: 0.9; + transition: all var(--transition-fast); + filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)); } .sidebar-logo img:hover { @@ -57,81 +124,159 @@ } .sidebar-header h1 { - font-size: 14px; + font-size: 13px; font-weight: 700; color: var(--accent); letter-spacing: 3px; font-family: var(--font-mono); + text-shadow: 0 0 20px var(--accent-glow); } .sidebar-header .version { - font-size: 9px; + font-size: 10px; color: var(--text-muted); - margin-top: 1px; + margin-top: 2px; letter-spacing: 0.5px; } +/* Theme switcher in sidebar */ +.theme-switcher { + display: flex; + gap: 2px; + background: var(--surface2); + padding: 3px; + border-radius: var(--radius-full); + border: 1px solid var(--border); +} + +.theme-opt { + width: 26px; + height: 26px; + border: none; + background: transparent; + border-radius: var(--radius-full); + cursor: pointer; + font-size: 12px; + color: var(--text-dim); + transition: all var(--transition-fast); + display: flex; + align-items: center; + justify-content: center; +} + +.theme-opt:hover { + color: var(--text); +} + +.theme-opt.active { + background: var(--surface); + color: var(--accent); + box-shadow: var(--shadow-sm); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + SIDEBAR STATUS — Connection indicator + ═══════════════════════════════════════════════════════════════════════════ */ + .sidebar-status { font-size: 11px; color: var(--success); display: flex; align-items: center; - gap: 6px; - padding: 8px 16px; - border-bottom: 1px solid var(--border); + gap: 8px; + padding: 10px 18px; + border-bottom: 1px solid var(--border-subtle); + font-weight: 500; } -.sidebar-status.offline { color: var(--error); } +.sidebar-status.offline { + color: var(--error); +} .status-dot { - width: 6px; height: 6px; + width: 6px; + height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; - box-shadow: 0 0 6px currentColor; + box-shadow: 0 0 8px currentColor; + animation: pulse-ring 2s infinite; } .conn-badge { font-size: 9px; - padding: 1px 5px; - border-radius: 3px; - font-weight: 600; + padding: 2px 6px; + border-radius: var(--radius-sm); + font-weight: 700; letter-spacing: 0.5px; margin-left: auto; + font-family: var(--font-mono); } -.conn-badge.ws { background: var(--success); color: #000; } -.conn-badge.http { background: var(--warning); color: #000; } -/* Navigation */ +.conn-badge.ws { + background: var(--success-subtle); + color: var(--success); +} + +.conn-badge.http { + background: var(--warning-subtle); + color: var(--warning); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + SIDEBAR NAVIGATION + ═══════════════════════════════════════════════════════════════════════════ */ + .sidebar-nav { flex: 1; overflow-y: auto; - padding: 8px; + overflow-x: hidden; + padding: 12px; scrollbar-width: none; } -.sidebar-nav::-webkit-scrollbar { width: 0; } + +.sidebar-nav::-webkit-scrollbar { + width: 0; +} .nav-section { - margin-bottom: 4px; + margin-bottom: 8px; } .nav-section-title { - font-size: 9px; + font-size: 10px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--text-muted); - padding: 12px 12px 4px; + padding: 12px 12px 6px; font-weight: 600; + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + transition: color var(--transition-fast); } -.sidebar.collapsed .nav-section-title { display: none; } +.nav-section-title:hover { + color: var(--text-dim); +} + +.sidebar.collapsed .nav-section-title { + display: none; +} + +.nav-section-chevron { + font-size: 14px; + transition: transform var(--transition-fast); + opacity: 0.5; +} .nav-item { display: flex; align-items: center; - gap: 10px; - padding: 9px 12px; - border-radius: var(--radius-md); + gap: 12px; + padding: 10px 14px; + border-radius: var(--radius-lg); cursor: pointer; font-size: 13px; color: var(--text-dim); @@ -140,34 +285,61 @@ border: 1px solid transparent; white-space: nowrap; font-weight: 500; - min-height: 36px; /* Minimum touch target */ + min-height: 40px; + position: relative; + overflow: hidden; +} + +/* Nav item hover glow */ +.nav-item::before { + content: ''; + position: absolute; + inset: 0; + background: var(--gradient-accent-subtle); + opacity: 0; + transition: opacity var(--transition-fast); } .nav-item:hover { background: var(--surface2); color: var(--text); - transform: translateX(2px); + transform: translateX(3px); +} + +.nav-item:hover::before { + opacity: 1; } .nav-item.active { background: var(--accent); - color: var(--bg-primary); + color: var(--text-on-accent); font-weight: 600; - box-shadow: var(--shadow-sm), 0 2px 8px rgba(255, 92, 0, 0.2); + box-shadow: var(--shadow-accent); } +.nav-item.active::before { + opacity: 0; +} + +.nav-item.active:hover { + background: var(--accent-hover); +} + +/* Nav icon */ .nav-icon { - width: 18px; - height: 18px; + width: 20px; + height: 20px; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; + position: relative; + z-index: 1; } .nav-icon svg { - width: 16px; - height: 16px; + width: 18px; + height: 18px; fill: none; stroke: currentColor; stroke-width: 2; @@ -175,20 +347,39 @@ stroke-linejoin: round; } -/* Sidebar toggle button */ +.nav-label { + position: relative; + z-index: 1; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + SIDEBAR FOOTER + ═══════════════════════════════════════════════════════════════════════════ */ + +.sidebar-footer { + padding: 12px 16px; + border-top: 1px solid var(--border-subtle); +} + .sidebar-toggle { - padding: 10px 16px; - border-top: 1px solid var(--border); + padding: 12px 16px; + border-top: 1px solid var(--border-subtle); cursor: pointer; text-align: center; font-size: 14px; color: var(--text-muted); - transition: color var(--transition-fast); + transition: all var(--transition-fast); } -.sidebar-toggle:hover { color: var(--text); } +.sidebar-toggle:hover { + color: var(--text); + background: var(--surface2); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + MAIN CONTENT AREA + ═══════════════════════════════════════════════════════════════════════════ */ -/* Main content area */ .main-content { flex: 1; display: flex; @@ -196,321 +387,690 @@ min-width: 0; overflow: hidden; background: var(--bg); + position: relative; } -/* Page wrapper divs (rendered by x-if) must fill the column - and be flex containers so .page-body can scroll. */ +/* Aurora background effect */ +.main-content::before { + content: ''; + position: absolute; + inset: 0; + background: var(--gradient-mesh); + pointer-events: none; + opacity: 0.5; +} + +/* Page wrapper divs (rendered by x-if) must fill the column */ .main-content > div { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; + position: relative; + z-index: 1; } +/* ═══════════════════════════════════════════════════════════════════════════ + PAGE HEADER + ═══════════════════════════════════════════════════════════════════════════ */ + .page-header { - padding: 14px 24px; + padding: 16px 28px; border-bottom: 1px solid var(--border); - background: var(--bg-primary); + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur-subtle)); + -webkit-backdrop-filter: blur(var(--glass-blur-subtle)); display: flex; align-items: center; justify-content: space-between; min-height: var(--header-height); + position: sticky; + top: 0; + z-index: var(--z-elevated); } .page-header h2 { - font-size: 15px; + font-size: 16px; font-weight: 600; letter-spacing: -0.01em; + color: var(--text); } -.page-body { - flex: 1; - min-height: 0; - overflow-y: auto; - padding: 24px; -} - -/* Mobile overlay */ -.sidebar-overlay { - display: none; - position: fixed; - inset: 0; - background: rgba(0,0,0,0.6); - z-index: 99; -} - -/* Wide desktop — larger card grids */ -@media (min-width: 1400px) { - .card-grid { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); } -} - -/* Responsive — tablet breakpoint */ -@media (max-width: 1024px) { - .card-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); } - .security-grid { grid-template-columns: 1fr; } - .cost-charts-row { grid-template-columns: 1fr; } - .overview-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); } - .page-body { padding: 16px; } -} - -/* Responsive — mobile breakpoint */ -@media (max-width: 768px) { - .sidebar { - position: fixed; - left: -300px; - top: 0; - bottom: 0; - transition: left var(--transition-normal); - } - .sidebar.mobile-open { - left: 0; - } - .sidebar.mobile-open + .sidebar-overlay { - display: block; - } - .sidebar.collapsed { - width: var(--sidebar-width); - left: -300px; - } - .mobile-menu-btn { display: flex !important; } -} - -@media (min-width: 769px) { - .mobile-menu-btn { display: none !important; } -} - -/* Mobile small screen */ -@media (max-width: 480px) { - .page-header { flex-direction: column; gap: 8px; align-items: flex-start; padding: 12px 16px; } - .page-body { padding: 12px; } - .stats-row { flex-wrap: wrap; } - .stat-card { min-width: 80px; flex: 1 1 40%; } - .stat-card-lg { min-width: 80px; flex: 1 1 40%; padding: 12px; } - .stat-card-lg .stat-value { font-size: 22px; } - .card-grid { grid-template-columns: 1fr; } - .overview-grid { grid-template-columns: 1fr; } - .input-area { padding: 8px 12px; } - .main-content { padding: 0; } - .table-wrap { font-size: 10px; } - .modal { margin: 8px; max-height: calc(100vh - 16px); } -} - -/* Touch-friendly tap targets */ -@media (pointer: coarse) { - .btn { min-height: 44px; min-width: 44px; } - .nav-item { min-height: 44px; padding: 12px; } - .form-input, .form-select, .form-textarea { min-height: 44px; } - .toggle { min-width: 44px; min-height: 28px; } - .tab { min-height: 44px; padding: 12px 16px; } - .filter-pill, .wizard-category-pill { min-height: 44px; } -} - -/* Focus mode — hide sidebar for distraction-free chat */ -.app-layout.focus-mode .sidebar { display: none; } -.app-layout.focus-mode .sidebar-overlay { display: none; } -.app-layout.focus-mode .main-content { max-width: 100%; margin-left: 0; } -.app-layout.focus-mode .mobile-menu-btn { display: none !important; } - /* ═══════════════════════════════════════════════════════════════════════════ - UI/UX Pro Max Layout Enhancements + PAGE BODY ═══════════════════════════════════════════════════════════════════════════ */ -/* Z-index scale for consistent layering */ -.sidebar { z-index: var(--z-sticky, 200); } -.sidebar-overlay { z-index: calc(var(--z-sticky, 200) - 1); } -.mobile-menu-btn { z-index: var(--z-fixed, 300); } - -/* Improved responsive breakpoints */ -/* Extra small devices (phones, 480px and below) */ -@media (max-width: 480px) { - .sidebar { - width: 100%; - max-width: 280px; - } - .page-header { - padding: 12px 16px; - flex-wrap: wrap; - gap: 8px; - } - .page-header h2 { - font-size: 14px; - } - .stats-row { - gap: 8px; - } - .stat-card, .stat-card-lg { - padding: 12px 16px; - min-width: unset; - flex: 1 1 calc(50% - 4px); - } - .card-grid { - grid-template-columns: 1fr; - gap: 12px; - } - .overview-grid { - grid-template-columns: 1fr; - } - .modal { - margin: 8px; - max-height: calc(100vh - 16px); - width: calc(100% - 16px); - } -} - -/* Small devices (tablets portrait, 481px to 768px) */ -@media (min-width: 481px) and (max-width: 768px) { - .card-grid { - grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); - } - .overview-grid { - grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); - } -} - -/* Medium devices (tablets landscape, 769px to 1024px) */ -@media (min-width: 769px) and (max-width: 1024px) { - .card-grid { - grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); - } - .sidebar { - width: 200px; - } -} - -/* Large devices (desktops, 1025px to 1400px) */ -@media (min-width: 1025px) and (max-width: 1400px) { - .card-grid { - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - } -} - -/* Extra large devices (large desktops, 1401px and above) */ -@media (min-width: 1401px) { - .card-grid { - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - } - .overview-grid { - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - } -} - -/* Sidebar improvements */ -.sidebar-header { - position: sticky; - top: 0; - background: var(--bg-primary); - z-index: 10; -} - -/* Main content area improvements */ -.main-content { - display: flex; - flex-direction: column; - min-width: 0; - overflow: hidden; - background: var(--bg); -} - -/* Page body scroll improvements */ .page-body { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; - padding: 24px; + padding: var(--page-padding); scroll-behavior: smooth; overscroll-behavior: contain; } -/* Better keyboard navigation for sidebar */ -.nav-item:focus-visible { - outline: 2px solid var(--accent); - outline-offset: -2px; - background: var(--surface2); +/* ═══════════════════════════════════════════════════════════════════════════ + CARD GRIDS + ═══════════════════════════════════════════════════════════════════════════ */ + +.card-grid { + display: grid; + gap: 20px; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } -/* Mobile menu button improvements */ +.overview-grid { + display: grid; + gap: 16px; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); +} + +.security-grid { + display: grid; + gap: 16px; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); +} + +.cost-charts-row { + display: grid; + gap: 20px; + grid-template-columns: repeat(2, 1fr); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + MOBILE OVERLAY + ═══════════════════════════════════════════════════════════════════════════ */ + +.sidebar-overlay { + display: none; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + z-index: calc(var(--z-sticky) - 1); + animation: fadeIn 0.2s ease; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + MOBILE MENU BUTTON + ═══════════════════════════════════════════════════════════════════════════ */ + .mobile-menu-btn { position: fixed; - top: 8px; - left: 8px; - z-index: var(--z-fixed, 300); - padding: 8px 12px; - border-radius: var(--radius-md); - background: var(--surface); - border: 1px solid var(--border); - box-shadow: var(--shadow-sm); + top: 12px; + left: 12px; + z-index: var(--z-fixed); + padding: 10px 14px; + border-radius: var(--radius-lg); + background: var(--glass-bg-strong); + backdrop-filter: blur(var(--glass-blur)); + -webkit-backdrop-filter: blur(var(--glass-blur)); + border: 1px solid var(--glass-border); + box-shadow: var(--shadow-md); transition: all var(--transition-fast); } + .mobile-menu-btn:hover { background: var(--surface2); - border-color: var(--border-light); + transform: scale(1.02); } + .mobile-menu-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } -/* Safe area insets for mobile devices */ +/* ═══════════════════════════════════════════════════════════════════════════ + FOCUS MODE — Distraction-free chat + ═══════════════════════════════════════════════════════════════════════════ */ + +.app-layout.focus-mode .sidebar { + display: none; +} + +.app-layout.focus-mode .sidebar-overlay { + display: none; +} + +.app-layout.focus-mode .main-content { + max-width: 100%; + margin-left: 0; +} + +.app-layout.focus-mode .mobile-menu-btn { + display: none !important; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + RESPONSIVE BREAKPOINTS + ═══════════════════════════════════════════════════════════════════════════ */ + +/* Extra large devices (1401px and above) */ +@media (min-width: 1401px) { + .card-grid { + grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); + } + .overview-grid { + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + } + .page-body { + padding: 32px; + } +} + +/* Large devices (1025px to 1400px) */ +@media (min-width: 1025px) and (max-width: 1400px) { + .card-grid { + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + } + .overview-grid { + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + } +} + +/* Medium devices (769px to 1024px) — Tablets landscape */ +@media (min-width: 769px) and (max-width: 1024px) { + .card-grid { + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + } + .overview-grid { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + } + .sidebar { + width: 220px; + } + .cost-charts-row { + grid-template-columns: 1fr; + } + .page-body { + padding: 20px; + } +} + +/* Small devices (481px to 768px) — Tablets portrait */ +@media (min-width: 481px) and (max-width: 768px) { + .sidebar { + position: fixed; + left: -280px; + top: 0; + bottom: 0; + width: 260px; + transition: left var(--transition-spring); + z-index: var(--z-fixed); + } + + .sidebar.mobile-open { + left: 0; + } + + .sidebar.mobile-open + .sidebar-overlay { + display: block; + } + + .sidebar.collapsed { + width: 260px; + left: -280px; + } + + .card-grid { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + } + .overview-grid { + grid-template-columns: 1fr; + } + .cost-charts-row { + grid-template-columns: 1fr; + } + .security-grid { + grid-template-columns: 1fr; + } + .page-body { + padding: 16px; + } + .page-header { + padding: 14px 20px; + } + .mobile-menu-btn { + display: flex !important; + } +} + +/* Extra small devices (480px and below) — Phones */ +@media (max-width: 480px) { + .sidebar { + position: fixed; + left: -100%; + top: 0; + bottom: 0; + width: 100%; + max-width: 280px; + transition: left var(--transition-spring); + z-index: var(--z-fixed); + } + + .sidebar.mobile-open { + left: 0; + } + + .sidebar.mobile-open + .sidebar-overlay { + display: block; + } + + .sidebar.collapsed { + width: 100%; + max-width: 280px; + left: -100%; + } + + .mobile-menu-btn { + display: flex !important; + } + + .page-header { + flex-direction: column; + gap: 10px; + align-items: flex-start; + padding: 12px 16px; + min-height: auto; + } + + .page-header h2 { + font-size: 14px; + } + + .page-body { + padding: 12px; + } + + .stats-row { + gap: 10px; + } + + .stat-card, + .stat-card-lg { + padding: 14px 16px; + min-width: unset; + flex: 1 1 calc(50% - 5px); + border-radius: var(--radius-lg); + } + + .stat-card-lg .stat-value { + font-size: 22px; + } + + .card-grid, + .overview-grid { + grid-template-columns: 1fr; + gap: 12px; + } + + .card { + padding: 16px; + border-radius: var(--radius-lg); + } + + .cost-charts-row { + grid-template-columns: 1fr; + } + + .security-grid { + grid-template-columns: 1fr; + } + + .input-area { + padding: 10px 14px; + } + + .main-content { + padding: 0; + } + + .modal { + margin: 12px; + max-height: calc(100vh - 24px); + width: calc(100% - 24px); + border-radius: var(--radius-xl); + } + + .quick-action-card { + padding: 14px 16px; + } + + .btn { + padding: 10px 14px; + } + + .btn-sm { + padding: 8px 12px; + } +} + +/* ═══════════════════════════════════════════════════════════════════════════ + TOUCH DEVICE OPTIMIZATIONS + ═══════════════════════════════════════════════════════════════════════════ */ + +@media (pointer: coarse) { + .btn { + min-height: 44px; + min-width: 44px; + } + + .nav-item { + min-height: 44px; + padding: 12px 14px; + } + + .form-input, + .form-select, + .form-textarea { + min-height: 48px; + font-size: 16px; /* Prevents iOS zoom */ + } + + .toggle { + min-width: 48px; + min-height: 28px; + } + + .tab { + min-height: 44px; + padding: 12px 18px; + } + + .badge[onclick] { + min-height: 32px; + padding: 6px 12px; + } +} + +/* ═══════════════════════════════════════════════════════════════════════════ + SAFE AREA INSETS — iOS devices + ═══════════════════════════════════════════════════════════════════════════ */ + @supports (padding: env(safe-area-inset-bottom)) { .input-area { padding-bottom: calc(16px + env(safe-area-inset-bottom)); } + .sidebar { padding-bottom: env(safe-area-inset-bottom); } + + .modal { + padding-bottom: calc(24px + env(safe-area-inset-bottom)); + } + + .toast-container { + bottom: calc(24px + env(safe-area-inset-bottom)); + } } -/* Container query support for responsive components */ +/* ═══════════════════════════════════════════════════════════════════════════ + CONTAINER QUERIES — Component-level responsiveness + ═══════════════════════════════════════════════════════════════════════════ */ + @container (min-width: 400px) { .card-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } } -/* Grid layout improvements */ -.card-grid { - display: grid; - gap: 16px; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); +/* ═══════════════════════════════════════════════════════════════════════════ + CHAT LAYOUT — Message area specific + ═══════════════════════════════════════════════════════════════════════════ */ + +.chat-wrapper { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + overflow: hidden; } -/* Flexbox utilities */ -.flex-wrap { flex-wrap: wrap; } -.flex-1 { flex: 1; } -.flex-grow { flex-grow: 1; } -.flex-shrink-0 { flex-shrink: 0; } +.messages { + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 20px; + display: flex; + flex-direction: column; + gap: 16px; +} -/* Gap utilities */ -.gap-1 { gap: 4px; } -.gap-2 { gap: 8px; } -.gap-3 { gap: 12px; } -.gap-4 { gap: 16px; } -.gap-6 { gap: 24px; } +.input-area { + padding: 16px 20px; + border-top: 1px solid var(--border); + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur-subtle)); + -webkit-backdrop-filter: blur(var(--glass-blur-subtle)); +} -/* Padding utilities */ -.p-2 { padding: 8px; } -.p-3 { padding: 12px; } -.p-4 { padding: 16px; } -.px-2 { padding-left: 8px; padding-right: 8px; } -.px-4 { padding-left: 16px; padding-right: 16px; } -.py-2 { padding-top: 8px; padding-bottom: 8px; } -.py-4 { padding-top: 16px; padding-bottom: 16px; } +/* ═══════════════════════════════════════════════════════════════════════════ + TABLE WRAPPER — Responsive tables + ═══════════════════════════════════════════════════════════════════════════ */ -/* Margin utilities */ -.m-0 { margin: 0; } -.mt-1 { margin-top: 4px; } -.mt-2 { margin-top: 8px; } -.mt-4 { margin-top: 16px; } -.mb-1 { margin-bottom: 4px; } -.mb-2 { margin-bottom: 8px; } -.mb-4 { margin-bottom: 16px; } -.mx-auto { margin-left: auto; margin-right: auto; } +.table-wrap { + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} -/* Width utilities */ -.w-full { width: 100%; } -.max-w-sm { max-width: 24rem; } -.max-w-md { max-width: 28rem; } -.max-w-lg { max-width: 32rem; } -.max-w-xl { max-width: 36rem; } +.table-wrap table { + width: 100%; + border-collapse: collapse; + font-size: 13px; +} + +.table-wrap th, +.table-wrap td { + padding: 12px 16px; + text-align: left; + border-bottom: 1px solid var(--border); +} + +.table-wrap th { + font-weight: 600; + color: var(--text-dim); + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.05em; + background: var(--surface2); +} + +.table-wrap tr:hover td { + background: var(--surface2); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + SESSION DROPDOWN + ═══════════════════════════════════════════════════════════════════════════ */ + +.session-dropdown { + position: absolute; + top: calc(100% + 4px); + right: 0; + min-width: 220px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + z-index: var(--z-dropdown); + overflow: hidden; +} + +.session-dropdown-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 14px; + border-bottom: 1px solid var(--border); + background: var(--surface2); +} + +.session-item { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 14px; + cursor: pointer; + transition: background var(--transition-fast); +} + +.session-item:hover { + background: var(--surface2); +} + +.session-item.active { + background: var(--accent-subtle); +} + +.session-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--text-muted); + flex-shrink: 0; +} + +.session-dot.active { + background: var(--success); + box-shadow: 0 0 8px var(--success-glow); +} + +.session-count-badge { + position: absolute; + top: -4px; + right: -4px; + min-width: 16px; + height: 16px; + padding: 0 4px; + background: var(--accent); + color: var(--text-on-accent); + border-radius: var(--radius-full); + font-size: 10px; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + CHAT SEARCH BAR + ═══════════════════════════════════════════════════════════════════════════ */ + +.chat-search-bar { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 16px; + background: var(--surface2); + border-bottom: 1px solid var(--border); +} + +.chat-search-input { + flex: 1; + border: none; + background: transparent; + color: var(--text); + font-size: 14px; + outline: none; +} + +.chat-search-input::placeholder { + color: var(--text-muted); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + QUEUE BADGE + ═══════════════════════════════════════════════════════════════════════════ */ + +.queue-badge { + font-size: 10px; + padding: 2px 8px; + background: var(--info-subtle); + color: var(--info); + border-radius: var(--radius-full); + font-weight: 600; + animation: pulse-ring 2s infinite; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + MESSAGE STYLES + ═══════════════════════════════════════════════════════════════════════════ */ + +.message { + display: flex; + gap: 12px; + max-width: 85%; + animation: slideUp 0.3s var(--ease-spring); +} + +.message.user { + flex-direction: row-reverse; + margin-left: auto; +} + +.message.agent { + margin-right: auto; +} + +.message-avatar { + width: 32px; + height: 32px; + border-radius: var(--radius-md); + overflow: hidden; + flex-shrink: 0; + background: var(--surface2); + display: flex; + align-items: center; + justify-content: center; +} + +.message-avatar img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.message-body { + flex: 1; + min-width: 0; +} + +.message.grouped .message-avatar { + visibility: hidden; +} + +.message-actions { + display: flex; + gap: 4px; + opacity: 0; + transition: opacity var(--transition-fast); +} + +.message:hover .message-actions { + opacity: 1; +} + +.message-action-btn { + padding: 4px 8px; + border: none; + background: var(--surface2); + border-radius: var(--radius-sm); + cursor: pointer; + color: var(--text-dim); + font-size: 11px; + transition: all var(--transition-fast); +} + +.message-action-btn:hover { + background: var(--surface3); + color: var(--text); +} + +.message-action-btn.copied { + background: var(--success-subtle); + color: var(--success); +} diff --git a/crates/openfang-api/static/css/theme.css b/crates/openfang-api/static/css/theme.css index 8c9ca2d..c8a0966 100644 --- a/crates/openfang-api/static/css/theme.css +++ b/crates/openfang-api/static/css/theme.css @@ -1,146 +1,358 @@ -/* OpenFang Theme — Premium design system */ -/* Optimized with UI/UX Pro Max guidelines: WCAG AAA contrast, accessible focus states */ +/* ═══════════════════════════════════════════════════════════════════════════ + OpenFang Design System — Premium Glassmorphism + Dark Mode OLED + ═══════════════════════════════════════════════════════════════════════════ + + Style: Modern Glassmorphism with Aurora accents + Typography: Inter (UI) + Geist Mono (Code) + Color Strategy: Deep OLED black + Vibrant accents + Frosted glass overlays + Accessibility: WCAG AAA contrast (7:1+) + + ═══════════════════════════════════════════════════════════════════════════ */ /* Font imports in index_head.html: Inter (body) + Geist Mono (code) */ +/* ═══════════════════════════════════════════════════════════════════════════ + LIGHT THEME — Clean Professional + ═══════════════════════════════════════════════════════════════════════════ */ [data-theme="light"], :root { - /* Backgrounds — layered depth */ - --bg: #F5F4F2; - --bg-primary: #EDECEB; - --bg-elevated: #F8F7F6; - --surface: #FFFFFF; - --surface2: #F0EEEC; - --surface3: #E8E6E3; - --border: #D5D2CF; - --border-light: #C8C4C0; - --border-subtle: #E0DEDA; + /* ───────────────────────────────────────────────────────────────────────── + Core Backgrounds — Layered depth system + ───────────────────────────────────────────────────────────────────────── */ + --bg: #F8F9FB; /* Base canvas */ + --bg-primary: #FFFFFF; /* Primary surface */ + --bg-elevated: #FFFFFF; /* Elevated cards */ + --surface: #FFFFFF; /* Card background */ + --surface2: #F4F5F7; /* Secondary surface */ + --surface3: #ECEEF1; /* Tertiary surface */ + --surface-glass: rgba(255, 255, 255, 0.72); /* Glass effect */ + --surface-glass-strong: rgba(255, 255, 255, 0.88); - /* Text hierarchy — WCAG AAA optimized (7:1+ contrast) */ - --text: #0F0F0F; /* 15.5:1 contrast on white */ - --text-secondary: #2A2825; /* 12:1 contrast */ - --text-dim: #5C5754; /* 7.5:1 contrast */ - --text-muted: #8A8580; /* 4.6:1 contrast for non-critical */ + /* Borders — Subtle definition */ + --border: rgba(0, 0, 0, 0.08); + --border-light: rgba(0, 0, 0, 0.05); + --border-subtle: rgba(0, 0, 0, 0.04); + --border-strong: rgba(0, 0, 0, 0.12); + --border-glass: rgba(255, 255, 255, 0.3); - /* Brand — Orange accent */ - --accent: #FF5C00; - --accent-light: #FF7A2E; - --accent-dim: #E05200; - --accent-glow: rgba(255, 92, 0, 0.1); - --accent-subtle: rgba(255, 92, 0, 0.05); + /* ───────────────────────────────────────────────────────────────────────── + Text Hierarchy — WCAG AAA (7:1+ contrast) + ───────────────────────────────────────────────────────────────────────── */ + --text: #0F172A; /* 15.8:1 — Primary text */ + --text-secondary: #1E293B; /* 13.2:1 — Secondary text */ + --text-dim: #475569; /* 7.5:1 — Muted text */ + --text-muted: #94A3B8; /* 4.6:1 — Non-critical */ + --text-on-accent: #FFFFFF; /* Text on accent color */ + + /* ───────────────────────────────────────────────────────────────────────── + Brand Accent — Vibrant Orange + ───────────────────────────────────────────────────────────────────────── */ + --accent: #FF5C00; /* Primary brand */ + --accent-hover: #FF7A2E; /* Hover state */ + --accent-active: #E05200; /* Active/pressed */ + --accent-light: #FF8A4D; /* Lighter variant */ + --accent-muted: #FFB380; /* Muted variant */ + --accent-subtle: rgba(255, 92, 0, 0.08); + --accent-glow: rgba(255, 92, 0, 0.15); + --accent-glass: rgba(255, 92, 0, 0.12); + + /* ───────────────────────────────────────────────────────────────────────── + Semantic Colors — Status indicators + ───────────────────────────────────────────────────────────────────────── */ + --success: #10B981; + --success-hover: #059669; + --success-dim: #047857; + --success-subtle: rgba(16, 185, 129, 0.08); + --success-muted: rgba(16, 185, 129, 0.15); + --success-glow: rgba(16, 185, 129, 0.2); - /* Status colors */ - --success: #22C55E; - --success-dim: #16A34A; - --success-subtle: rgba(34, 197, 94, 0.08); --error: #EF4444; - --error-dim: #DC2626; + --error-hover: #DC2626; + --error-dim: #B91C1C; --error-subtle: rgba(239, 68, 68, 0.06); + --error-muted: rgba(239, 68, 68, 0.12); + --error-glow: rgba(239, 68, 68, 0.15); + --warning: #F59E0B; - --warning-dim: #D97706; + --warning-hover: #D97706; + --warning-dim: #B45309; --warning-subtle: rgba(245, 158, 11, 0.08); - --info: #3B82F6; - --info-dim: #2563EB; - --info-subtle: rgba(59, 130, 246, 0.06); - --success-muted: rgba(34, 197, 94, 0.15); - --error-muted: rgba(239, 68, 68, 0.15); --warning-muted: rgba(245, 158, 11, 0.15); - --info-muted: rgba(59, 130, 246, 0.15); - --border-strong: #B0ACA8; - --card-highlight: rgba(0, 0, 0, 0.02); - /* Chat-specific */ - --agent-bg: #F5F4F2; - --user-bg: #FFF3E6; + --info: #3B82F6; + --info-hover: #2563EB; + --info-dim: #1D4ED8; + --info-subtle: rgba(59, 130, 246, 0.06); + --info-muted: rgba(59, 130, 246, 0.12); + --info-glow: rgba(59, 130, 246, 0.15); - /* Layout */ - --sidebar-width: 240px; - --sidebar-collapsed: 56px; - --header-height: 48px; + /* ───────────────────────────────────────────────────────────────────────── + Glassmorphism — Frosted glass effects + ───────────────────────────────────────────────────────────────────────── */ + --glass-bg: rgba(255, 255, 255, 0.72); + --glass-bg-strong: rgba(255, 255, 255, 0.88); + --glass-bg-subtle: rgba(255, 255, 255, 0.48); + --glass-border: rgba(255, 255, 255, 0.4); + --glass-blur: 16px; + --glass-blur-strong: 24px; + --glass-blur-subtle: 8px; - /* Radius — slightly larger for premium feel */ + /* ───────────────────────────────────────────────────────────────────────── + Gradients — Aurora-inspired + ───────────────────────────────────────────────────────────────────────── */ + --gradient-accent: linear-gradient(135deg, #FF5C00 0%, #FF8A4D 50%, #FFB380 100%); + --gradient-accent-subtle: linear-gradient(135deg, rgba(255, 92, 0, 0.1) 0%, rgba(255, 138, 77, 0.05) 100%); + --gradient-success: linear-gradient(135deg, #10B981 0%, #34D399 100%); + --gradient-mesh: + radial-gradient(at 40% 20%, rgba(255, 92, 0, 0.08) 0px, transparent 50%), + radial-gradient(at 80% 0%, rgba(59, 130, 246, 0.06) 0px, transparent 50%), + radial-gradient(at 0% 50%, rgba(16, 185, 129, 0.05) 0px, transparent 50%), + radial-gradient(at 80% 50%, rgba(168, 85, 247, 0.04) 0px, transparent 50%), + radial-gradient(at 0% 100%, rgba(255, 92, 0, 0.05) 0px, transparent 50%), + radial-gradient(at 80% 100%, rgba(59, 130, 246, 0.04) 0px, transparent 50%); + --gradient-card-shine: linear-gradient( + 105deg, + transparent 40%, + rgba(255, 255, 255, 0.8) 45%, + rgba(255, 255, 255, 0.8) 50%, + transparent 55% + ); + + /* ───────────────────────────────────────────────────────────────────────── + Shadows — 6-level depth system + ───────────────────────────────────────────────────────────────────────── */ + --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.04); + --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.03); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06), 0 2px 4px rgba(0, 0, 0, 0.04); + --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.08), 0 4px 12px rgba(0, 0, 0, 0.04); + --shadow-xl: 0 24px 48px rgba(0, 0, 0, 0.1), 0 8px 16px rgba(0, 0, 0, 0.05); + --shadow-2xl: 0 32px 64px rgba(0, 0, 0, 0.12), 0 12px 24px rgba(0, 0, 0, 0.06); + + /* Colored shadows */ + --shadow-accent: 0 8px 24px rgba(255, 92, 0, 0.18), 0 2px 8px rgba(255, 92, 0, 0.1); + --shadow-success: 0 8px 24px rgba(16, 185, 129, 0.15); + --shadow-error: 0 8px 24px rgba(239, 68, 68, 0.15); + --shadow-glow: 0 0 60px rgba(0, 0, 0, 0.04); + --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.8); + --shadow-inset-dark: inset 0 1px 0 rgba(0, 0, 0, 0.04); + + /* ───────────────────────────────────────────────────────────────────────── + Chat-specific colors + ───────────────────────────────────────────────────────────────────────── */ + --agent-bg: #F8F9FB; + --user-bg: #FFF7ED; + --agent-bg-glass: rgba(248, 249, 251, 0.8); + --user-bg-glass: rgba(255, 247, 237, 0.8); + + /* ───────────────────────────────────────────────────────────────────────── + Layout Constants + ───────────────────────────────────────────────────────────────────────── */ + --sidebar-width: 260px; + --sidebar-collapsed: 64px; + --header-height: 52px; + --page-padding: 24px; + --card-padding: 20px; + + /* ───────────────────────────────────────────────────────────────────────── + Border Radius — Premium rounded corners + ───────────────────────────────────────────────────────────────────────── */ --radius-xs: 4px; --radius-sm: 6px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; + --radius-md: 10px; + --radius-lg: 14px; + --radius-xl: 20px; + --radius-2xl: 28px; + --radius-full: 9999px; - /* Shadows — 6-level depth system */ - --shadow-xs: 0 1px 2px rgba(0,0,0,0.04); - --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04); - --shadow-md: 0 4px 12px rgba(0,0,0,0.07), 0 2px 4px rgba(0,0,0,0.04); - --shadow-lg: 0 12px 28px rgba(0,0,0,0.08), 0 4px 10px rgba(0,0,0,0.05); - --shadow-xl: 0 20px 40px rgba(0,0,0,0.1), 0 8px 16px rgba(0,0,0,0.06); - --shadow-glow: 0 0 40px rgba(0,0,0,0.05); - --shadow-accent: 0 4px 16px rgba(255, 92, 0, 0.12); - --shadow-inset: inset 0 1px 0 rgba(255,255,255,0.5); - - /* Typography — dual font system */ + /* ───────────────────────────────────────────────────────────────────────── + Typography — Dual font system + ───────────────────────────────────────────────────────────────────────── */ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; --font-mono: 'Geist Mono', 'SF Mono', 'Fira Code', 'Cascadia Code', 'JetBrains Mono', monospace; - /* Motion — spring curves for premium feel */ + /* ───────────────────────────────────────────────────────────────────────── + Motion — Spring physics curves + ───────────────────────────────────────────────────────────────────────── */ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); + --ease-spring-subtle: cubic-bezier(0.22, 1.2, 0.36, 1); --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1); --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in: cubic-bezier(0.4, 0, 1, 1); + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); + --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55); + + --transition-instant: 0.1s var(--ease-smooth); --transition-fast: 0.15s var(--ease-smooth); --transition-normal: 0.25s var(--ease-smooth); - --transition-spring: 0.4s var(--ease-spring); + --transition-slow: 0.4s var(--ease-smooth); + --transition-spring: 0.5s var(--ease-spring); + --transition-spring-fast: 0.35s var(--ease-spring); + + /* ───────────────────────────────────────────────────────────────────────── + Z-index Scale — Layer management + ───────────────────────────────────────────────────────────────────────── */ + --z-base: 1; + --z-elevated: 10; + --z-dropdown: 100; + --z-sticky: 200; + --z-fixed: 300; + --z-overlay: 400; + --z-modal-backdrop: 500; + --z-modal: 600; + --z-popover: 700; + --z-tooltip: 800; + --z-toast: 900; + --z-max: 9999; } +/* ═══════════════════════════════════════════════════════════════════════════ + DARK THEME — OLED-Optimized with Glassmorphism + ═══════════════════════════════════════════════════════════════════════════ */ [data-theme="dark"] { - /* OLED-optimized dark theme with WCAG AAA contrast */ - --bg: #020617; /* Deep black for OLED */ - --bg-primary: #0A0A0A; /* Near black primary */ - --bg-elevated: #121212; /* Elevated surface */ - --surface: #1A1A1A; /* Card background */ - --surface2: #242424; /* Secondary surface */ - --surface3: #18181B; /* Tertiary surface */ - --border: #2E2E2E; /* Visible border (3:1 contrast) */ - --border-light: #404040; /* Lighter border for hover */ - --border-subtle: #1F1F1F; /* Subtle separator */ - --text: #F8FAFC; /* 15.3:1 contrast on dark */ - --text-secondary: #E2E8F0; /* 12.5:1 contrast */ - --text-dim: #A1A1AA; /* 8:1 contrast */ - --text-muted: #71717A; /* 4.7:1 contrast */ + /* ───────────────────────────────────────────────────────────────────────── + Core Backgrounds — Deep OLED blacks + ───────────────────────────────────────────────────────────────────────── */ + --bg: #020617; /* OLED pure black */ + --bg-primary: #0A0A0F; /* Near black primary */ + --bg-elevated: #12121A; /* Elevated surface */ + --surface: #16161E; /* Card background */ + --surface2: #1C1C26; /* Secondary surface */ + --surface3: #22222E; /* Tertiary surface */ + --surface-glass: rgba(22, 22, 30, 0.72); + --surface-glass-strong: rgba(22, 22, 30, 0.88); + + /* Borders — Visible on dark */ + --border: rgba(255, 255, 255, 0.08); + --border-light: rgba(255, 255, 255, 0.06); + --border-subtle: rgba(255, 255, 255, 0.04); + --border-strong: rgba(255, 255, 255, 0.14); + --border-glass: rgba(255, 255, 255, 0.15); + + /* ───────────────────────────────────────────────────────────────────────── + Text Hierarchy — WCAG AAA on dark + ───────────────────────────────────────────────────────────────────────── */ + --text: #F8FAFC; /* 15.3:1 — Primary text */ + --text-secondary: #E2E8F0; /* 12.5:1 — Secondary text */ + --text-dim: #A1A1AA; /* 8:1 — Muted text */ + --text-muted: #71717A; /* 4.7:1 — Non-critical */ + --text-on-accent: #FFFFFF; + + /* ───────────────────────────────────────────────────────────────────────── + Brand Accent — Glowing orange + ───────────────────────────────────────────────────────────────────────── */ --accent: #FF5C00; - --accent-light: #FF7A2E; - --accent-dim: #E05200; - --accent-glow: rgba(255, 92, 0, 0.15); - --accent-subtle: rgba(255, 92, 0, 0.08); - --success: #4ADE80; - --success-dim: #22C55E; - --success-subtle: rgba(74, 222, 128, 0.1); + --accent-hover: #FF7A2E; + --accent-active: #E05200; + --accent-light: #FF8A4D; + --accent-muted: #FFB380; + --accent-subtle: rgba(255, 92, 0, 0.12); + --accent-glow: rgba(255, 92, 0, 0.25); + --accent-glass: rgba(255, 92, 0, 0.15); + + /* ───────────────────────────────────────────────────────────────────────── + Semantic Colors — Glowing status + ───────────────────────────────────────────────────────────────────────── */ + --success: #22C55E; + --success-hover: #16A34A; + --success-dim: #15803D; + --success-subtle: rgba(34, 197, 94, 0.12); + --success-muted: rgba(34, 197, 94, 0.2); + --success-glow: rgba(34, 197, 94, 0.3); + --error: #EF4444; + --error-hover: #DC2626; --error-dim: #B91C1C; --error-subtle: rgba(239, 68, 68, 0.1); - --warning: #F59E0B; + --error-muted: rgba(239, 68, 68, 0.18); + --error-glow: rgba(239, 68, 68, 0.25); + + --warning: #FBBF24; + --warning-hover: #F59E0B; --warning-dim: #D97706; - --warning-subtle: rgba(245, 158, 11, 0.1); - --info: #3B82F6; + --warning-subtle: rgba(251, 191, 36, 0.1); + --warning-muted: rgba(251, 191, 36, 0.18); + + --info: #60A5FA; + --info-hover: #3B82F6; --info-dim: #2563EB; - --info-subtle: rgba(59, 130, 246, 0.1); - --success-muted: rgba(74, 222, 128, 0.25); - --error-muted: rgba(239, 68, 68, 0.25); - --warning-muted: rgba(245, 158, 11, 0.25); - --info-muted: rgba(59, 130, 246, 0.25); - --border-strong: #4A4644; - --card-highlight: rgba(255, 255, 255, 0.04); - --agent-bg: #1A1817; - --user-bg: #2A1A08; - --shadow-xs: 0 1px 2px rgba(0,0,0,0.3); - --shadow-sm: 0 1px 3px rgba(0,0,0,0.4), 0 1px 2px rgba(0,0,0,0.3); - --shadow-md: 0 4px 12px rgba(0,0,0,0.4), 0 2px 4px rgba(0,0,0,0.3); - --shadow-lg: 0 12px 28px rgba(0,0,0,0.35), 0 4px 10px rgba(0,0,0,0.3); - --shadow-xl: 0 20px 40px rgba(0,0,0,0.4), 0 8px 16px rgba(0,0,0,0.3); - --shadow-glow: 0 0 80px rgba(0,0,0,0.6); - --shadow-accent: 0 4px 16px rgba(255, 92, 0, 0.2); - --shadow-inset: inset 0 1px 0 rgba(255,255,255,0.03); + --info-subtle: rgba(96, 165, 250, 0.1); + --info-muted: rgba(96, 165, 250, 0.18); + --info-glow: rgba(96, 165, 250, 0.25); + + /* ───────────────────────────────────────────────────────────────────────── + Glassmorphism — Dark glass effects + ───────────────────────────────────────────────────────────────────────── */ + --glass-bg: rgba(22, 22, 30, 0.72); + --glass-bg-strong: rgba(22, 22, 30, 0.88); + --glass-bg-subtle: rgba(22, 22, 30, 0.48); + --glass-border: rgba(255, 255, 255, 0.1); + --glass-blur: 20px; + --glass-blur-strong: 32px; + --glass-blur-subtle: 10px; + + /* ───────────────────────────────────────────────────────────────────────── + Gradients — Aurora night mode + ───────────────────────────────────────────────────────────────────────── */ + --gradient-accent: linear-gradient(135deg, #FF5C00 0%, #FF7A2E 50%, #FF8A4D 100%); + --gradient-accent-subtle: linear-gradient(135deg, rgba(255, 92, 0, 0.15) 0%, rgba(255, 122, 46, 0.08) 100%); + --gradient-success: linear-gradient(135deg, #22C55E 0%, #4ADE80 100%); + --gradient-mesh: + radial-gradient(at 20% 30%, rgba(255, 92, 0, 0.08) 0px, transparent 50%), + radial-gradient(at 80% 10%, rgba(96, 165, 250, 0.06) 0px, transparent 50%), + radial-gradient(at 10% 60%, rgba(34, 197, 94, 0.05) 0px, transparent 50%), + radial-gradient(at 80% 60%, rgba(168, 85, 247, 0.05) 0px, transparent 50%), + radial-gradient(at 20% 90%, rgba(255, 92, 0, 0.06) 0px, transparent 50%), + radial-gradient(at 80% 90%, rgba(96, 165, 250, 0.04) 0px, transparent 50%); + --gradient-card-shine: linear-gradient( + 105deg, + transparent 40%, + rgba(255, 255, 255, 0.06) 45%, + rgba(255, 255, 255, 0.06) 50%, + transparent 55% + ); + --gradient-glow-line: linear-gradient( + 90deg, + transparent 0%, + rgba(255, 92, 0, 0.4) 50%, + transparent 100% + ); + + /* ───────────────────────────────────────────────────────────────────────── + Shadows — Deep depth + ───────────────────────────────────────────────────────────────────────── */ + --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4); + --shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.5), 0 2px 4px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.45), 0 4px 12px rgba(0, 0, 0, 0.35); + --shadow-xl: 0 24px 48px rgba(0, 0, 0, 0.5), 0 8px 16px rgba(0, 0, 0, 0.4); + --shadow-2xl: 0 32px 64px rgba(0, 0, 0, 0.55), 0 12px 24px rgba(0, 0, 0, 0.45); + + /* Colored shadows with glow */ + --shadow-accent: 0 8px 32px rgba(255, 92, 0, 0.25), 0 0 48px rgba(255, 92, 0, 0.1); + --shadow-success: 0 8px 32px rgba(34, 197, 94, 0.2), 0 0 48px rgba(34, 197, 94, 0.08); + --shadow-error: 0 8px 32px rgba(239, 68, 68, 0.2), 0 0 48px rgba(239, 68, 68, 0.08); + --shadow-glow: 0 0 80px rgba(0, 0, 0, 0.6); + --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.04); + --shadow-inset-dark: inset 0 1px 0 rgba(0, 0, 0, 0.2); + + /* ───────────────────────────────────────────────────────────────────────── + Chat-specific colors + ───────────────────────────────────────────────────────────────────────── */ + --agent-bg: #12121A; + --user-bg: #1A1208; + --agent-bg-glass: rgba(18, 18, 26, 0.8); + --user-bg-glass: rgba(26, 18, 8, 0.8); } +/* ═══════════════════════════════════════════════════════════════════════════ + BASE RESET & GLOBAL STYLES + ═══════════════════════════════════════════════════════════════════════════ */ + * { margin: 0; padding: 0; box-sizing: border-box; } -html { scroll-behavior: smooth; } +html { + scroll-behavior: smooth; + -webkit-text-size-adjust: 100%; +} body { font-family: var(--font-sans); @@ -151,107 +363,237 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; font-size: 14px; - line-height: 1.5; + line-height: 1.55; letter-spacing: -0.01em; + /* Aurora mesh gradient background */ + background-image: var(--gradient-mesh); + background-attachment: fixed; } -/* Mono text utility — only for code/data */ +/* Mono text utility — code/data only */ .font-mono, code, pre, .tool-pre, .tool-card-name, .detail-value, -.stat-value, .conn-badge, .version { font-family: var(--font-mono); } +.stat-value, .conn-badge, .version { + font-family: var(--font-mono); +} -/* Scrollbar — Webkit (Chrome, Edge, Safari) */ -::-webkit-scrollbar { width: 6px; height: 6px; } +/* ═══════════════════════════════════════════════════════════════════════════ + SCROLLBAR STYLING + ═══════════════════════════════════════════════════════════════════════════ */ + +/* Webkit (Chrome, Edge, Safari) */ +::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: transparent; } -::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } -::-webkit-scrollbar-thumb:hover { background: var(--border-light); } +::-webkit-scrollbar-thumb { + background: var(--border-strong); + border-radius: var(--radius-full); + border: 2px solid transparent; + background-clip: padding-box; +} +::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); + border: 2px solid transparent; + background-clip: padding-box; +} -/* Scrollbar — Firefox */ +/* Firefox */ * { scrollbar-width: thin; - scrollbar-color: var(--border) transparent; + scrollbar-color: var(--border-strong) transparent; } +/* ═══════════════════════════════════════════════════════════════════════════ + SELECTION & THEME TRANSITIONS + ═══════════════════════════════════════════════════════════════════════════ */ + ::selection { background: var(--accent); - color: var(--bg-primary); + color: var(--text-on-accent); } -/* Theme transition — smooth switch between light/dark */ +/* Smooth theme switching */ body { - transition: background-color 0.3s ease, color 0.3s ease; -} -.sidebar, .main-content, .card, .modal, .tool-card, .toast, .page-header { - transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease; + transition: + background-color 0.4s var(--ease-smooth), + color 0.4s var(--ease-smooth); } -/* Tighter letter spacing for headings */ -h1, h2, h3, .card-header, .stat-value, .page-header h2 { letter-spacing: -0.02em; } -.nav-section-title, .badge, th { letter-spacing: 0.04em; } +.sidebar, .main-content, .card, .modal, .tool-card, .toast, .page-header, +.stat-card, .badge, .btn, .nav-item, input, select, textarea { + transition: + background-color 0.3s var(--ease-smooth), + border-color 0.3s var(--ease-smooth), + color 0.3s var(--ease-smooth), + box-shadow 0.3s var(--ease-smooth); +} + +/* ═══════════════════════════════════════════════════════════════════════════ + TYPOGRAPHY UTILITIES + ═══════════════════════════════════════════════════════════════════════════ */ + +h1, h2, h3, h4, h5, h6 { + font-weight: 600; + letter-spacing: -0.02em; + line-height: 1.3; +} + +.card-header, .stat-value, .page-header h2 { + letter-spacing: -0.02em; +} + +.nav-section-title, .badge, th { + letter-spacing: 0.05em; + text-transform: uppercase; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + FOCUS STATES — Accessible double-ring with glow + ═══════════════════════════════════════════════════════════════════════════ */ -/* Focus styles — accessible double-ring with glow */ :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 4px var(--accent-glow); } -button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { + +button:focus-visible, a:focus-visible, input:focus-visible, +select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 4px var(--accent-glow); + transition: box-shadow 0.15s ease; } -/* Entrance animations */ +/* ═══════════════════════════════════════════════════════════════════════════ + ANIMATIONS — Premium motion design + ═══════════════════════════════════════════════════════════════════════════ */ + +/* Fade animations */ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } +@keyframes fadeOut { + from { opacity: 1; } + to { opacity: 0; } +} + +/* Slide animations */ @keyframes slideUp { - from { opacity: 0; transform: translateY(8px); } + from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideDown { - from { opacity: 0; transform: translateY(-8px); } + from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } } +@keyframes slideLeft { + from { opacity: 0; transform: translateX(12px); } + to { opacity: 1; transform: translateX(0); } +} + +@keyframes slideRight { + from { opacity: 0; transform: translateX(-12px); } + to { opacity: 1; transform: translateX(0); } +} + +/* Scale animations */ @keyframes scaleIn { - from { opacity: 0; transform: scale(0.95); } + from { opacity: 0; transform: scale(0.92); } to { opacity: 1; transform: scale(1); } } +@keyframes scaleOut { + from { opacity: 1; transform: scale(1); } + to { opacity: 0; transform: scale(0.92); } +} + +/* Spring animations */ +@keyframes springIn { + 0% { opacity: 0; transform: scale(0.9) translateY(10px); } + 70% { transform: scale(1.02) translateY(-2px); } + 100% { opacity: 1; transform: scale(1) translateY(0); } +} + +/* Staggered card entry animation */ +@keyframes cardEntry { + from { + opacity: 0; + transform: translateY(16px) scale(0.97); + filter: blur(4px); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + filter: blur(0); + } +} + +.animate-entry { + animation: cardEntry 0.5s var(--ease-spring) both; +} + +.stagger-1 { animation-delay: 0.05s; } +.stagger-2 { animation-delay: 0.1s; } +.stagger-3 { animation-delay: 0.15s; } +.stagger-4 { animation-delay: 0.2s; } +.stagger-5 { animation-delay: 0.25s; } +.stagger-6 { animation-delay: 0.3s; } +.stagger-7 { animation-delay: 0.35s; } +.stagger-8 { animation-delay: 0.4s; } + +/* Shimmer loading effect */ @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } +@keyframes glow-pulse { + 0%, 100% { opacity: 0.5; } + 50% { opacity: 1; } +} + +/* Pulse ring effect */ @keyframes pulse-ring { 0% { box-shadow: 0 0 0 0 currentColor; } - 70% { box-shadow: 0 0 0 4px transparent; } + 70% { box-shadow: 0 0 0 6px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } } +/* Spin animation */ @keyframes spin { to { transform: rotate(360deg); } } -/* Staggered card entry animation */ -@keyframes cardEntry { - from { opacity: 0; transform: translateY(12px) scale(0.98); } - to { opacity: 1; transform: translateY(0) scale(1); } +/* Float animation */ +@keyframes float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-4px); } } -.animate-entry { animation: cardEntry 0.35s var(--ease-spring) both; } -.stagger-1 { animation-delay: 0.05s; } -.stagger-2 { animation-delay: 0.10s; } -.stagger-3 { animation-delay: 0.15s; } -.stagger-4 { animation-delay: 0.20s; } -.stagger-5 { animation-delay: 0.25s; } -.stagger-6 { animation-delay: 0.30s; } -/* Skeleton loading animation */ +/* Gradient flow animation */ +@keyframes gradient-flow { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +/* Glow line animation */ +@keyframes glow-line { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } +} + +/* Skeleton loading */ .skeleton { - background: linear-gradient(90deg, var(--surface) 25%, var(--surface2) 50%, var(--surface) 75%); + background: linear-gradient( + 90deg, + var(--surface) 25%, + var(--surface2) 50%, + var(--surface) 75% + ); background-size: 200% 100%; animation: shimmer 1.5s ease-in-out infinite; border-radius: var(--radius-sm); @@ -263,76 +605,154 @@ button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible .skeleton-card { height: 100px; border-radius: var(--radius-lg); } .skeleton-avatar { width: 32px; height: 32px; border-radius: 50%; } -/* Print styles */ -@media print { - .sidebar, .sidebar-overlay, .mobile-menu-btn, .toast-container, .btn { display: none !important; } - .main-content { margin: 0; max-width: 100%; } - body { background: #fff; color: #000; } +/* ═══════════════════════════════════════════════════════════════════════════ + GLASSMORPHISM UTILITY CLASSES + ═══════════════════════════════════════════════════════════════════════════ */ + +.glass { + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur)); + -webkit-backdrop-filter: blur(var(--glass-blur)); + border: 1px solid var(--glass-border); } -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { - animation-duration: 0.01ms !important; - transition-duration: 0.01ms !important; - } +.glass-strong { + background: var(--glass-bg-strong); + backdrop-filter: blur(var(--glass-blur-strong)); + -webkit-backdrop-filter: blur(var(--glass-blur-strong)); + border: 1px solid var(--glass-border); +} + +.glass-subtle { + background: var(--glass-bg-subtle); + backdrop-filter: blur(var(--glass-blur-subtle)); + -webkit-backdrop-filter: blur(var(--glass-blur-subtle)); + border: 1px solid var(--border-light); } /* ═══════════════════════════════════════════════════════════════════════════ - UI/UX Pro Max Optimizations — Accessibility & Interaction Enhancement + INTERACTION UTILITIES ═══════════════════════════════════════════════════════════════════════════ */ -/* Cursor pointer for all clickable elements (CRITICAL) */ +/* Cursor pointer for all clickable elements */ .clickable, [role="button"], [onclick], .nav-item, .card[onclick], .stat-card[onclick], .quick-action-card, .badge[onclick], .dropdown-item, .menu-item, .list-item[onclick] { cursor: pointer; } -/* Ensure buttons always show pointer */ button, .btn, [type="button"], [type="submit"], [type="reset"] { cursor: pointer; } -/* Disabled state cursor */ :disabled, .disabled, [aria-disabled="true"] { cursor: not-allowed !important; } -/* Focus ring enhancement for keyboard navigation (WCAG 2.4.7) */ -a:focus-visible, button:focus-visible, input:focus-visible, -select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible { - outline: 2px solid var(--accent) !important; - outline-offset: 2px !important; - box-shadow: 0 0 0 4px var(--accent-glow) !important; - transition: box-shadow 0.15s ease; +/* Hover lift effect */ +.hover-lift { + transition: transform 0.2s var(--ease-smooth), box-shadow 0.2s var(--ease-smooth); } +.hover-lift:hover { + transform: translateY(-3px); + box-shadow: var(--shadow-lg); +} + +/* Hover glow effect */ +.hover-glow { + transition: box-shadow 0.25s var(--ease-smooth); +} +.hover-glow:hover { + box-shadow: 0 0 30px var(--accent-glow); +} + +/* Loading button state */ +.btn-loading { + position: relative; + color: transparent !important; + pointer-events: none; +} +.btn-loading::after { + content: ''; + position: absolute; + width: 16px; + height: 16px; + border: 2px solid var(--border); + border-top-color: currentColor; + border-radius: 50%; + animation: spin 0.6s linear infinite; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + ACCESSIBILITY UTILITIES + ═══════════════════════════════════════════════════════════════════════════ */ /* Skip link for keyboard users */ .skip-link { position: absolute; - top: -40px; - left: 0; + top: -100px; + left: 8px; background: var(--accent); - color: var(--bg-primary); - padding: 8px 16px; - z-index: 10000; - transition: top 0.2s; + color: var(--text-on-accent); + padding: 10px 16px; + border-radius: var(--radius-md); + z-index: var(--z-max); + font-weight: 600; + transition: top 0.2s var(--ease-smooth); } .skip-link:focus { - top: 0; + top: 8px; } -/* Minimum touch target size (WCAG 2.5.5 — 44x44px) */ -@media (pointer: coarse) { - button, .btn, .nav-item, .badge[onclick], .toggle, - input[type="checkbox"], input[type="radio"], - .form-input, .form-select, .form-textarea { - min-height: 44px; - min-width: 44px; +/* Screen reader only */ +.sr-only, .visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* Truncate text */ +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.line-clamp-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.line-clamp-3 { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + MEDIA QUERIES + ═══════════════════════════════════════════════════════════════════════════ */ + +/* Reduced motion */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; } } -/* High contrast mode support */ +/* High contrast mode */ @media (prefers-contrast: high) { :root, [data-theme="light"], [data-theme="dark"] { --border: currentColor; @@ -356,114 +776,34 @@ select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible { } } -/* Z-index scale (prevent z-index conflicts) */ -:root { - --z-base: 1; - --z-dropdown: 100; - --z-sticky: 200; - --z-fixed: 300; - --z-modal-backdrop: 400; - --z-modal: 500; - --z-popover: 600; - --z-tooltip: 700; - --z-toast: 800; - --z-max: 9999; +/* Touch device optimizations */ +@media (pointer: coarse) { + button, .btn, .nav-item, .badge[onclick], .toggle, + input[type="checkbox"], input[type="radio"], + .form-input, .form-select, .form-textarea { + min-height: 44px; + min-width: 44px; + } } -/* Utility classes for common patterns */ -.truncate { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; +/* Print styles */ +@media print { + .sidebar, .sidebar-overlay, .mobile-menu-btn, + .toast-container, .btn, .modal-backdrop { + display: none !important; + } + .main-content { margin: 0; max-width: 100%; } + body { background: #fff; color: #000; } } -.line-clamp-2 { - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; -} +/* ═══════════════════════════════════════════════════════════════════════════ + DARK MODE IMAGE ADJUSTMENTS + ═══════════════════════════════════════════════════════════════════════════ */ -.line-clamp-3 { - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; -} - -/* Screen reader only */ -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -/* Focus visible only (not on click) */ -.focus-visible:focus:not(:focus-visible) { - outline: none; - box-shadow: none; -} - -/* Smooth hover transitions (150-300ms per guidelines) */ -.hover-lift { - transition: transform 0.2s var(--ease-smooth), box-shadow 0.2s var(--ease-smooth); -} -.hover-lift:hover { - transform: translateY(-2px); - box-shadow: var(--shadow-md); -} - -.hover-glow { - transition: box-shadow 0.2s var(--ease-smooth); -} -.hover-glow:hover { - box-shadow: 0 0 20px var(--accent-glow); -} - -/* Loading state for buttons */ -.btn-loading { - position: relative; - color: transparent !important; - pointer-events: none; -} -.btn-loading::after { - content: ''; - position: absolute; - width: 16px; - height: 16px; - border: 2px solid var(--border); - border-top-color: currentColor; - border-radius: 50%; - animation: spin 0.6s linear infinite; -} - -/* Improved dark mode image handling */ [data-theme="dark"] img { opacity: 0.95; - transition: opacity 0.2s; + transition: opacity 0.2s var(--ease-smooth); } [data-theme="dark"] img:hover { opacity: 1; } - -/* Dark mode specific adjustments */ -[data-theme="dark"] { - --agent-bg: #1A1A1A; - --user-bg: #2A1A08; - --shadow-xs: 0 1px 2px rgba(0,0,0,0.5); - --shadow-sm: 0 1px 3px rgba(0,0,0,0.6), 0 1px 2px rgba(0,0,0,0.4); - --shadow-md: 0 4px 12px rgba(0,0,0,0.5), 0 2px 4px rgba(0,0,0,0.4); - --shadow-lg: 0 12px 28px rgba(0,0,0,0.5), 0 4px 10px rgba(0,0,0,0.4); - --shadow-xl: 0 20px 40px rgba(0,0,0,0.6), 0 8px 16px rgba(0,0,0,0.4); - --shadow-glow: 0 0 80px rgba(0,0,0,0.8); - --shadow-accent: 0 4px 20px rgba(255, 92, 0, 0.25); - --shadow-inset: inset 0 1px 0 rgba(255,255,255,0.05); - --card-highlight: rgba(255, 255, 255, 0.03); -} - diff --git a/crates/openfang-api/static/index_head.html b/crates/openfang-api/static/index_head.html index bb4456f..7b30f2d 100644 --- a/crates/openfang-api/static/index_head.html +++ b/crates/openfang-api/static/index_head.html @@ -2,14 +2,46 @@ - - - + + + + + + + + + OpenFang Dashboard + + - + + + + + + + + + diff --git a/crates/openfang-kernel/src/presence.rs b/crates/openfang-kernel/src/presence.rs index bb9bc46..0272581 100644 --- a/crates/openfang-kernel/src/presence.rs +++ b/crates/openfang-kernel/src/presence.rs @@ -360,14 +360,25 @@ impl PresenceManager { .clone(); // Check if user is already in another session - if let Some(existing_user) = self.users.get(&connection_id) { - if existing_user.session_id != session_id { - // Leave the previous session first - self.leave_session(connection_id)?; - } else { - // Already in this session - return Ok(existing_user.clone()); + // Note: We need to clone the data and drop the reference before calling leave_session + // to avoid a deadlock with DashMap + let should_leave = { + let user_ref = self.users.get(&connection_id); + match user_ref { + Some(u) => { + if u.session_id == session_id { + // Already in this session - return the user + return Ok(u.clone()); + } + true // Need to leave the old session + } + None => false } + }; + // user_ref is now dropped, we can safely call leave_session + + if should_leave { + self.leave_session(connection_id)?; } // Check max participants @@ -535,11 +546,11 @@ impl PresenceManager { for mut entry in self.users.iter_mut() { let user = entry.value_mut(); let elapsed = now.signed_duration_since(user.last_activity); - let elapsed_secs = elapsed.num_seconds() as u64; + let elapsed_ms = elapsed.num_milliseconds() as u128; - let new_status = if elapsed_secs > self.config.away_timeout.as_secs() { + let new_status = if elapsed_ms > self.config.away_timeout.as_millis() { PresenceStatus::Away - } else if elapsed_secs > self.config.idle_timeout.as_secs() { + } else if elapsed_ms > self.config.idle_timeout.as_millis() { PresenceStatus::Idle } else { PresenceStatus::Active @@ -566,8 +577,9 @@ impl PresenceManager { for entry in self.users.iter() { let user = entry.value(); let elapsed = now.signed_duration_since(user.last_activity); + let elapsed_ms = elapsed.num_milliseconds() as u64; - if elapsed.num_seconds() as u64 > self.config.cleanup_timeout.as_secs() { + if u128::from(elapsed_ms) > self.config.cleanup_timeout.as_millis() { removed.push(user.connection_id); } }