From f04fef916f4048e0f2f8ac5fedb032ec8c518df1 Mon Sep 17 00:00:00 2001 From: zhaoxi Date: Mon, 1 Jun 2026 03:30:30 +0000 Subject: [PATCH] =?UTF-8?q?style(frontend):=E4=BC=98=E5=8C=96=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=95=88=E6=9E=9C=201.=E5=AF=B9=E4=BA=8EUI=E7=9A=84?= =?UTF-8?q?=E9=85=8D=E8=89=B2=E5=92=8C=E5=B8=83=E5=B1=80=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=BA=86=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.tsx | 19 +- frontend/src/components/Auth/AuthPage.tsx | 191 ++++++++++-------- frontend/src/components/Chat/ChatPanel.tsx | 99 +++++---- frontend/src/components/Chat/LeftPanel.tsx | 111 +++++----- .../src/components/Chat/WorkflowListView.tsx | 173 +++++++++------- .../components/Layout/CollapsibleSidebar.tsx | 11 +- frontend/src/components/Layout/TopBar.tsx | 84 ++++---- .../components/Settings/SettingsLayout.tsx | 18 +- frontend/src/i18n/locales/en.json | 4 +- frontend/src/i18n/locales/zh.json | 4 +- frontend/src/index.css | 154 +++++++------- 11 files changed, 452 insertions(+), 416 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index b8a51be..a8aa2f2 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -28,7 +28,6 @@ function App() { const { loadSessions } = useChatStore(); - // Initialize theme on mount useEffect(() => { applyTheme(); const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); @@ -37,14 +36,12 @@ function App() { return () => mediaQuery.removeEventListener('change', handler); }, [applyTheme]); - // Sync persisted locale to i18next on mount useEffect(() => { if (locale && i18n.language !== locale) { i18n.changeLanguage(locale); } }, [locale]); - // Check auth and load sessions useEffect(() => { const token = localStorage.getItem('token'); if (token) { @@ -75,11 +72,9 @@ function App() {
{mode === 'work' && workTab === 'chat' && ( -
-
- - -
+
+ +
)} @@ -101,22 +96,22 @@ function WorkflowShell() { if (selectedWorkflow === 'new') { return ( - <> +
setSelectedWorkflow(null)} onSuccess={(traceId: string) => setSelectedWorkflow(traceId)} /> - +
); } if (selectedWorkflow) { return ( - <> +
- +
); } diff --git a/frontend/src/components/Auth/AuthPage.tsx b/frontend/src/components/Auth/AuthPage.tsx index d063674..a23c0fc 100644 --- a/frontend/src/components/Auth/AuthPage.tsx +++ b/frontend/src/components/Auth/AuthPage.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import apiClient from '../../api/client'; -import { Zap, ArrowRight, ShieldCheck } from 'lucide-react'; +import { ArrowRight } from 'lucide-react'; interface AuthPageProps { onLoginSuccess: () => void; @@ -49,96 +49,109 @@ export function AuthPage({ onLoginSuccess }: AuthPageProps) { }; return ( -
- {/* Background decoration */} -
-
-
-
- -
-
- {/* Logo */} -
-
- -
-

{t('app.name')}

-

{t('app.tagline')}

-
- -
-
- -

- {isLogin ? t('auth.welcomeBack') : t('auth.createAccount')} -

-
- - {error && ( -
- {error} -
- )} - -
-
- - setUserName(e.target.value)} - className="w-full px-4 py-2.5 bg-bg-input border border-border-primary rounded-xl focus:outline-none focus:ring-2 focus:ring-accent/20 focus:border-accent transition-all text-text-primary placeholder:text-text-muted/60 text-sm" - placeholder={t('auth.usernamePlaceholder')} - required - /> -
- -
- - setPassword(e.target.value)} - className="w-full px-4 py-2.5 bg-bg-input border border-border-primary rounded-xl focus:outline-none focus:ring-2 focus:ring-accent/20 focus:border-accent transition-all text-text-primary placeholder:text-text-muted/60 text-sm" - placeholder={t('auth.passwordPlaceholder')} - required - /> -
- - -
- -
- {isLogin ? t('auth.noAccount') : t('auth.hasAccount')}{' '} - -
-
- -

+

+
+ {/* Left: Brand */} +
+
+

+ KiloStar +

+

{t('app.tagline')}

+
+
+
+ Multi-Agent Orchestration +
+
+
+ Visual Pipeline Builder +
+
+
+ Intelligent Monitoring +
+
+
+ + {/* Right: Card */} +
+

+ {isLogin ? t('auth.welcomeBack') : t('auth.createAccount')} +

+

+ {isLogin ? t('auth.enterCredentials') : t('auth.signUpToStart')} +

+ + {error && ( +
+ {error} +
+ )} + +
+
+ + setUserName(e.target.value)} + className="w-full px-3.5 py-3 rounded-[10px] border border-border-primary bg-bg-primary text-sm text-text-primary placeholder:text-[#bbb5ae] outline-none transition-all focus:border-accent focus:shadow-[0_0_0_3px_rgba(156,175,136,0.1)]" + placeholder={t('auth.usernamePlaceholder')} + required + /> +
+ +
+ + setPassword(e.target.value)} + className="w-full px-3.5 py-3 rounded-[10px] border border-border-primary bg-bg-primary text-sm text-text-primary placeholder:text-[#bbb5ae] outline-none transition-all focus:border-accent focus:shadow-[0_0_0_3px_rgba(156,175,136,0.1)]" + placeholder={t('auth.passwordPlaceholder')} + required + /> +
+ + +
+ +
+ or +
+ +

+ {isLogin ? t('auth.noAccount') : t('auth.hasAccount')}{' '} + +

diff --git a/frontend/src/components/Chat/ChatPanel.tsx b/frontend/src/components/Chat/ChatPanel.tsx index 14787ad..3069dc6 100644 --- a/frontend/src/components/Chat/ChatPanel.tsx +++ b/frontend/src/components/Chat/ChatPanel.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { MessageSquare, Activity, ArrowUp, Plus, Sparkles, Code, FileText, Search } from 'lucide-react'; +import { MessageSquare, Activity, ArrowUp, Plus, Sparkles, Code, FileText, Search, User } from 'lucide-react'; import { useChatStore } from '../../store/useChatStore'; export function ChatPanel() { @@ -64,36 +64,32 @@ export function ChatPanel() { if (!activeSessionId) { return ( -
- {/* Decorative background */} -
- +
-
- +
+
-

{t('chat.assistantName')}

-

+

{t('chat.assistantName')}

+

{t('chat.selectChat')}

- {/* Quick Actions */} -
+
{quickActions.map((action) => ( ))}
-

+

{t('chat.mistakeWarning')}

diff --git a/frontend/src/components/Chat/LeftPanel.tsx b/frontend/src/components/Chat/LeftPanel.tsx index b745782..4235f51 100644 --- a/frontend/src/components/Chat/LeftPanel.tsx +++ b/frontend/src/components/Chat/LeftPanel.tsx @@ -69,9 +69,9 @@ export function LeftPanel({ activeTab }: LeftPanelProps) { const isChats = activeTab === 'chats'; return ( -
-
- +
+
+ {isChats ? t('chat.chatHistory') : t('nav.workflow')}
-
+
{isChats ? ( sessions.length === 0 ? (
{t('chat.noHistory')}
) : ( - sessions.map((session) => ( -
setActiveSessionId(session.id)} - className={`group flex items-center gap-2.5 px-3 py-2.5 rounded-lg cursor-pointer transition-all ${ - activeSessionId === session.id - ? 'bg-accent-light text-accent' - : 'hover:bg-bg-hover text-text-secondary' - }`} - > - -
-

- {session.title} -

-

- {new Date(session.updatedAt).toLocaleDateString()} -

-
- -
- )) +
+ +
+
+

+ {session.title} +

+
+ +
+ ); + }) ) ) : ( loadingWorkflows ? ( @@ -129,32 +131,29 @@ export function LeftPanel({ activeTab }: LeftPanelProps) { {t('workflow.noWorkflows')}
) : ( - workflows.map((wf) => ( -
setSelectedWorkflow(wf.trace_id)} - className={`group flex items-center gap-2.5 px-3 py-2.5 rounded-lg cursor-pointer transition-all ${ - selectedWorkflow === wf.trace_id - ? 'bg-accent-light' - : 'hover:bg-bg-hover' - }`} - > - -
-

- {wf.title || t('common.unnamed')} -

-
- - {wf.trace_id.slice(-8)} + workflows.map((wf) => { + const isActive = selectedWorkflow === wf.trace_id; + return ( +
setSelectedWorkflow(wf.trace_id)} + className={`group flex items-center gap-2.5 px-2.5 py-2 rounded-lg cursor-pointer transition-all mb-px ${ + isActive + ? 'bg-bg-card shadow-[0_1px_3px_rgba(0,0,0,0.04)]' + : 'hover:bg-white/60 dark:hover:bg-white/[0.04]' + }`} + > +
+ +
+
+

+ {wf.title || t('common.unnamed')} +

-
- )) + ); + }) ) )}
diff --git a/frontend/src/components/Chat/WorkflowListView.tsx b/frontend/src/components/Chat/WorkflowListView.tsx index 5de13ff..4f6aaaf 100644 --- a/frontend/src/components/Chat/WorkflowListView.tsx +++ b/frontend/src/components/Chat/WorkflowListView.tsx @@ -2,7 +2,6 @@ import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import apiClient from '../../api/client'; import type { Workflow } from '../../types'; -import { PlayCircle, CheckCircle, XCircle, Clock, ArrowRight, Zap } from 'lucide-react'; interface WorkflowListViewProps { onSelectWorkflow: (id: string) => void; @@ -37,11 +36,24 @@ export function WorkflowListView({ onSelectWorkflow }: WorkflowListViewProps) { return () => clearInterval(intervalId); }, []); - const getStatusMeta = (status?: string) => { - if (status === 'completed') return { icon: CheckCircle, color: 'text-success', bg: 'bg-success-bg', border: 'border-success/20', glow: 'group-hover:shadow-success/20' }; - if (status === 'failed') return { icon: XCircle, color: 'text-danger', bg: 'bg-danger-bg', border: 'border-danger/20', glow: 'group-hover:shadow-danger/20' }; - if (status && status.includes('working')) return { icon: PlayCircle, color: 'text-accent', bg: 'bg-accent-light', border: 'border-accent/20', glow: 'group-hover:shadow-accent/20' }; - return { icon: Clock, color: 'text-text-muted', bg: 'bg-bg-secondary', border: 'border-border-primary', glow: 'group-hover:shadow-border-primary' }; + const getStatusStyle = (status?: string) => { + if (status && status.includes('working')) { + return { label: t('workflow.status.running'), bg: 'bg-[rgba(156,175,136,0.12)]', text: 'text-[#7a8e6a]' }; + } + if (status === 'completed') { + return { label: t('workflow.status.completed'), bg: 'bg-[rgba(196,168,130,0.12)]', text: 'text-[#9a7d5e]' }; + } + if (status === 'failed') { + return { label: t('workflow.status.failed'), bg: 'bg-[rgba(196,145,122,0.1)]', text: 'text-[#a0705a]' }; + } + return { label: t('workflow.status.waiting'), bg: 'bg-[rgba(138,154,170,0.1)]', text: 'text-[#6e7d8d]' }; + }; + + const stats = { + total: workflows.length, + running: workflows.filter((w) => w.status?.includes('working')).length, + completed: workflows.filter((w) => w.status === 'completed').length, + queued: workflows.filter((w) => !w.status || (!w.status.includes('working') && w.status !== 'completed' && w.status !== 'failed')).length, }; if (loading) { @@ -56,80 +68,85 @@ export function WorkflowListView({ onSelectWorkflow }: WorkflowListViewProps) { } return ( -
-
-
-
-
- -

{t('workflow.workflows')}

-
-

{t('workflow.manageWorkflows')}

-
- +
+ {/* Header */} +
+
+

{t('workflow.workflows')}

+

{t('workflow.manageWorkflows')}

- - {workflows.length === 0 ? ( -
-
- -
-

{t('workflow.noWorkflows')}

-

{t('workflow.workflowsAppearHere')}

-
- ) : ( -
- {workflows.map((wf) => { - const meta = getStatusMeta(wf.status); - const Icon = meta.icon; - return ( -
onSelectWorkflow(wf.trace_id)} - className={`group relative bg-bg-card rounded-2xl p-5 border border-border-primary card-hover cursor-pointer overflow-hidden ${meta.glow}`} - > - {/* Status glow on hover */} -
- -
-
-
- -
- -
- -

- {wf.title || t('common.unnamed')} -

- - {wf.command && ( -

- {wf.command} -

- )} - -
- - {wf.trace_id.slice(0, 8)}... - - {wf.created_at && ( - {new Date(wf.created_at).toLocaleDateString()} - )} -
-
-
- ); - })} -
- )} +
+ + {/* Stats */} +
+
+
{t('workflow.total')}
+
{stats.total}
+
+
+
{t('workflow.status.running')}
+
{stats.running}
+
+
+
{t('workflow.status.completed')}
+
{stats.completed}
+
+
+
{t('workflow.queued')}
+
{stats.queued}
+
+
+ + {workflows.length === 0 ? ( +
+
+ +
+

{t('workflow.noWorkflows')}

+

{t('workflow.workflowsAppearHere')}

+
+ ) : ( +
+ {workflows.map((wf) => { + const style = getStatusStyle(wf.status); + return ( +
onSelectWorkflow(wf.trace_id)} + className="p-4 bg-bg-card rounded-xl border border-border-primary cursor-pointer transition-all hover:shadow-[0_4px_16px_rgba(0,0,0,0.05)] hover:-translate-y-0.5 hover:border-[#d5d0ca] dark:hover:border-white/10" + > +
+ + {style.label} + +
+

+ {wf.title || t('common.unnamed')} +

+ {wf.command && ( +

+ {wf.command} +

+ )} +
+ + {wf.trace_id.slice(-8)} + + {wf.created_at && ( + {new Date(wf.created_at).toLocaleDateString()} + )} +
+
+ ); + })} +
+ )}
); } diff --git a/frontend/src/components/Layout/CollapsibleSidebar.tsx b/frontend/src/components/Layout/CollapsibleSidebar.tsx index b32cdbb..dcbad9d 100644 --- a/frontend/src/components/Layout/CollapsibleSidebar.tsx +++ b/frontend/src/components/Layout/CollapsibleSidebar.tsx @@ -33,7 +33,7 @@ export function CollapsibleSidebar() { isSidebarOpen ? 'w-56' : 'w-14' }`} > -
+
{navItems.map((item) => { const isActive = activeTab === item.key; return ( @@ -42,18 +42,15 @@ export function CollapsibleSidebar() { onClick={() => setTab(item.key as any)} className={`w-full flex items-center mx-1.5 rounded-lg transition-all duration-200 group ${ isActive - ? 'bg-accent-light text-accent' - : 'text-text-muted hover:text-text-secondary hover:bg-bg-hover' + ? 'bg-white/50 dark:bg-white/[0.06] text-text-primary shadow-[0_1px_3px_rgba(0,0,0,0.04)]' + : 'text-text-muted hover:text-text-secondary hover:bg-white/40 dark:hover:bg-white/[0.04]' } ${isSidebarOpen ? 'px-3 py-2.5 gap-3' : 'px-0 py-2.5 justify-center'}`} style={{ width: isSidebarOpen ? 'calc(100% - 12px)' : 'calc(100% - 12px)' }} > - + {isSidebarOpen && ( {item.label} )} - {isActive && isSidebarOpen && ( -
- )} ); })} diff --git a/frontend/src/components/Layout/TopBar.tsx b/frontend/src/components/Layout/TopBar.tsx index c148397..42f4a68 100644 --- a/frontend/src/components/Layout/TopBar.tsx +++ b/frontend/src/components/Layout/TopBar.tsx @@ -36,83 +36,77 @@ export function TopBar() { }; return ( -
- {/* Left: Logo with status */} -
-
-
- +
+ {/* Left: Logo + Nav */} +
+
+
+
- + {t('app.name')}
-
- {t('app.name')} - {t('app.tagline')} -
-
- {/* Center: Mode Switch */} -
- - + {/* Center: Pill Nav */} +
+ + +
{/* Right: Actions */}
-
-
diff --git a/frontend/src/components/Settings/SettingsLayout.tsx b/frontend/src/components/Settings/SettingsLayout.tsx index dc56ff1..1776a6e 100644 --- a/frontend/src/components/Settings/SettingsLayout.tsx +++ b/frontend/src/components/Settings/SettingsLayout.tsx @@ -14,23 +14,25 @@ export function SettingsLayout() { ]; return ( -
+
-
-

{t('settings.settings')}

+
+ + {t('settings.settings')} +
-
+
{tabs.map((tab) => ( ))} diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 498ba45..186a7e0 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -88,7 +88,9 @@ "running": "Running", "completed": "Completed", "failed": "Failed" - } + }, + "total": "Total", + "queued": "Queued" }, "settings": { "settings": "Settings", diff --git a/frontend/src/i18n/locales/zh.json b/frontend/src/i18n/locales/zh.json index 1c34de4..369bb98 100644 --- a/frontend/src/i18n/locales/zh.json +++ b/frontend/src/i18n/locales/zh.json @@ -88,7 +88,9 @@ "running": "运行中", "completed": "已完成", "failed": "失败" - } + }, + "total": "总数", + "queued": "排队中" }, "settings": { "settings": "设置", diff --git a/frontend/src/index.css b/frontend/src/index.css index 1fb24c5..b841d31 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -38,72 +38,83 @@ --color-warning-bg: var(--warning-bg); --color-glow-purple: var(--glow-purple); --color-glow-cyan: var(--glow-cyan); + --color-clay: var(--clay); + --color-slate: var(--slate); + --color-terracotta: var(--terracotta); --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; } +/* ===== Morandi Light ===== */ :root { - --bg-primary: #fafafa; - --bg-secondary: #f4f4f5; - --bg-tertiary: #e4e4e7; - --bg-card: #ffffff; - --bg-sidebar: #f4f4f5; - --bg-topbar: rgba(255, 255, 255, 0.72); - --bg-input: #f4f4f5; - --bg-hover: #f4f4f5; - --bg-active: #eff6ff; - --bg-glass: rgba(255, 255, 255, 0.6); - --border-primary: #e4e4e7; - --border-secondary: #f4f4f5; - --text-primary: #18181b; - --text-secondary: #3f3f46; - --text-tertiary: #52525b; - --text-muted: #a1a1aa; - --accent: #4f46e5; - --accent-hover: #4338ca; - --accent-light: #e0e7ff; - --accent-text: #3730a3; - --accent-glow: rgba(79, 70, 229, 0.15); - --danger: #dc2626; - --danger-bg: #fef2f2; - --success: #16a34a; - --success-bg: #f0fdf4; - --warning: #d97706; - --warning-bg: #fffbeb; - --glow-purple: #a855f7; - --glow-cyan: #06b6d4; + --bg-primary: #f2f0ed; + --bg-secondary: #eae8e4; + --bg-tertiary: #e0ddd8; + --bg-card: #faf9f7; + --bg-sidebar: #eae8e4; + --bg-topbar: rgba(250, 249, 247, 0.85); + --bg-input: #f2f0ed; + --bg-hover: rgba(255, 255, 255, 0.4); + --bg-active: rgba(156, 175, 136, 0.08); + --bg-glass: rgba(250, 249, 247, 0.72); + --border-primary: #e0ddd8; + --border-secondary: #eae8e4; + --text-primary: #3d3d3d; + --text-secondary: #5a5a5a; + --text-tertiary: #8c8680; + --text-muted: #b5afa8; + --accent: #9caf88; + --accent-hover: #8a9e78; + --accent-light: rgba(156, 175, 136, 0.12); + --accent-text: #7a8e6a; + --accent-glow: rgba(156, 175, 136, 0.2); + --danger: #c4917a; + --danger-bg: rgba(196, 145, 122, 0.08); + --success: #7a8e6a; + --success-bg: rgba(122, 142, 106, 0.08); + --warning: #c4a882; + --warning-bg: rgba(196, 168, 130, 0.08); + --glow-purple: #8a9aaa; + --glow-cyan: #c4a882; + --clay: #c4a882; + --slate: #8a9aaa; + --terracotta: #c4917a; } +/* ===== Morandi Dark ===== */ .dark { - --bg-primary: #09090b; - --bg-secondary: #0f0f11; - --bg-tertiary: #18181b; - --bg-card: #131316; - --bg-sidebar: #0c0c0e; - --bg-topbar: rgba(9, 9, 11, 0.72); - --bg-input: #18181b; - --bg-hover: #1c1c1f; - --bg-active: rgba(79, 70, 229, 0.12); - --bg-glass: rgba(19, 19, 22, 0.6); - --border-primary: rgba(255, 255, 255, 0.08); - --border-secondary: rgba(255, 255, 255, 0.04); - --text-primary: #fafafa; - --text-secondary: #e4e4e7; - --text-tertiary: #a1a1aa; - --text-muted: #71717a; - --accent: #6366f1; - --accent-hover: #818cf8; - --accent-light: rgba(99, 102, 241, 0.15); - --accent-text: #a5b4fc; - --accent-glow: rgba(99, 102, 241, 0.25); - --danger: #f87171; - --danger-bg: rgba(248, 113, 113, 0.1); - --success: #4ade80; - --success-bg: rgba(74, 222, 128, 0.1); - --warning: #fbbf24; - --warning-bg: rgba(251, 191, 36, 0.1); - --glow-purple: #c084fc; - --glow-cyan: #67e8f9; + --bg-primary: #1c1b19; + --bg-secondary: #232220; + --bg-tertiary: #2d2b28; + --bg-card: #252421; + --bg-sidebar: #1e1d1b; + --bg-topbar: rgba(28, 27, 25, 0.85); + --bg-input: #2d2b28; + --bg-hover: rgba(255, 255, 255, 0.04); + --bg-active: rgba(156, 175, 136, 0.1); + --bg-glass: rgba(37, 36, 33, 0.72); + --border-primary: rgba(255, 255, 255, 0.06); + --border-secondary: rgba(255, 255, 255, 0.03); + --text-primary: #e8e6e3; + --text-secondary: #c8c5c0; + --text-tertiary: #a09c96; + --text-muted: #7a7772; + --accent: #a8bc94; + --accent-hover: #b8caa6; + --accent-light: rgba(156, 175, 136, 0.15); + --accent-text: #c4d4b4; + --accent-glow: rgba(156, 175, 136, 0.2); + --danger: #d4a894; + --danger-bg: rgba(196, 145, 122, 0.1); + --success: #9caf88; + --success-bg: rgba(156, 175, 136, 0.1); + --warning: #c4a882; + --warning-bg: rgba(196, 168, 130, 0.1); + --glow-purple: #a0aab8; + --glow-cyan: #c4b89e; + --clay: #c4a882; + --slate: #8a9aaa; + --terracotta: #c4917a; } html { @@ -118,16 +129,19 @@ body { -moz-osx-font-smoothing: grayscale; } -/* Dot pattern background for dark mode */ -.dark body::before { +/* Dot pattern background */ +body::before { content: ""; position: fixed; inset: 0; - background-image: radial-gradient(circle at 1px 1px, rgba(255,255,255,0.04) 1px, transparent 0); + background-image: radial-gradient(circle at 1px 1px, rgba(0, 0, 0, 0.012) 1px, transparent 0); background-size: 24px 24px; pointer-events: none; z-index: 0; } +.dark body::before { + background-image: radial-gradient(circle at 1px 1px, rgba(255, 255, 255, 0.015) 1px, transparent 0); +} /* Custom scrollbar */ ::-webkit-scrollbar { @@ -139,7 +153,7 @@ body { } ::-webkit-scrollbar-thumb { background: var(--border-primary); - border-radius: 10px; + border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); @@ -209,21 +223,23 @@ body { /* Glass effect */ .glass { background: var(--bg-glass); - backdrop-filter: blur(16px) saturate(180%); - -webkit-backdrop-filter: blur(16px) saturate(180%); + backdrop-filter: blur(16px) saturate(140%); + -webkit-backdrop-filter: blur(16px) saturate(140%); border-bottom: 1px solid var(--border-primary); } -/* Modern card hover */ +/* Card hover */ .card-hover { - transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease, border-color 0.2s ease; + transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.25s ease, border-color 0.25s ease; } .card-hover:hover { transform: translateY(-2px); - box-shadow: 0 8px 30px -8px rgba(0, 0, 0, 0.12); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05); + border-color: #d5d0ca; } .dark .card-hover:hover { - box-shadow: 0 8px 30px -8px rgba(0, 0, 0, 0.4); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); + border-color: rgba(255, 255, 255, 0.1); } /* Glow effects */ @@ -231,7 +247,7 @@ body { box-shadow: 0 0 20px -4px var(--accent-glow); } .glow-purple { - box-shadow: 0 0 30px -6px rgba(168, 85, 247, 0.3); + box-shadow: 0 0 30px -6px rgba(138, 154, 170, 0.2); } /* Status indicator pulse */