Files
openfang/crates/openfang-api/static/css/theme.css
iven 20093a6644
Some checks failed
CI / Check / macos-latest (push) Has been cancelled
CI / Check / ubuntu-latest (push) Has been cancelled
CI / Check / windows-latest (push) Has been cancelled
CI / Test / macos-latest (push) Has been cancelled
CI / Test / ubuntu-latest (push) Has been cancelled
CI / Test / windows-latest (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / Secrets Scan (push) Has been cancelled
CI / Install Script Smoke Test (push) Has been cancelled
重构组件样式系统为玻璃态设计风格并优化交互动效
2026-03-01 18:24:02 +08:00

810 lines
37 KiB
CSS

/* ═══════════════════════════════════════════════════════════════════════════
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 {
/* ─────────────────────────────────────────────────────────────────────────
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);
/* 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);
/* ─────────────────────────────────────────────────────────────────────────
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);
--error: #EF4444;
--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-hover: #D97706;
--warning-dim: #B45309;
--warning-subtle: rgba(245, 158, 11, 0.08);
--warning-muted: rgba(245, 158, 11, 0.15);
--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);
/* ─────────────────────────────────────────────────────────────────────────
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;
/* ─────────────────────────────────────────────────────────────────────────
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: 10px;
--radius-lg: 14px;
--radius-xl: 20px;
--radius-2xl: 28px;
--radius-full: 9999px;
/* ─────────────────────────────────────────────────────────────────────────
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 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-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"] {
/* ─────────────────────────────────────────────────────────────────────────
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-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);
--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(251, 191, 36, 0.1);
--warning-muted: rgba(251, 191, 36, 0.18);
--info: #60A5FA;
--info-hover: #3B82F6;
--info-dim: #2563EB;
--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;
-webkit-text-size-adjust: 100%;
}
body {
font-family: var(--font-sans);
background: var(--bg);
color: var(--text);
height: 100vh;
overflow: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 14px;
line-height: 1.55;
letter-spacing: -0.01em;
/* Aurora mesh gradient background */
background-image: var(--gradient-mesh);
background-attachment: fixed;
}
/* 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);
}
/* ═══════════════════════════════════════════════════════════════════════════
SCROLLBAR STYLING
═══════════════════════════════════════════════════════════════════════════ */
/* Webkit (Chrome, Edge, Safari) */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-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;
}
/* Firefox */
* {
scrollbar-width: thin;
scrollbar-color: var(--border-strong) transparent;
}
/* ═══════════════════════════════════════════════════════════════════════════
SELECTION & THEME TRANSITIONS
═══════════════════════════════════════════════════════════════════════════ */
::selection {
background: var(--accent);
color: var(--text-on-accent);
}
/* Smooth theme switching */
body {
transition:
background-color 0.4s var(--ease-smooth),
color 0.4s var(--ease-smooth);
}
.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-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, [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;
}
/* ═══════════════════════════════════════════════════════════════════════════
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(12px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideDown {
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.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 6px transparent; }
100% { box-shadow: 0 0 0 0 transparent; }
}
/* Spin animation */
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Float animation */
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-4px); }
}
/* 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-size: 200% 100%;
animation: shimmer 1.5s ease-in-out infinite;
border-radius: var(--radius-sm);
}
.skeleton-text { height: 14px; margin-bottom: 8px; }
.skeleton-text:last-child { width: 60%; }
.skeleton-heading { height: 20px; width: 40%; margin-bottom: 12px; }
.skeleton-card { height: 100px; border-radius: var(--radius-lg); }
.skeleton-avatar { width: 32px; height: 32px; border-radius: 50%; }
/* ═══════════════════════════════════════════════════════════════════════════
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);
}
.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);
}
/* ═══════════════════════════════════════════════════════════════════════════
INTERACTION UTILITIES
═══════════════════════════════════════════════════════════════════════════ */
/* 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;
}
button, .btn, [type="button"], [type="submit"], [type="reset"] {
cursor: pointer;
}
:disabled, .disabled, [aria-disabled="true"] {
cursor: not-allowed !important;
}
/* 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: -100px;
left: 8px;
background: var(--accent);
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: 8px;
}
/* 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 */
@media (prefers-contrast: high) {
:root, [data-theme="light"], [data-theme="dark"] {
--border: currentColor;
--text-dim: var(--text);
--text-muted: var(--text-secondary);
}
.card, .modal, .btn, input, select, textarea {
border-width: 2px;
}
}
/* Forced colors mode (Windows High Contrast) */
@media (forced-colors: active) {
.btn, .badge, .toggle, .card {
border: 2px solid currentColor;
}
.status-dot, .session-dot {
forced-color-adjust: none;
}
}
/* 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;
}
}
/* 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; }
}
/* ═══════════════════════════════════════════════════════════════════════════
DARK MODE IMAGE ADJUSTMENTS
═══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"] img {
opacity: 0.95;
transition: opacity 0.2s var(--ease-smooth);
}
[data-theme="dark"] img:hover {
opacity: 1;
}