Download vetcopilot-app/src/index.css from WWsCa/VetNet-LCPS: direct link, hf CLI and curl.
- Browser
- Download file 92.3 kB
-
https://huggingface.co/WWsCa/VetNet-LCPS/resolve/main/vetcopilot-app/src/index.css
- Command line
-
hf download hf://WWsCa/VetNet-LCPS/vetcopilot-app/src/index.css
-
curl -L -o index.css https://huggingface.co/WWsCa/VetNet-LCPS/resolve/main/vetcopilot-app/src/index.css
92.3 kB
| @tailwind base; | |
| @tailwind components; | |
| @tailwind utilities; | |
| /* ================================================================ | |
| 主题系统 | |
| [data-theme] 选择器覆盖 Tailwind 工具类 | |
| ================================================================ */ | |
| /* ===== 方案 A:暖绿自然 (Emerald) ===== */ | |
| [data-theme="emerald"] .bg-medical-50 { background-color: #ecfdf5; } | |
| [data-theme="emerald"] .bg-medical-100 { background-color: #d1fae5; } | |
| [data-theme="emerald"] .bg-medical-200 { background-color: #a7f3d0; } | |
| [data-theme="emerald"] .bg-medical-500 { background-color: #10b981; } | |
| [data-theme="emerald"] .bg-medical-600 { background-color: #059669; } | |
| [data-theme="emerald"] .bg-medical-700 { background-color: #047857; } | |
| [data-theme="emerald"] .text-medical-600 { color: #059669; } | |
| [data-theme="emerald"] .text-medical-700 { color: #047857; } | |
| [data-theme="emerald"] .border-medical-600 { border-color: #059669; } | |
| [data-theme="emerald"] .ring-medical-500 { --tw-ring-color: #10b981; } | |
| [data-theme="emerald"] .ring-medical-600 { --tw-ring-color: #059669; } | |
| [data-theme="emerald"] .from-medical-600 { --tw-gradient-from: #059669; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } | |
| [data-theme="emerald"] .from-medical-700 { --tw-gradient-from: #047857; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } | |
| [data-theme="emerald"] .to-medical-700 { --tw-gradient-to: #047857; } | |
| [data-theme="emerald"] .bg-accent-50 { background-color: #fffbeb; } | |
| [data-theme="emerald"] .bg-accent-100 { background-color: #fef3c7; } | |
| [data-theme="emerald"] .bg-accent-500 { background-color: #f59e0b; } | |
| [data-theme="emerald"] .bg-accent-600 { background-color: #d97706; } | |
| [data-theme="emerald"] .text-accent-600 { color: #d97706; } | |
| [data-theme="emerald"] .border-accent-500 { border-color: #f59e0b; } | |
| [data-theme="emerald"] .bg-surface-50 { background-color: #f8faf7; } | |
| [data-theme="emerald"] .bg-surface-100 { background-color: #f0f5f0; } | |
| [data-theme="emerald"] .page-title::before { background: linear-gradient(180deg, #10b981, #059669); } | |
| [data-theme="emerald"] .btn-primary { background-color: #059669; } | |
| [data-theme="emerald"] .btn-primary:hover { background-color: #047857; } | |
| /* ===== 方案 B:蓝绿医疗 (Cyan) ===== */ | |
| [data-theme="cyan"] .bg-medical-50 { background-color: #ecfeff; } | |
| [data-theme="cyan"] .bg-medical-100 { background-color: #cffafe; } | |
| [data-theme="cyan"] .bg-medical-200 { background-color: #a5f3fc; } | |
| [data-theme="cyan"] .bg-medical-500 { background-color: #06b6d4; } | |
| [data-theme="cyan"] .bg-medical-600 { background-color: #0891b2; } | |
| [data-theme="cyan"] .bg-medical-700 { background-color: #0e7490; } | |
| [data-theme="cyan"] .text-medical-600 { color: #0891b2; } | |
| [data-theme="cyan"] .text-medical-700 { color: #0e7490; } | |
| [data-theme="cyan"] .border-medical-600 { border-color: #0891b2; } | |
| [data-theme="cyan"] .ring-medical-500 { --tw-ring-color: #06b6d4; } | |
| [data-theme="cyan"] .ring-medical-600 { --tw-ring-color: #0891b2; } | |
| [data-theme="cyan"] .from-medical-600 { --tw-gradient-from: #0891b2; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } | |
| [data-theme="cyan"] .from-medical-700 { --tw-gradient-from: #0e7490; --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } | |
| [data-theme="cyan"] .to-medical-700 { --tw-gradient-to: #0e7490; } | |
| [data-theme="cyan"] .bg-accent-50 { background-color: #f0fdf4; } | |
| [data-theme="cyan"] .bg-accent-100 { background-color: #dcfce7; } | |
| [data-theme="cyan"] .bg-accent-500 { background-color: #22c55e; } | |
| [data-theme="cyan"] .bg-accent-600 { background-color: #16a34a; } | |
| [data-theme="cyan"] .text-accent-600 { color: #16a34a; } | |
| [data-theme="cyan"] .border-accent-500 { border-color: #22c55e; } | |
| [data-theme="cyan"] .bg-surface-50 { background-color: #f8fafa; } | |
| [data-theme="cyan"] .bg-surface-100 { background-color: #f0f5f6; } | |
| [data-theme="cyan"] .page-title::before { background: linear-gradient(180deg, #06b6d4, #0891b2); } | |
| [data-theme="cyan"] .btn-primary { background-color: #0891b2; } | |
| [data-theme="cyan"] .btn-primary:hover { background-color: #0e7490; } | |
| /* ================================================================ | |
| 暗色模式 CSS 变量基础(为未来暗色模式做准备) | |
| 当前所有变量值为亮色默认值,暂不启用暗色模式 | |
| ================================================================ */ | |
| :root { | |
| /* ---- 背景色 ---- */ | |
| --color-bg-primary: #ffffff; | |
| --color-bg-secondary: #f8fafc; | |
| --color-surface: #ffffff; | |
| /* ---- 文字色 ---- */ | |
| --color-text-primary: #111827; | |
| --color-text-secondary: #6b7280; | |
| /* ---- 边框色 ---- */ | |
| --color-border: #e5e7eb; | |
| /* ---- 阴影层级 ---- */ | |
| --shadow-sm: 0 1px 2px 0 rgba(0,0,0,0.05); | |
| --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1); | |
| --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1); | |
| } | |
| /* 在未来启用暗色模式时,只需在 <html> 上添加 data-theme="dark" */ | |
| [data-theme="dark"] { | |
| --color-bg-primary: #0f172a; | |
| --color-bg-secondary: #1e293b; | |
| --color-surface: #1e293b; | |
| --color-text-primary: #f1f5f9; | |
| --color-text-secondary: #94a3b8; | |
| --color-border: #334155; | |
| --shadow-sm: 0 1px 2px 0 rgba(0,0,0,0.3); | |
| --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.4), 0 2px 4px -2px rgba(0,0,0,0.3); | |
| --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.5), 0 4px 6px -4px rgba(0,0,0,0.4); | |
| } | |
| /* ================================================================ | |
| Base | |
| ================================================================ */ | |
| @layer base { | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, | |
| "Helvetica Neue", Arial, "Noto Sans SC", "Microsoft YaHei", sans-serif; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| } | |
| /* ===== 自定义选中色 ===== */ | |
| ::selection { background-color: rgba(59,130,246,0.2); color: #1e3a8a; } | |
| [data-theme="emerald"] ::selection { background-color: rgba(16,185,129,0.2); color: #064e3b; } | |
| [data-theme="cyan"] ::selection { background-color: rgba(6,182,212,0.2); color: #164e63; } | |
| /* ===== 全局自定义滚动条 ===== */ | |
| ::-webkit-scrollbar { width: 6px; height: 6px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { | |
| background: #d1d5db; | |
| border-radius: 3px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { background: #9ca3af; } | |
| /* ===== 全局 textarea 统一样式 ===== */ | |
| textarea:not(.input-field) { | |
| @apply w-full px-3 py-2 text-sm border border-gray-300 rounded-lg | |
| focus:outline-none focus:ring-2 focus:ring-medical-500 focus:border-transparent | |
| placeholder:text-gray-400 transition-all duration-200 resize-y; | |
| } | |
| /* ===== 全局 input 统一样式 ===== */ | |
| input[type="text"]:not(.input-field):not([class*="border-"]), | |
| input[type="tel"]:not(.input-field):not([class*="border-"]), | |
| input[type="email"]:not(.input-field):not([class*="border-"]), | |
| input[type="number"]:not(.input-field):not([class*="border-"]), | |
| input[type="date"]:not(.input-field):not([class*="border-"]), | |
| input[type="password"]:not(.input-field):not([class*="border-"]) { | |
| @apply w-full px-3 py-2 text-sm border border-gray-300 rounded-lg | |
| focus:outline-none focus:ring-2 focus:ring-medical-500 focus:border-transparent | |
| placeholder:text-gray-400 transition-all duration-200; | |
| } | |
| /* ===== 全局 select 美化 ===== */ | |
| select:not(.input-field):not([class*="native"]) { | |
| @apply w-full px-3 py-2 text-sm border border-gray-300 rounded-lg | |
| bg-white text-gray-700 | |
| focus:outline-none focus:ring-2 focus:ring-medical-500 focus:border-transparent | |
| transition-all duration-200; | |
| appearance: none; | |
| background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); | |
| background-repeat: no-repeat; | |
| background-position: right 0.75rem center; | |
| padding-right: 2.25rem; | |
| } | |
| /* ===== 全局表格行 hover ===== */ | |
| table tbody tr { transition: background-color 0.15s ease; } | |
| table tbody tr:hover { background-color: #f9fafb; } | |
| /* ===== 全局链接颜色跟随主题 ===== */ | |
| a:not([class*="text-"]) { color: #2563eb; } | |
| [data-theme="emerald"] a:not([class*="text-"]) { color: #059669; } | |
| [data-theme="cyan"] a:not([class*="text-"]) { color: #0891b2; } | |
| /* ===== 自定义 checkbox/radio ===== */ | |
| input[type="checkbox"].custom-check { | |
| @apply w-4 h-4 rounded border-gray-300 text-medical-600 | |
| focus:ring-medical-500 focus:ring-2 transition-all duration-150; | |
| } | |
| input[type="radio"].custom-radio { | |
| @apply w-4 h-4 border-gray-300 text-medical-600 | |
| focus:ring-medical-500 focus:ring-2 transition-all duration-150; | |
| } | |
| /* ===== Reduced Motion:尊重用户操作系统偏好 ===== */ | |
| @media (prefers-reduced-motion: reduce) { | |
| /* 全局禁用所有非必要动画和过渡 */ | |
| *, | |
| *::before, | |
| *::after { | |
| animation-duration: 0.01ms ; | |
| animation-iteration-count: 1 ; | |
| transition-duration: 0.01ms ; | |
| scroll-behavior: auto ; | |
| } | |
| /* 骨架屏闪烁 → 静态展示 */ | |
| .skeleton, | |
| .skeleton-shimmer, | |
| .skeleton-card, | |
| .skeleton-card-line, | |
| .skeleton-avatar { | |
| animation: none ; | |
| background-image: none ; | |
| opacity: 0.5; | |
| } | |
| /* 脉冲动画 → 静态 */ | |
| .animate-spin, | |
| .animate-pulse, | |
| .animate-pulse-soft, | |
| .animate-bounce { | |
| animation: none ; | |
| } | |
| /* 浮动动画 → 静态 */ | |
| .animate-float, | |
| .empty-state-icon { | |
| animation: none ; | |
| } | |
| } | |
| .page-enter { animation: fade-in-up 0.35s ease-out; } | |
| } | |
| /* ================================================================ | |
| Components | |
| ================================================================ */ | |
| @layer components { | |
| /* ===== 按钮 ===== */ | |
| .btn-primary { | |
| @apply inline-flex items-center justify-center gap-2 px-5 py-2.5 | |
| bg-medical-600 text-white text-sm font-medium rounded-lg | |
| hover:bg-medical-700 active:scale-95 | |
| transition-all duration-200 | |
| disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100; | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04); | |
| } | |
| .btn-primary:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04); } | |
| .btn-secondary { | |
| @apply inline-flex items-center justify-center gap-2 px-5 py-2.5 | |
| bg-white text-gray-700 text-sm font-medium rounded-lg | |
| border border-gray-300 hover:bg-gray-50 active:bg-gray-100 active:scale-95 | |
| transition-all duration-200 | |
| disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100; | |
| } | |
| .btn-danger { | |
| @apply inline-flex items-center justify-center gap-2 px-5 py-2.5 | |
| bg-white text-red-600 text-sm font-medium rounded-lg | |
| border border-red-300 hover:bg-red-50 active:bg-red-100 active:scale-95 | |
| transition-all duration-200 | |
| disabled:opacity-50 disabled:cursor-not-allowed disabled:active:scale-100; | |
| } | |
| .btn-ghost { | |
| @apply inline-flex items-center justify-center gap-2 px-4 py-2 | |
| text-gray-500 text-sm font-medium rounded-lg | |
| hover:bg-gray-100 hover:text-gray-700 active:scale-95 | |
| transition-all duration-150; | |
| } | |
| /* ================================================================ | |
| 响应式工具类 | |
| ================================================================ */ | |
| /* 仅移动端/小屏显示(< lg 时可见,>= lg 隐藏) */ | |
| .mobile-only { | |
| @apply block; | |
| } | |
| @media (min-width: 1024px) { | |
| .mobile-only { display: none ; } | |
| } | |
| /* 仅桌面端显示(>= lg 时可见,< lg 隐藏) */ | |
| .desktop-only { | |
| display: none ; | |
| } | |
| @media (min-width: 1024px) { | |
| .desktop-only { display: block ; } | |
| } | |
| /* 触控友好区域:最小 44x44px(满足 WCAG 触控目标) */ | |
| .touch-target { | |
| min-width: 44px; | |
| min-height: 44px; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| touch-action: manipulation; | |
| } | |
| /* ===== 页面标题 ===== */ | |
| .page-title { | |
| @apply text-lg md:text-xl font-bold text-gray-900 flex items-center gap-3 mb-5; | |
| } | |
| .page-title::before { | |
| content: ''; | |
| @apply w-1 h-6 rounded-full shrink-0; | |
| background: linear-gradient(180deg, #3b82f6, #2563eb); | |
| } | |
| /* ===== 卡片 ===== */ | |
| .card { | |
| @apply bg-white rounded-xl border border-gray-200 transition-all duration-200; | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04); | |
| } | |
| .card-hover:hover { | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04); | |
| @apply border-gray-300; | |
| } | |
| /* ===== 玻璃态卡片 ===== */ | |
| .glass-card { | |
| @apply bg-white/70 backdrop-blur-xl border border-white/40 rounded-xl; | |
| box-shadow: 0 4px 24px rgba(0,0,0,0.06), 0 1px 4px rgba(0,0,0,0.04); | |
| } | |
| .glass-card:hover { | |
| @apply bg-white/85 border-white/60; | |
| box-shadow: 0 8px 32px rgba(0,0,0,0.1), 0 2px 8px rgba(0,0,0,0.06); | |
| } | |
| /* ===== 增强玻璃态卡片(更明显的磨砂 + 彩色边框光晕)===== */ | |
| .glass-card-enhanced { | |
| @apply bg-white/60 backdrop-blur-2xl border border-white/50 rounded-2xl; | |
| box-shadow: | |
| 0 4px 24px rgba(0,0,0,0.08), | |
| 0 1px 4px rgba(0,0,0,0.04), | |
| inset 0 1px 0 rgba(255,255,255,0.6); | |
| transition: all 0.4s cubic-bezier(.34,1.56,.64,1); | |
| } | |
| .glass-card-enhanced:hover { | |
| @apply bg-white/80 border-white/70; | |
| box-shadow: | |
| 0 12px 40px rgba(0,0,0,0.12), | |
| 0 4px 16px rgba(0,0,0,0.08), | |
| inset 0 1px 0 rgba(255,255,255,0.8); | |
| transform: translateY(-2px); | |
| } | |
| /* ===== 多层阴影卡片(更深的深度感)===== */ | |
| .elevated-card { | |
| @apply bg-white rounded-xl border border-gray-100 transition-all duration-300; | |
| box-shadow: | |
| 0 1px 2px rgba(0,0,0,0.04), | |
| 0 2px 4px rgba(0,0,0,0.04), | |
| 0 4px 8px rgba(0,0,0,0.04), | |
| 0 8px 16px rgba(0,0,0,0.04); | |
| } | |
| .elevated-card:hover { | |
| box-shadow: | |
| 0 2px 4px rgba(0,0,0,0.06), | |
| 0 4px 8px rgba(0,0,0,0.06), | |
| 0 8px 16px rgba(0,0,0,0.06), | |
| 0 16px 32px rgba(0,0,0,0.08); | |
| transform: translateY(-3px); | |
| @apply border-gray-200; | |
| } | |
| .elevated-card:active { | |
| transform: translateY(-1px); | |
| box-shadow: | |
| 0 1px 2px rgba(0,0,0,0.04), | |
| 0 2px 4px rgba(0,0,0,0.04), | |
| 0 4px 8px rgba(0,0,0,0.04); | |
| } | |
| /* ===== 渐变文字工具类 ===== */ | |
| .gradient-text { | |
| @apply bg-clip-text text-transparent; | |
| background-image: linear-gradient(135deg, var(--tw-gradient-from, #3b82f6), var(--tw-gradient-to, #8b5cf6)); | |
| } | |
| [data-theme="emerald"] .gradient-text { background-image: linear-gradient(135deg, #10b981, #059669, #047857); } | |
| [data-theme="cyan"] .gradient-text { background-image: linear-gradient(135deg, #06b6d4, #0891b2, #0e7490); } | |
| /* ===== 语义色彩标记(信息面板)===== */ | |
| .info-panel-info { @apply border-l-4 border-medical-500 bg-medical-50; } | |
| .info-panel-success { @apply border-l-4 border-green-500 bg-green-50; } | |
| .info-panel-warning { @apply border-l-4 border-amber-500 bg-amber-50; } | |
| .info-panel-error { @apply border-l-4 border-red-500 bg-red-50; } | |
| /* ===== 渐变分隔线 ===== */ | |
| .section-divider { | |
| @apply relative h-px my-8; | |
| background: linear-gradient(90deg, transparent, #d1d5db 20%, #d1d5db 80%, transparent); | |
| } | |
| .section-divider-accent { | |
| @apply section-divider; | |
| background: linear-gradient(90deg, transparent, var(--tw-gradient-from, #3b82f6) 20%, var(--tw-gradient-from, #3b82f6) 80%, transparent); | |
| } | |
| [data-theme="emerald"] .section-divider-accent { background: linear-gradient(90deg, transparent, #10b981 20%, #10b981 80%, transparent); } | |
| [data-theme="cyan"] .section-divider-accent { background: linear-gradient(90deg, transparent, #06b6d4 20%, #06b6d4 80%, transparent); } | |
| /* ===== 输入框 ===== */ | |
| .input-field { | |
| @apply w-full px-3 py-2 text-sm border border-gray-300 rounded-lg | |
| focus:outline-none focus:ring-2 focus:ring-medical-500 focus:border-transparent | |
| placeholder:text-gray-400 transition-all duration-200 bg-white; | |
| } | |
| .input-field:focus { | |
| box-shadow: 0 0 0 3px rgba(59,130,246,0.12), 0 0 8px rgba(59,130,246,0.06); | |
| } | |
| [data-theme="emerald"] .input-field:focus { box-shadow: 0 0 0 3px rgba(16,185,129,0.12), 0 0 8px rgba(16,185,129,0.06); } | |
| [data-theme="cyan"] .input-field:focus { box-shadow: 0 0 0 3px rgba(6,182,212,0.12), 0 0 8px rgba(6,182,212,0.06); } | |
| .label-text { @apply block text-sm font-medium text-gray-700 mb-1; } | |
| /* ===== Floating Label(浮动标签)===== */ | |
| .float-label-group { | |
| @apply relative mb-4; | |
| } | |
| .float-label-input { | |
| @apply w-full px-3 pt-5 pb-2 text-sm border border-gray-300 rounded-lg | |
| bg-white | |
| focus:outline-none focus:ring-2 focus:ring-medical-500 focus:border-transparent | |
| placeholder-transparent transition-all duration-200; | |
| } | |
| .float-label-input.error { | |
| @apply border-red-400 focus:ring-red-400; | |
| } | |
| .float-label-text { | |
| @apply absolute left-3 text-gray-400 text-sm transition-all duration-200 pointer-events-none; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| } | |
| .float-label-input:focus ~ .float-label-text, | |
| .float-label-input:not(:placeholder-shown) ~ .float-label-text, | |
| .float-label-text.active { | |
| top: 0.5rem; | |
| transform: translateY(0); | |
| font-size: 0.65rem; | |
| @apply text-medical-600; | |
| } | |
| .float-label-input.error ~ .float-label-text { | |
| @apply text-red-500; | |
| } | |
| .float-label-error { | |
| @apply mt-1 text-xs text-red-500 flex items-center gap-1; | |
| animation: fade-in-up 0.2s ease-out; | |
| } | |
| /* ===== Password Toggle(密码可见切换)===== */ | |
| .password-toggle-btn { | |
| @apply absolute right-2 top-1/2 -translate-y-1/2 p-1.5 | |
| text-gray-400 hover:text-gray-600 | |
| rounded-md transition-colors duration-150 | |
| min-h-[32px] min-w-[32px] flex items-center justify-center; | |
| } | |
| /* ===== Validation Icon(验证状态图标)===== */ | |
| .validation-icon { | |
| @apply absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none; | |
| } | |
| .validation-icon-error { | |
| @apply text-red-400; | |
| animation: validation-pop-in 0.25s cubic-bezier(.34,1.56,.64,1); | |
| } | |
| .validation-icon-success { | |
| @apply text-green-500; | |
| animation: validation-pop-in 0.25s cubic-bezier(.34,1.56,.64,1); | |
| } | |
| /* ===== Badge ===== */ | |
| .badge { @apply inline-flex items-center text-xs px-2 py-0.5 rounded-full font-medium; } | |
| .badge-success { @apply badge bg-green-100 text-green-700; } | |
| .badge-warning { @apply badge bg-amber-100 text-amber-700; } | |
| .badge-danger { @apply badge bg-red-100 text-red-700; } | |
| .badge-info { @apply badge bg-medical-100 text-medical-700; } | |
| .badge-neutral { @apply badge bg-gray-100 text-gray-600; } | |
| [data-theme="emerald"] .badge-info { @apply bg-green-100 text-green-700; } | |
| [data-theme="cyan"] .badge-info { @apply bg-cyan-100 text-cyan-700; } | |
| /* ===== Trend Arrow(趋势箭头)===== */ | |
| .trend-arrow { | |
| @apply inline-flex items-center gap-0.5 text-xs font-medium; | |
| animation: trend-bounce-in 0.5s cubic-bezier(.34,1.56,.64,1) 0.3s both; | |
| } | |
| .trend-arrow-up { @apply text-green-600; } | |
| .trend-arrow-down { @apply text-red-500; } | |
| .trend-arrow-neutral { @apply text-gray-400; } | |
| .trend-arrow svg { | |
| animation: trend-arrow-pop 0.4s ease-out 0.5s both; | |
| } | |
| /* ===== Tag ===== */ | |
| .tag { | |
| @apply inline-flex items-center gap-1 text-xs px-2.5 py-1 rounded-md font-medium | |
| bg-gray-100 text-gray-600 border border-gray-200 transition-all duration-200; | |
| } | |
| .tag-active { @apply tag bg-medical-100 text-medical-700 border-medical-300; } | |
| .tag-removable { | |
| @apply tag cursor-pointer hover:bg-red-50 hover:text-red-600 hover:border-red-200; | |
| } | |
| /* ===== 空状态 ===== */ | |
| .empty-state { @apply flex flex-col items-center justify-center py-16 px-4 text-center; } | |
| .empty-state-icon { | |
| @apply w-16 h-16 mx-auto mb-4 text-gray-300; | |
| animation: float 3s ease-in-out infinite; | |
| } | |
| .empty-state-title { @apply text-sm font-medium text-gray-500 mb-1; } | |
| .empty-state-desc { @apply text-xs text-gray-400 mb-4 max-w-xs; } | |
| /* ===== Spinner ===== */ | |
| .spinner { | |
| @apply border-4 border-gray-200 rounded-full animate-spin; | |
| border-top-color: #3b82f6; | |
| } | |
| [data-theme="emerald"] .spinner { border-top-color: #059669; } | |
| [data-theme="cyan"] .spinner { border-top-color: #0891b2; } | |
| /* ===== Loading Dots ===== */ | |
| .loading-dots { @apply inline-flex items-center gap-1; } | |
| .loading-dots span { | |
| @apply w-2 h-2 rounded-full bg-gray-400; | |
| animation: dot-bounce 1.4s ease-in-out infinite both; | |
| } | |
| .loading-dots span:nth-child(1) { animation-delay: -0.32s; } | |
| .loading-dots span:nth-child(2) { animation-delay: -0.16s; } | |
| .loading-dots span:nth-child(3) { animation-delay: 0s; } | |
| /* ===== 进度条 ===== */ | |
| .progress-bar { | |
| @apply w-full h-2 bg-gray-100 rounded-full overflow-hidden; | |
| } | |
| .progress-bar-fill { | |
| @apply h-full rounded-full transition-all duration-500 ease-out; | |
| background: linear-gradient(90deg, #3b82f6, #2563eb); | |
| animation: progress-grow 0.8s ease-out; | |
| } | |
| [data-theme="emerald"] .progress-bar-fill { background: linear-gradient(90deg, #10b981, #059669); } | |
| [data-theme="cyan"] .progress-bar-fill { background: linear-gradient(90deg, #06b6d4, #0891b2); } | |
| /* ===== Tooltip ===== */ | |
| .tooltip-wrapper { @apply relative inline-flex; } | |
| .tooltip-content { | |
| @apply absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2.5 py-1.5 | |
| bg-gray-900 text-white text-xs rounded-lg whitespace-nowrap | |
| opacity-0 pointer-events-none transition-opacity duration-200 z-50; | |
| } | |
| .tooltip-wrapper:hover .tooltip-content { @apply opacity-100; } | |
| .tooltip-content::after { | |
| content: ''; | |
| @apply absolute top-full left-1/2 -translate-x-1/2 | |
| border-4 border-transparent border-t-gray-900; | |
| } | |
| /* ===== Toggle Switch ===== */ | |
| .toggle-switch { | |
| @apply relative inline-flex w-11 h-6 rounded-full transition-colors duration-200 | |
| bg-gray-300 cursor-pointer; | |
| } | |
| .toggle-switch.active { @apply bg-medical-600; } | |
| [data-theme="emerald"] .toggle-switch.active { @apply bg-emerald-600; } | |
| [data-theme="cyan"] .toggle-switch.active { @apply bg-cyan-600; } | |
| .toggle-switch::after { | |
| content: ''; | |
| @apply absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-white shadow-sm | |
| transition-transform duration-200; | |
| } | |
| .toggle-switch.active::after { transform: translateX(20px); } | |
| /* ===== 成功勾选动画 ===== */ | |
| .checkmark-animated { | |
| stroke-dasharray: 50; | |
| stroke-dashoffset: 50; | |
| animation: checkmark-draw 0.5s ease-out forwards; | |
| } | |
| /* ===== 分隔线 ===== */ | |
| .divider-animated { | |
| @apply relative h-px bg-gray-200 my-6 overflow-hidden; | |
| } | |
| .divider-animated::after { | |
| content: ''; | |
| @apply absolute inset-0; | |
| background: linear-gradient(90deg, transparent, #3b82f6, transparent); | |
| animation: divider-slide 2s ease-in-out infinite; | |
| } | |
| /* ===== 可拖拽手柄 ===== */ | |
| .drag-handle { | |
| @apply cursor-grab active:cursor-grabbing text-gray-300 hover:text-gray-500 | |
| transition-colors duration-150; | |
| } | |
| /* ===== 心形动画 ===== */ | |
| .heart-icon { | |
| @apply transition-all duration-300 cursor-pointer; | |
| } | |
| .heart-icon.liked { | |
| @apply text-red-500 scale-110; | |
| animation: heart-beat 0.4s ease-out; | |
| } | |
| } | |
| /* ================================================================ | |
| Utilities | |
| ================================================================ */ | |
| @layer utilities { | |
| /* ===== 移动端紧凑间距工具类 ===== */ | |
| .p-mobile { padding: 0.75rem; } /* 12px - 移动端紧凑内边距 */ | |
| .px-mobile { padding-left: 0.75rem; padding-right: 0.75rem; } | |
| .py-mobile { padding-top: 0.75rem; padding-bottom: 0.75rem; } | |
| .gap-mobile { gap: 0.5rem; } /* 8px - 移动端紧凑间距 */ | |
| .text-mobile { font-size: 0.8125rem; } /* 13px - 移动端略小字号 */ | |
| /* 移动端全宽(突破父容器 padding 限制) */ | |
| .mobile-full-bleed { | |
| margin-left: -0.75rem; | |
| margin-right: -0.75rem; | |
| width: calc(100% + 1.5rem); | |
| } | |
| .skeleton { | |
| @apply bg-gray-200 rounded; | |
| animation: shimmer 2s ease-in-out infinite; | |
| background-image: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.6) 50%, transparent 100%); | |
| background-size: 200% 100%; | |
| } | |
| .glass { | |
| @apply bg-white/80 backdrop-blur-md border-b border-gray-200/60; | |
| } | |
| /* 页面进入 */ | |
| .animate-fade-in { animation: fade-in-up 0.4s ease-out; } | |
| .animate-fade-in-up { opacity: 0; animation: fade-in-up 0.5s ease-out forwards; } | |
| .animate-scale-in { animation: scale-in 0.25s cubic-bezier(.16,1,.3,1); } | |
| .animate-slide-in { animation: slide-in 0.4s ease-out; } | |
| .animate-fade-in-left { opacity: 0; animation: fade-in-left 0.4s ease-out forwards; } | |
| /* 卡片悬停浮升 */ | |
| .animate-lift { | |
| transition: transform 0.3s cubic-bezier(.34,1.56,.64,1), box-shadow 0.3s ease; | |
| } | |
| .animate-lift:hover { | |
| transform: translateY(-4px); | |
| box-shadow: 0 12px 24px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.06); | |
| } | |
| /* 推荐替代: hover-lift(更自然的浮升 + 光晕) */ | |
| .hover-lift { | |
| transition: transform 0.35s cubic-bezier(.34,1.56,.64,1), box-shadow 0.35s ease, border-color 0.35s ease; | |
| will-change: transform; | |
| } | |
| .hover-lift:hover { | |
| transform: translateY(-6px); | |
| box-shadow: 0 16px 32px rgba(0,0,0,0.12), 0 6px 12px rgba(0,0,0,0.06); | |
| } | |
| /* 按压缩放反馈 */ | |
| .press-scale { | |
| transition: transform 0.15s cubic-bezier(.34,1.56,.64,1); | |
| } | |
| .press-scale:active { | |
| transform: scale(0.94); | |
| } | |
| .press-scale-sm:active { | |
| transform: scale(0.97); | |
| } | |
| /* 改进波纹效果(JavaScript 驱动的点击波纹) */ | |
| .ripple-container { | |
| position: relative; | |
| overflow: hidden; | |
| -webkit-mask-image: -webkit-radial-gradient(white, black); | |
| } | |
| .ripple-effect { | |
| position: absolute; | |
| border-radius: 50%; | |
| background: rgba(255,255,255,0.35); | |
| transform: scale(0); | |
| animation: ripple-expand 0.6s ease-out forwards; | |
| pointer-events: none; | |
| } | |
| /* 改进脉冲点(状态指示) */ | |
| .pulse-dot { | |
| @apply relative inline-flex; | |
| } | |
| .pulse-dot::before { | |
| content: ''; | |
| @apply absolute inset-0 rounded-full; | |
| animation: pulse-dot-ring 2s ease-in-out infinite; | |
| } | |
| .pulse-dot-online::before { background: rgba(16,185,129,0.4); } | |
| .pulse-dot-busy::before { background: rgba(245,158,11,0.4); } | |
| .pulse-dot-offline::before { background: rgba(156,163,175,0.4); } | |
| /* 改进骨架屏闪烁 */ | |
| .skeleton-shimmer { | |
| @apply bg-gray-200 rounded; | |
| background-image: linear-gradient( | |
| 110deg, | |
| #e5e7eb 8%, | |
| #f3f4f6 18%, | |
| #e5e7eb 33% | |
| ); | |
| background-size: 200% 100%; | |
| animation: skeleton-shimmer-wave 1.8s ease-in-out infinite; | |
| } | |
| /* 文字揭示动画(逐字或整段出现) */ | |
| .text-reveal { | |
| opacity: 0; | |
| animation: text-reveal-fade 0.6s ease-out forwards; | |
| } | |
| .text-reveal-up { | |
| opacity: 0; | |
| transform: translateY(12px); | |
| animation: text-reveal-up 0.6s ease-out forwards; | |
| } | |
| .text-reveal-stagger > * { | |
| opacity: 0; | |
| animation: text-reveal-fade 0.5s ease-out forwards; | |
| } | |
| .text-reveal-stagger > *:nth-child(1) { animation-delay: 0.05s; } | |
| .text-reveal-stagger > *:nth-child(2) { animation-delay: 0.15s; } | |
| .text-reveal-stagger > *:nth-child(3) { animation-delay: 0.25s; } | |
| .text-reveal-stagger > *:nth-child(4) { animation-delay: 0.35s; } | |
| .text-reveal-stagger > *:nth-child(5) { animation-delay: 0.45s; } | |
| /* 打字光标闪烁增强 */ | |
| .typing-cursor::after { | |
| content: '|'; | |
| display: inline-block; | |
| margin-left: 1px; | |
| animation: typing-blink 0.8s step-end infinite; | |
| @apply text-medical-500; | |
| font-weight: 300; | |
| } | |
| [data-theme="emerald"] .typing-cursor::after { color: #10b981; } | |
| [data-theme="cyan"] .typing-cursor::after { color: #06b6d4; } | |
| /* Stagger */ | |
| .stagger-fade > * { opacity: 0; animation: fade-in-up 0.4s ease-out forwards; } | |
| .stagger-fade > *:nth-child(1) { animation-delay: 0.05s; } | |
| .stagger-fade > *:nth-child(2) { animation-delay: 0.1s; } | |
| .stagger-fade > *:nth-child(3) { animation-delay: 0.15s; } | |
| .stagger-fade > *:nth-child(4) { animation-delay: 0.2s; } | |
| .stagger-fade > *:nth-child(5) { animation-delay: 0.25s; } | |
| .stagger-fade > *:nth-child(6) { animation-delay: 0.3s; } | |
| .stagger-fade > *:nth-child(7) { animation-delay: 0.35s; } | |
| .stagger-fade > *:nth-child(8) { animation-delay: 0.4s; } | |
| /* 数字 */ | |
| .animate-number { animation: number-pop 0.4s cubic-bezier(.34,1.56,.64,1); } | |
| /* 脉冲 */ | |
| .animate-glow-pulse { animation: glow-pulse 2s ease-in-out infinite; } | |
| .animate-ring-pulse { animation: ring-pulse 1.5s ease-in-out infinite; } | |
| /* 渐变 */ | |
| .animate-gradient-flow { background-size: 300% 300%; animation: gradient-flow 6s ease infinite; } | |
| .text-gradient { | |
| @apply bg-clip-text text-transparent; | |
| background-image: linear-gradient(135deg, #3b82f6, #8b5cf6, #3b82f6); | |
| background-size: 200% auto; | |
| animation: gradient-flow 4s ease infinite; | |
| } | |
| /* 浮动 */ | |
| .animate-float { animation: float 3s ease-in-out infinite; } | |
| /* 抖动 */ | |
| .animate-shake { animation: shake 0.5s ease-in-out; } | |
| /* 登录表单 shake */ | |
| .animate-login-shake { animation: login-shake 0.5s ease-in-out; } | |
| /* 弹入 */ | |
| .animate-bounce-in { animation: bounce-in 0.6s cubic-bezier(.34,1.56,.64,1); } | |
| /* 旋转 */ | |
| .animate-spin-in { animation: spin-in 0.5s cubic-bezier(.34,1.2,.64,1); } | |
| .animate-spin-slow { animation: spin 3s linear infinite; } | |
| /* 波纹 */ | |
| .animate-ripple { | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .animate-ripple::after { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: radial-gradient(circle, rgba(255,255,255,0.4) 10%, transparent 10%); | |
| background-position: center; | |
| background-repeat: no-repeat; | |
| opacity: 0; | |
| transition: opacity 0.3s, transform 0.5s; | |
| transform: scale(10); | |
| pointer-events: none; | |
| } | |
| .animate-ripple:active::after { | |
| opacity: 1; | |
| transform: scale(0); | |
| transition: 0s; | |
| } | |
| /* 骨架 */ | |
| .skeleton-pulse { animation: skeleton-pulse 1.8s ease-in-out infinite; } | |
| /* 打字效果 */ | |
| .typewriter { | |
| overflow: hidden; | |
| white-space: nowrap; | |
| border-right: 2px solid #3b82f6; | |
| animation: typing 3s steps(40) 1s forwards, blink-caret 0.75s step-end infinite; | |
| } | |
| /* 淡入淡出切换 */ | |
| .crossfade-enter { animation: crossfade-in 0.3s ease-out; } | |
| .crossfade-exit { animation: crossfade-out 0.2s ease-in forwards; } | |
| /* 搜索框展开 */ | |
| .search-expand { | |
| width: 40px; | |
| transition: width 0.4s cubic-bezier(.34,1.56,.64,1); | |
| } | |
| .search-expand:focus { width: 200px; } | |
| /* 滚动揭示 */ | |
| .reveal-on-scroll { | |
| opacity: 0; | |
| transform: translateY(24px); | |
| transition: opacity 0.6s ease-out, transform 0.6s ease-out; | |
| } | |
| .reveal-on-scroll.visible { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| /* 通知红点 */ | |
| .notify-dot { | |
| @apply absolute -top-0.5 -right-0.5 w-2.5 h-2.5 bg-red-500 rounded-full border-2 border-white; | |
| animation: notification-bounce 0.4s ease-out, pulse-dot 2s ease-in-out 0.4s infinite; | |
| } | |
| .notify-dot-sm { | |
| @apply absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full border border-white; | |
| animation: notification-bounce 0.3s ease-out; | |
| } | |
| /* 高亮闪烁 */ | |
| .highlight-flash { animation: highlight-flash 1.5s ease-out; } | |
| /* 页面阶段过渡 */ | |
| .stage-transition-enter { animation: stage-enter 0.35s ease-out; } | |
| .stage-transition-exit { animation: stage-exit 0.25s ease-in forwards; } | |
| /* 折叠面板 */ | |
| .collapsible-open { animation: collapse-open 0.4s ease-out forwards; } | |
| .collapsible-close { animation: collapse-close 0.3s ease-in forwards; } | |
| /* 计数徽章 */ | |
| .count-badge { | |
| @apply inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 | |
| bg-red-500 text-white text-[10px] font-bold rounded-full; | |
| animation: count-badge 0.4s cubic-bezier(.34,1.56,.64,1); | |
| } | |
| /* 下拉刷新指示器 */ | |
| .pull-indicator { | |
| animation: pull-indicator 0.3s ease-out; | |
| } | |
| /* Toast 入场 */ | |
| .toast-enter { animation: toast-enter 0.35s cubic-bezier(.34,1.2,.64,1); } | |
| .toast-exit { animation: toast-exit 0.25s ease-in forwards; } | |
| /* 自动保存状态点 */ | |
| .autosave-dot { | |
| @apply inline-flex items-center gap-1.5 text-xs text-gray-400; | |
| } | |
| .autosave-dot::before { | |
| content: ''; | |
| @apply w-2 h-2 rounded-full bg-green-400; | |
| animation: auto-save-dot 1.5s ease-in-out infinite; | |
| } | |
| .autosave-dot.saving::before { @apply bg-amber-400; animation-duration: 0.6s; } | |
| .autosave-dot.saved::before { @apply bg-green-500; animation: none; } | |
| /* 菜单弹出 */ | |
| .menu-popup { animation: menu-slide-in 0.2s ease-out; } | |
| /* 拖拽排序手柄 */ | |
| .sortable-ghost { @apply opacity-30 bg-gray-100 rounded-lg; } | |
| .sortable-chosen { @apply shadow-lg ring-2 ring-medical-500/30; } | |
| .sortable-drag { @apply opacity-80 rotate-2 scale-105 shadow-2xl; } | |
| /* 骨架卡片 */ | |
| .skeleton-card { | |
| @apply bg-white rounded-xl border border-gray-100 p-4; | |
| animation: skeleton-pulse 1.8s ease-in-out infinite; | |
| } | |
| .skeleton-card-line { | |
| @apply h-3 rounded bg-gray-200; | |
| background-image: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.5) 50%, transparent 100%); | |
| background-size: 200% 100%; | |
| animation: skeleton-wave 1.5s ease-in-out infinite; | |
| } | |
| /* 下拉菜单项 */ | |
| .dropdown-item { | |
| @apply w-full text-left px-3 py-2 text-sm text-gray-700 | |
| hover:bg-gray-50 hover:text-gray-900 transition-colors duration-150 | |
| flex items-center gap-2 rounded-md; | |
| } | |
| .dropdown-item-danger { | |
| @apply dropdown-item text-red-600 hover:bg-red-50 hover:text-red-700; | |
| } | |
| /* 标签输入 */ | |
| .tag-input-wrapper { | |
| @apply flex flex-wrap items-center gap-1.5 p-1.5 min-h-[42px] | |
| border border-gray-300 rounded-lg bg-white | |
| focus-within:ring-2 focus-within:ring-medical-500 focus-within:border-transparent | |
| transition-all duration-200; | |
| } | |
| .tag-input-wrapper:focus-within { | |
| box-shadow: 0 0 0 3px rgba(59,130,246,0.12); | |
| } | |
| /* 步骤连接线 */ | |
| .step-connector { | |
| @apply relative flex-1 h-0.5 bg-gray-200 mx-2; | |
| } | |
| .step-connector.active { | |
| background: linear-gradient(90deg, #3b82f6, #2563eb); | |
| animation: status-flow 0.6s ease-out; | |
| } | |
| [data-theme="emerald"] .step-connector.active { background: linear-gradient(90deg, #10b981, #059669); } | |
| [data-theme="cyan"] .step-connector.active { background: linear-gradient(90deg, #06b6d4, #0891b2); } | |
| /* 时间线节点 */ | |
| .timeline-dot { | |
| @apply relative w-3.5 h-3.5 rounded-full border-2 border-medical-500 bg-white z-10 shrink-0; | |
| box-shadow: 0 0 0 3px rgba(59,130,246,0.12); | |
| } | |
| .timeline-dot.active { | |
| @apply bg-medical-500 border-medical-600; | |
| animation: pulse-ring 2s ease-in-out infinite; | |
| } | |
| .timeline-line { | |
| @apply absolute left-[6px] top-3.5 bottom-0 w-0.5 bg-gray-200; | |
| } | |
| .timeline-line.active { | |
| background: linear-gradient(to bottom, #3b82f6, #2563eb); | |
| } | |
| /* 数据表格行 hover */ | |
| .table-row-hover { @apply transition-all duration-150; } | |
| .table-row-hover:hover { @apply bg-medical-50/50 -translate-y-px shadow-sm relative z-10; } | |
| /* 空状态增强 */ | |
| .empty-state-animated .empty-state-icon { | |
| animation: float 3s ease-in-out infinite, shimmer 3s ease-in-out infinite; | |
| } | |
| /* 彩色顶部条变体 */ | |
| .card-accent-blue { border-top: 3px solid #3b82f6; } | |
| .card-accent-green { border-top: 3px solid #10b981; } | |
| .card-accent-amber { border-top: 3px solid #f59e0b; } | |
| .card-accent-red { border-top: 3px solid #ef4444; } | |
| .card-accent-purple { border-top: 3px solid #8b5cf6; } | |
| /* 呼吸脉冲按钮 */ | |
| .animate-breathing { animation: breathing 2.5s ease-in-out infinite; } | |
| /* 统计卡片辉光悬停 */ | |
| .stat-card-glow { transition: box-shadow 0.4s ease, transform 0.3s ease; } | |
| .stat-card-glow:hover { | |
| transform: translateY(-3px); | |
| animation: stat-glow 2s ease-in-out infinite; | |
| } | |
| /* 数字弹跳 */ | |
| .animate-count-pop { animation: count-pop 0.5s cubic-bezier(.34,1.56,.64,1); } | |
| /* 状态脉冲 */ | |
| .animate-status-pulse { animation: status-pulse 0.5s ease-out; } | |
| /* 字段聚焦 */ | |
| .animate-field-ripple:focus { animation: field-ripple 0.6s ease-out; } | |
| /* 面板弹入 */ | |
| .animate-panel-up { animation: panel-slide-up 0.4s cubic-bezier(.16,1,.3,1); } | |
| /* 缩放呼吸 */ | |
| .animate-scale-breathing { animation: scale-breathing 3s ease-in-out infinite; } | |
| /* 筛选芯片 */ | |
| .chip-active { | |
| @apply bg-medical-600 text-white border-medical-600; | |
| animation: chip-pop 0.3s cubic-bezier(.34,1.2,.64,1); | |
| } | |
| /* 状态指示点 */ | |
| .status-dot { | |
| @apply inline-block w-2 h-2 rounded-full; | |
| } | |
| .status-dot.live { @apply bg-green-500; animation: status-dot-pulse 2s ease-in-out infinite; } | |
| .status-dot.warn { @apply bg-amber-500; animation: status-dot-pulse 3s ease-in-out infinite; } | |
| .status-dot.idle { @apply bg-gray-300; } | |
| /* 进度条条纹 */ | |
| .progress-striped { | |
| background-image: linear-gradient(45deg, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); | |
| background-size: 1rem 1rem; | |
| animation: progress-stripes 1s linear infinite; | |
| } | |
| /* 不确定进度条(条纹流动,用于无确切进度的下载场景) */ | |
| .animate-indeterminate-progress { | |
| background-size: 200% 100% ; | |
| animation: indeterminate-progress 1.8s ease-in-out infinite; | |
| } | |
| /* 上传头像光环 */ | |
| .avatar-upload-ring { | |
| @apply absolute inset-0 rounded-full; | |
| border: 2px dashed theme('colors.medical.500'); | |
| animation: avatar-ring-rotate 8s linear infinite; | |
| } | |
| /* 数值高亮 */ | |
| .value-highlight { animation: value-highlight 0.6s ease-out; } | |
| /* 徽章摆动 */ | |
| .animate-badge-swing { animation: badge-swing 0.6s ease-in-out; } | |
| /* 库存告警脉冲 */ | |
| .stock-alert-pulse { animation: low-stock-pulse 2s ease-in-out infinite; } | |
| /* ===== 触觉视觉反馈 ===== */ | |
| .haptic-feedback:active { | |
| animation: haptic-flash 0.4s ease-out; | |
| --haptic-color: rgba(59,130,246,0.35); | |
| } | |
| [data-theme="emerald"] .haptic-feedback:active { --haptic-color: rgba(16,185,129,0.35); } | |
| [data-theme="cyan"] .haptic-feedback:active { --haptic-color: rgba(6,182,212,0.35); } | |
| /* ===== 进度环 SVG 组件 ===== */ | |
| .progress-ring { | |
| transform: rotate(-90deg); | |
| } | |
| .progress-ring-circle-bg { | |
| fill: none; | |
| stroke: #e5e7eb; | |
| } | |
| .progress-ring-circle-fill { | |
| fill: none; | |
| stroke: #3b82f6; | |
| stroke-linecap: round; | |
| transition: stroke-dashoffset 0.6s ease-out; | |
| } | |
| [data-theme="emerald"] .progress-ring-circle-fill { stroke: #10b981; } | |
| [data-theme="cyan"] .progress-ring-circle-fill { stroke: #06b6d4; } | |
| /* ===== 空状态插图增强 ===== */ | |
| .empty-state-illustration { | |
| @apply flex flex-col items-center justify-center py-16 px-4 text-center; | |
| } | |
| .empty-state-illustration-icon { | |
| @apply w-20 h-20 mx-auto mb-5; | |
| animation: float 3s ease-in-out infinite; | |
| opacity: 0.6; | |
| } | |
| .empty-state-illustration-title { | |
| @apply text-base font-semibold text-gray-600 mb-2; | |
| } | |
| .empty-state-illustration-desc { | |
| @apply text-sm text-gray-400 mb-6 max-w-sm; | |
| } | |
| /* ===== #7 表格行交互增强 ===== */ | |
| /* 斑马条纹 */ | |
| .table-zebra tbody tr:nth-child(even) { | |
| @apply bg-gray-50/80; | |
| } | |
| .table-zebra tbody tr:nth-child(odd) { | |
| @apply bg-white; | |
| } | |
| /* 行 hover 高亮 + 轻微 scale */ | |
| .table-hover-row tbody tr { | |
| @apply transition-all duration-200; | |
| } | |
| .table-hover-row tbody tr:hover { | |
| @apply bg-medical-50/60 scale-[1.005] shadow-sm relative z-10; | |
| } | |
| .table-hover-row tbody tr:hover td:first-child { | |
| @apply rounded-l-lg; | |
| } | |
| .table-hover-row tbody tr:hover td:last-child { | |
| @apply rounded-r-lg; | |
| } | |
| /* 选中行左侧蓝色边框指示 */ | |
| .table-selected-row tbody tr.selected { | |
| @apply relative bg-medical-50/70; | |
| } | |
| .table-selected-row tbody tr.selected::before { | |
| content: ''; | |
| @apply absolute left-0 top-0 bottom-0 w-1 bg-medical-500 rounded-r-full; | |
| animation: sidebar-active-indicator 0.35s ease-out; | |
| } | |
| /* ===== #12 Tab 内容切换动画 ===== */ | |
| .tab-content-enter { | |
| animation: tab-crossfade-enter 0.3s ease-out; | |
| } | |
| .tab-content-exit { | |
| animation: tab-crossfade-exit 0.2s ease-in forwards; | |
| } | |
| /* ===== #14 下拉菜单动画 ===== */ | |
| .dropdown-enter { | |
| animation: dropdown-scale-in 0.25s cubic-bezier(.34,1.2,.64,1); | |
| transform-origin: top; | |
| } | |
| .dropdown-exit { | |
| animation: dropdown-scale-out 0.18s ease-in forwards; | |
| transform-origin: top; | |
| } | |
| } | |
| /* ================================================================ | |
| 深度动画系统 (v2) — 15项升级 · 工具类 | |
| ================================================================ */ | |
| /* ----- 1. float-in:元素从下方浮动进入 ----- */ | |
| .animate-float-in { | |
| animation: float-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both; | |
| } | |
| .animate-float-in-delay-1 { animation-delay: 0.1s; } | |
| .animate-float-in-delay-2 { animation-delay: 0.2s; } | |
| .animate-float-in-delay-3 { animation-delay: 0.3s; } | |
| .animate-float-in-delay-4 { animation-delay: 0.4s; } | |
| .animate-float-in-delay-5 { animation-delay: 0.5s; } | |
| /* ----- 2. glow-border:边框发光动画 ----- */ | |
| .glow-border { | |
| transition: box-shadow 0.3s ease; | |
| } | |
| .glow-border:focus, | |
| .glow-border:focus-within { | |
| animation: glow-border-pulse 2s ease-in-out infinite; | |
| border-color: #3b82f6; | |
| } | |
| [data-theme="emerald"] .glow-border:focus, | |
| [data-theme="emerald"] .glow-border:focus-within { | |
| border-color: #059669; | |
| animation: none; | |
| box-shadow: 0 0 0 4px rgba(16,185,129,0.12), 0 0 12px rgba(16,185,129,0.25); | |
| } | |
| [data-theme="cyan"] .glow-border:focus, | |
| [data-theme="cyan"] .glow-border:focus-within { | |
| border-color: #0891b2; | |
| animation: none; | |
| box-shadow: 0 0 0 4px rgba(6,182,212,0.12), 0 0 12px rgba(6,182,212,0.25); | |
| } | |
| /* ----- 3. count-up:数字滚动动画(配合 JS 使用)----- */ | |
| .animate-count-up { | |
| display: inline-block; | |
| overflow: hidden; | |
| } | |
| .animate-count-up .count-digit { | |
| display: inline-block; | |
| animation: count-up-slide 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) both; | |
| } | |
| /* ----- 4. typewriter-enhanced:增强打字机效果 ----- */ | |
| .typewriter-text { | |
| overflow: hidden; | |
| white-space: nowrap; | |
| border-right: 2px solid transparent; | |
| width: 0; | |
| animation: typing 3s steps(40) 1s forwards; | |
| } | |
| .typewriter-cursor { | |
| border-right: 2px solid #3b82f6; | |
| } | |
| [data-theme="emerald"] .typewriter-cursor { border-right-color: #10b981; } | |
| [data-theme="cyan"] .typewriter-cursor { border-right-color: #06b6d4; } | |
| /* 打字完成后的闪烁光标 */ | |
| .typewriter-cursor::after { | |
| content: '|'; | |
| display: inline-block; | |
| margin-left: 1px; | |
| animation: typewriter-cursor-blink 0.8s step-end infinite; | |
| color: #3b82f6; | |
| font-weight: 300; | |
| } | |
| [data-theme="emerald"] .typewriter-cursor::after { color: #10b981; } | |
| [data-theme="cyan"] .typewriter-cursor::after { color: #06b6d4; } | |
| /* 多行打字:移除 nowrap,逐段显示 */ | |
| .typewriter-text.multiline { | |
| white-space: normal; | |
| width: auto; | |
| animation: none; | |
| } | |
| /* ----- 5. spotlight:聚光灯扫描效果 ----- */ | |
| .spotlight-card { | |
| position: relative; | |
| overflow: hidden; | |
| --mouse-x: 50%; | |
| --mouse-y: 50%; | |
| } | |
| .spotlight-card::before { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: radial-gradient( | |
| 600px circle at var(--mouse-x) var(--mouse-y), | |
| rgba(59,130,246,0.12), | |
| transparent 50% | |
| ); | |
| opacity: 0; | |
| transition: opacity 0.3s ease; | |
| pointer-events: none; | |
| z-index: 1; | |
| } | |
| [data-theme="emerald"] .spotlight-card::before { | |
| background: radial-gradient(600px circle at var(--mouse-x) var(--mouse-y), rgba(16,185,129,0.12), transparent 50%); | |
| } | |
| [data-theme="cyan"] .spotlight-card::before { | |
| background: radial-gradient(600px circle at var(--mouse-x) var(--mouse-y), rgba(6,182,212,0.12), transparent 50%); | |
| } | |
| .spotlight-card:hover::before { | |
| opacity: 1; | |
| } | |
| /* ----- 6. morph-bg:渐变背景流动 ----- */ | |
| .morph-bg { | |
| background: linear-gradient(270deg, #3b82f6, #8b5cf6, #ec4899, #f59e0b, #3b82f6); | |
| background-size: 400% 400%; | |
| animation: morph-bg-flow 12s ease infinite; | |
| } | |
| [data-theme="emerald"] .morph-bg { | |
| background: linear-gradient(270deg, #10b981, #059669, #047857, #34d399, #10b981); | |
| background-size: 400% 400%; | |
| } | |
| [data-theme="cyan"] .morph-bg { | |
| background: linear-gradient(270deg, #06b6d4, #0891b2, #0e7490, #22d3ee, #06b6d4); | |
| background-size: 400% 400%; | |
| } | |
| /* ----- 7. breathe-scale:呼吸缩放 ----- */ | |
| .breathe { | |
| animation: breathe-scale 2s ease-in-out infinite; | |
| will-change: transform; | |
| } | |
| .breathe-slow { | |
| animation: breathe-scale-slow 3.5s ease-in-out infinite; | |
| will-change: transform; | |
| } | |
| /* ----- 8. stagger-list:列表逐项延迟出现 ----- */ | |
| .stagger-list > .stagger-item { | |
| opacity: 0; | |
| animation: stagger-item-in 0.4s ease-out forwards; | |
| } | |
| .stagger-list > .stagger-item:nth-child(1) { animation-delay: 0.05s; } | |
| .stagger-list > .stagger-item:nth-child(2) { animation-delay: 0.1s; } | |
| .stagger-list > .stagger-item:nth-child(3) { animation-delay: 0.15s; } | |
| .stagger-list > .stagger-item:nth-child(4) { animation-delay: 0.2s; } | |
| .stagger-list > .stagger-item:nth-child(5) { animation-delay: 0.25s; } | |
| .stagger-list > .stagger-item:nth-child(6) { animation-delay: 0.3s; } | |
| .stagger-list > .stagger-item:nth-child(7) { animation-delay: 0.35s; } | |
| .stagger-list > .stagger-item:nth-child(8) { animation-delay: 0.4s; } | |
| .stagger-list > .stagger-item:nth-child(9) { animation-delay: 0.45s; } | |
| .stagger-list > .stagger-item:nth-child(10) { animation-delay: 0.5s; } | |
| /* ----- 9. draw-underline:下划线绘制动画 ----- */ | |
| .draw-underline { | |
| position: relative; | |
| text-decoration: none; | |
| cursor: pointer; | |
| } | |
| .draw-underline::after { | |
| content: ''; | |
| position: absolute; | |
| bottom: -2px; | |
| left: 0; | |
| width: 100%; | |
| height: 2px; | |
| background: #3b82f6; | |
| border-radius: 1px; | |
| transform: scaleX(0); | |
| transform-origin: left center; | |
| transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| } | |
| [data-theme="emerald"] .draw-underline::after { background: #10b981; } | |
| [data-theme="cyan"] .draw-underline::after { background: #06b6d4; } | |
| .draw-underline:hover::after, | |
| .draw-underline.active::after { | |
| transform: scaleX(1); | |
| } | |
| /* 从中心展开的变体 */ | |
| .draw-underline-center::after { | |
| transform-origin: center center; | |
| } | |
| /* ----- 10. flip-card:3D 卡片翻转 ----- */ | |
| .flip-card { | |
| perspective: 1000px; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .flip-card-inner { | |
| position: relative; | |
| width: 100%; | |
| height: 100%; | |
| transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| transform-style: preserve-3d; | |
| } | |
| .flip-card:hover .flip-card-inner, | |
| .flip-card.flipped .flip-card-inner { | |
| transform: perspective(800px) rotateY(180deg); | |
| } | |
| .flip-card-front, | |
| .flip-card-back { | |
| position: absolute; | |
| inset: 0; | |
| backface-visibility: hidden; | |
| border-radius: inherit; | |
| } | |
| .flip-card-front { | |
| z-index: 2; | |
| } | |
| .flip-card-back { | |
| transform: rotateY(180deg); | |
| z-index: 1; | |
| } | |
| /* ----- 11. wave-ripple:水波纹扩散(配合 JS 使用)----- */ | |
| .wave-ripple { | |
| position: relative; | |
| overflow: hidden; | |
| -webkit-mask-image: -webkit-radial-gradient(white, black); | |
| } | |
| .wave-ripple .ripple-circle { | |
| position: absolute; | |
| border-radius: 50%; | |
| border: 1px solid rgba(59,130,246,0.3); | |
| background: rgba(59,130,246,0.1); | |
| animation: wave-ripple-expand 0.8s ease-out forwards; | |
| pointer-events: none; | |
| } | |
| [data-theme="emerald"] .wave-ripple .ripple-circle { | |
| border-color: rgba(16,185,129,0.3); | |
| background: rgba(16,185,129,0.1); | |
| } | |
| [data-theme="cyan"] .wave-ripple .ripple-circle { | |
| border-color: rgba(6,182,212,0.3); | |
| background: rgba(6,182,212,0.1); | |
| } | |
| /* ----- 12. elastic-bounce:弹性弹跳 ----- */ | |
| .elastic-bounce { | |
| animation: elastic-bounce 1.2s cubic-bezier(0.34, 1.56, 0.64, 1) both; | |
| } | |
| /* ----- 13. dissolve-out:烟雾消散 ----- */ | |
| .dissolve-out { | |
| animation: dissolve-out 0.6s ease-in forwards; | |
| pointer-events: none; | |
| } | |
| /* 消散 + 收缩(用于卡片删除) */ | |
| .dissolve-out-collapse { | |
| animation: | |
| dissolve-out 0.5s ease-in forwards, | |
| collapse-close 0.5s ease-in forwards; | |
| pointer-events: none; | |
| } | |
| /* ----- 14. orbit-spin:轨道旋转加载 ----- */ | |
| .orbit-spinner { | |
| position: relative; | |
| width: 48px; | |
| height: 48px; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .orbit-spinner .orbit-dot { | |
| position: absolute; | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: #3b82f6; | |
| animation: orbit-spin 1.5s linear infinite; | |
| } | |
| [data-theme="emerald"] .orbit-spinner .orbit-dot { background: #10b981; } | |
| [data-theme="cyan"] .orbit-spinner .orbit-dot { background: #06b6d4; } | |
| .orbit-spinner .orbit-dot:nth-child(2) { | |
| animation-delay: -0.5s; | |
| opacity: 0.7; | |
| width: 6px; | |
| height: 6px; | |
| } | |
| .orbit-spinner .orbit-dot:nth-child(3) { | |
| animation-delay: -1s; | |
| opacity: 0.4; | |
| width: 5px; | |
| height: 5px; | |
| } | |
| /* ----- 15. success-burst:成功撒花 ----- */ | |
| .success-burst { | |
| position: relative; | |
| width: 40px; | |
| height: 40px; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| /* 中心勾选标记 */ | |
| .success-burst::before { | |
| content: ''; | |
| position: absolute; | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 50%; | |
| background: #10b981; | |
| z-index: 2; | |
| animation: scale-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) both; | |
| } | |
| /* 多条彩色射线(通过多个 box-shadow 模拟) */ | |
| .success-burst::after { | |
| content: ''; | |
| position: absolute; | |
| width: 4px; | |
| height: 4px; | |
| border-radius: 50%; | |
| background: transparent; | |
| z-index: 1; | |
| animation: success-burst-rotate 2s linear infinite; | |
| box-shadow: | |
| /* 方向 0° (右侧) */ | |
| 12px 0 0 0 #3b82f6, | |
| 16px 0 0 0 rgba(59,130,246,0.6), | |
| 20px 0 0 0 rgba(59,130,246,0.3), | |
| /* 方向 45° */ | |
| 8px 8px 0 0 #8b5cf6, | |
| 11px 11px 0 0 rgba(139,92,246,0.5), | |
| /* 方向 90° (下方) */ | |
| 0 12px 0 0 #10b981, | |
| 0 16px 0 0 rgba(16,185,129,0.6), | |
| /* 方向 135° */ | |
| -8px 8px 0 0 #f59e0b, | |
| -11px 11px 0 0 rgba(245,158,11,0.5), | |
| /* 方向 180° (左侧) */ | |
| -12px 0 0 0 #ec4899, | |
| -16px 0 0 0 rgba(236,72,153,0.5), | |
| /* 方向 225° */ | |
| -8px -8px 0 0 #06b6d4, | |
| -11px -11px 0 0 rgba(6,182,212,0.5), | |
| /* 方向 270° (上方) */ | |
| 0 -12px 0 0 #ef4444, | |
| 0 -16px 0 0 rgba(239,68,68,0.5), | |
| /* 方向 315° */ | |
| 8px -8px 0 0 #22c55e, | |
| 11px -11px 0 0 rgba(34,197,94,0.5); | |
| } | |
| /* ================================================================ | |
| 深度动画系统 (v2) — Reduced Motion 适配 | |
| ================================================================ */ | |
| @media (prefers-reduced-motion: reduce) { | |
| .animate-float-in, | |
| .animate-float-in-delay-1, | |
| .animate-float-in-delay-2, | |
| .animate-float-in-delay-3, | |
| .animate-float-in-delay-4, | |
| .animate-float-in-delay-5 { | |
| animation: none; | |
| opacity: 1; | |
| transform: none; | |
| } | |
| .glow-border:focus, | |
| .glow-border:focus-within { | |
| animation: none; | |
| } | |
| .animate-count-up .count-digit { | |
| animation: none; | |
| opacity: 1; | |
| transform: none; | |
| } | |
| .typewriter-text { | |
| width: auto; | |
| animation: none; | |
| border-right: none; | |
| overflow: visible; | |
| white-space: normal; | |
| } | |
| .typewriter-cursor::after { | |
| animation: none; | |
| opacity: 1; | |
| } | |
| .spotlight-card::before { | |
| display: none; | |
| } | |
| .morph-bg { | |
| animation: none; | |
| background-size: 100% 100%; | |
| } | |
| .breathe, | |
| .breathe-slow { | |
| animation: none; | |
| } | |
| .stagger-list > .stagger-item { | |
| opacity: 1; | |
| animation: none; | |
| animation-delay: 0s; | |
| } | |
| .draw-underline::after { | |
| transition: none; | |
| } | |
| .flip-card-inner { | |
| transition: none; | |
| } | |
| .flip-card:hover .flip-card-inner, | |
| .flip-card.flipped .flip-card-inner { | |
| transform: none; | |
| } | |
| .wave-ripple .ripple-circle { | |
| animation: none; | |
| display: none; | |
| } | |
| .elastic-bounce { | |
| animation: none; | |
| opacity: 1; | |
| transform: none; | |
| } | |
| .dissolve-out, | |
| .dissolve-out-collapse { | |
| animation: none; | |
| opacity: 0; | |
| } | |
| .orbit-spinner .orbit-dot, | |
| .orbit-spinner .orbit-dot:nth-child(2), | |
| .orbit-spinner .orbit-dot:nth-child(3) { | |
| animation: none; | |
| } | |
| .success-burst::after { | |
| animation: none; | |
| box-shadow: none; | |
| } | |
| } | |
| /* ================================================================ | |
| Accessibility - Focus & Screen Reader | |
| ================================================================ */ | |
| /* 键盘焦点可见轮廓(Tailwind 的 focus-visible:ring 已在组件中使用,此处为全局兜底) */ | |
| :focus-visible { | |
| outline: 2px solid #3b82f6; | |
| outline-offset: 2px; | |
| border-radius: 4px; | |
| } | |
| [data-theme="emerald"] :focus-visible { outline-color: #059669; } | |
| [data-theme="cyan"] :focus-visible { outline-color: #0891b2; } | |
| /* 对于已有关注样式(如 ring)的元素取消默认 outline */ | |
| :focus-visible:has([class*="ring-"]), | |
| input:focus-visible, | |
| textarea:focus-visible, | |
| select:focus-visible, | |
| button:focus-visible { | |
| outline: none; | |
| } | |
| /* ===== 跳转到主内容(Skip to Content)===== */ | |
| .skip-to-content { | |
| position: fixed; | |
| top: -100px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| z-index: 10000; | |
| padding: 0.5rem 1rem; | |
| background: #2563eb; | |
| color: #fff; | |
| font-size: 0.875rem; | |
| font-weight: 500; | |
| border-radius: 0 0 0.5rem 0.5rem; | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.15); | |
| transition: top 0.2s; | |
| outline: none; | |
| } | |
| .skip-to-content:focus { | |
| top: 0; | |
| } | |
| /* ===== 仅屏幕阅读器可见 ===== */ | |
| .sr-only { | |
| position: absolute; | |
| width: 1px; | |
| height: 1px; | |
| padding: 0; | |
| margin: -1px; | |
| overflow: hidden; | |
| clip: rect(0, 0, 0, 0); | |
| white-space: nowrap; | |
| border-width: 0; | |
| } | |
| /* ===== 减少动画偏好 ===== */ | |
| @media (prefers-reduced-motion: reduce) { | |
| .page-transition-wrapper *, | |
| .page-transition-wrapper *::before, | |
| .page-transition-wrapper *::after { | |
| animation-duration: 0.01ms ; | |
| animation-iteration-count: 1 ; | |
| transition-duration: 0.01ms ; | |
| } | |
| } | |
| /* ================================================================ | |
| 动画性能优化 - GPU 合成层 & 渲染隔离 | |
| 使用 will-change / contain / translateZ 减少重绘和回流 | |
| ================================================================ */ | |
| /* ---- GPU 合成层:将元素提升到独立图层,避免触发整体重绘 ---- */ | |
| .gpu-layer { | |
| transform: translateZ(0); | |
| backface-visibility: hidden; | |
| perspective: 1000px; | |
| } | |
| /* ---- 渲染隔离:限制浏览器重绘范围 ---- */ | |
| .render-isolated { | |
| contain: layout style paint; | |
| } | |
| /* ---- 仅动画期间启用 will-change(动画结束后应移除,此处提供基础类) ---- */ | |
| .will-animate-transform { | |
| will-change: transform; | |
| } | |
| .will-animate-opacity { | |
| will-change: opacity; | |
| } | |
| .will-animate-both { | |
| will-change: transform, opacity; | |
| } | |
| /* ---- 为 Tailwind 动画类附加 GPU 优化 ---- */ | |
| /* 现有动画类在 hover/animation 时会自动获得 GPU 加速 */ | |
| /* 骨架屏动画:强制 GPU 合成层,避免 layout thrashing */ | |
| .skeleton, | |
| .skeleton-shimmer, | |
| .skeleton-card, | |
| .skeleton-card-line, | |
| .skeleton-avatar { | |
| transform: translateZ(0); | |
| backface-visibility: hidden; | |
| contain: layout style paint; | |
| } | |
| /* 骨架屏动画优化:使用 GPU 友好的 transform 替代 background-position */ | |
| @keyframes skeleton-shimmer-gpu { | |
| 0% { transform: translateX(-100%); } | |
| 100% { transform: translateX(100%); } | |
| } | |
| /* 浮升动画:GPU 加速 */ | |
| .animate-lift, | |
| .hover-lift, | |
| .elevated-card { | |
| transform: translateZ(0); | |
| will-change: transform; | |
| } | |
| /* 缩放动画:GPU 加速 */ | |
| .press-scale, | |
| .press-scale-sm, | |
| .btn-primary, | |
| .btn-secondary, | |
| .btn-danger, | |
| .btn-ghost { | |
| transform: translateZ(0); | |
| } | |
| /* 渐变流动:GPU 合成层 */ | |
| .animate-gradient-flow, | |
| .text-gradient { | |
| transform: translateZ(0); | |
| backface-visibility: hidden; | |
| } | |
| /* 通知点和状态指示器:GPU 合成(频繁更新) */ | |
| .notify-dot, | |
| .notify-dot-sm, | |
| .status-dot, | |
| .pulse-dot, | |
| .connection-dot { | |
| transform: translateZ(0); | |
| will-change: transform, opacity; | |
| } | |
| /* 页面过渡动画:GPU 合成 */ | |
| .page-enter, | |
| .page-exit, | |
| .crossfade-enter, | |
| .crossfade-exit, | |
| .page-transition-wrapper * { | |
| transform: translateZ(0); | |
| backface-visibility: hidden; | |
| } | |
| /* Spinner:GPU 合成旋转 */ | |
| .animate-spin, | |
| .spinner, | |
| .animate-spin-slow { | |
| transform: translateZ(0); | |
| } | |
| /* ================================================================ | |
| Animations - Keyframes | |
| ================================================================ */ | |
| @keyframes shimmer { | |
| 0% { background-position: 200% 0; } | |
| 100% { background-position: -200% 0; } | |
| } | |
| @keyframes fade-in-up { | |
| 0% { opacity: 0; transform: translateY(16px); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes scale-in { | |
| 0% { opacity: 0; transform: scale(0.9); } | |
| 100% { opacity: 1; transform: scale(1); } | |
| } | |
| @keyframes slide-in { | |
| 0% { opacity: 0; transform: translateX(24px); } | |
| 100% { opacity: 1; transform: translateX(0); } | |
| } | |
| @keyframes number-pop { | |
| 0% { transform: scale(0.6); opacity: 0; } | |
| 60% { transform: scale(1.15); opacity: 1; } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| @keyframes glow-pulse { | |
| 0%, 100% { box-shadow: 0 0 0 0 rgba(59,130,246,0); } | |
| 50% { box-shadow: 0 0 20px 4px rgba(59,130,246,0.3); } | |
| } | |
| @keyframes gradient-flow { | |
| 0% { background-position: 0% 50%; } | |
| 50% { background-position: 100% 50%; } | |
| 100% { background-position: 0% 50%; } | |
| } | |
| @keyframes float { | |
| 0%, 100% { transform: translateY(0px); } | |
| 50% { transform: translateY(-8px); } | |
| } | |
| @keyframes shake { | |
| 0%, 100% { transform: translateX(0); } | |
| 10%, 50%, 90% { transform: translateX(-4px); } | |
| 30%, 70% { transform: translateX(4px); } | |
| } | |
| @keyframes bounce-in { | |
| 0% { opacity: 0; transform: scale(0.3); } | |
| 50% { opacity: 1; transform: scale(1.05); } | |
| 70% { transform: scale(0.95); } | |
| 100% { transform: scale(1); } | |
| } | |
| @keyframes spin-in { | |
| 0% { opacity: 0; transform: rotate(-180deg) scale(0.3); } | |
| 100% { opacity: 1; transform: rotate(0deg) scale(1); } | |
| } | |
| @keyframes skeleton-pulse { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0.4; } | |
| } | |
| @keyframes ripple-expand { | |
| 0% { width: 0; height: 0; opacity: 0.5; } | |
| 100% { width: 500px; height: 500px; opacity: 0; } | |
| } | |
| @keyframes ring-pulse { | |
| 0% { box-shadow: 0 0 0 0 rgba(59,130,246,0.4); } | |
| 70% { box-shadow: 0 0 0 20px rgba(59,130,246,0); } | |
| 100% { box-shadow: 0 0 0 0 rgba(59,130,246,0); } | |
| } | |
| @keyframes slide-up-in { | |
| 0% { opacity: 0; transform: translateY(100%); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes slide-out-down { | |
| 0% { opacity: 1; transform: translateY(0); } | |
| 100% { opacity: 0; transform: translateY(20px); } | |
| } | |
| @keyframes checkmark-draw { | |
| 0% { stroke-dashoffset: 50; } | |
| 100% { stroke-dashoffset: 0; } | |
| } | |
| @keyframes progress-grow { | |
| 0% { width: 0%; } | |
| } | |
| @keyframes tab-underline { | |
| 0% { transform: scaleX(0); } | |
| 100% { transform: scaleX(1); } | |
| } | |
| @keyframes card-flip-in { | |
| 0% { transform: rotateY(90deg); opacity: 0; } | |
| 100% { transform: rotateY(0deg); opacity: 1; } | |
| } | |
| @keyframes float-up-fade { | |
| 0% { opacity: 1; transform: translateY(0) scale(1); } | |
| 100% { opacity: 0; transform: translateY(-40px) scale(0.8); } | |
| } | |
| @keyframes dot-bounce { | |
| 0%, 80%, 100% { transform: scale(0); } | |
| 40% { transform: scale(1); } | |
| } | |
| @keyframes divider-slide { | |
| 0% { transform: translateX(-100%); } | |
| 100% { transform: translateX(100%); } | |
| } | |
| @keyframes heart-beat { | |
| 0% { transform: scale(1); } | |
| 25% { transform: scale(1.3); } | |
| 50% { transform: scale(0.95); } | |
| 100% { transform: scale(1); } | |
| } | |
| @keyframes fade-in-left { | |
| 0% { opacity: 0; transform: translateX(-20px); } | |
| 100% { opacity: 1; transform: translateX(0); } | |
| } | |
| @keyframes crossfade-in { | |
| 0% { opacity: 0; transform: scale(0.97); } | |
| 100% { opacity: 1; transform: scale(1); } | |
| } | |
| @keyframes crossfade-out { | |
| 0% { opacity: 1; transform: scale(1); } | |
| 100% { opacity: 0; transform: scale(0.97); } | |
| } | |
| @keyframes typing { | |
| from { width: 0; } | |
| to { width: 100%; } | |
| } | |
| @keyframes blink-caret { | |
| from, to { border-color: transparent; } | |
| 50% { border-color: #3b82f6; } | |
| } | |
| @keyframes spin { | |
| from { transform: rotate(0deg); } | |
| to { transform: rotate(360deg); } | |
| } | |
| @keyframes wave-move { | |
| 0% { transform: translateX(0); } | |
| 100% { transform: translateX(-50%); } | |
| } | |
| @keyframes pulse-dot { | |
| 0%, 100% { transform: scale(1); opacity: 0.7; } | |
| 50% { transform: scale(1.8); opacity: 0.2; } | |
| } | |
| @keyframes slide-down-in { | |
| 0% { opacity: 0; transform: translateY(-12px); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes slide-up-out { | |
| 0% { opacity: 1; transform: translateY(0); } | |
| 100% { opacity: 0; transform: translateY(-12px); } | |
| } | |
| @keyframes notification-bounce { | |
| 0% { transform: scale(0); opacity: 0; } | |
| 50% { transform: scale(1.3); } | |
| 70% { transform: scale(0.9); } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| @keyframes confetti-fall { | |
| 0% { transform: translateY(-100%) rotate(0deg); opacity: 1; } | |
| 100% { transform: translateY(100vh) rotate(720deg); opacity: 0; } | |
| } | |
| @keyframes status-flow { | |
| 0% { width: 0%; } | |
| 100% { width: 100%; } | |
| } | |
| @keyframes pull-indicator { | |
| 0% { transform: translateY(-20px); opacity: 0; } | |
| 50% { opacity: 1; } | |
| 100% { transform: translateY(0); opacity: 1; } | |
| } | |
| @keyframes copy-popup { | |
| 0% { opacity: 0; transform: translateY(8px) scale(0.9); } | |
| 20% { opacity: 1; transform: translateY(0) scale(1.05); } | |
| 30% { transform: scale(0.95); } | |
| 100% { opacity: 1; transform: translateY(0) scale(1); } | |
| } | |
| @keyframes longpress-ripple { | |
| 0% { transform: scale(0); opacity: 0.6; } | |
| 100% { transform: scale(4); opacity: 0; } | |
| } | |
| @keyframes pulse-ring { | |
| 0% { box-shadow: 0 0 0 0 rgba(59,130,246,0.5); } | |
| 70% { box-shadow: 0 0 0 12px rgba(59,130,246,0); } | |
| 100% { box-shadow: 0 0 0 0 rgba(59,130,246,0); } | |
| } | |
| @keyframes auto-save-dot { | |
| 0%, 100% { opacity: 0.4; transform: scale(0.8); } | |
| 50% { opacity: 1; transform: scale(1.2); } | |
| } | |
| @keyframes stage-enter { | |
| 0% { opacity: 0; transform: translateX(40px); } | |
| 100% { opacity: 1; transform: translateX(0); } | |
| } | |
| @keyframes stage-exit { | |
| 0% { opacity: 1; transform: translateX(0); } | |
| 100% { opacity: 0; transform: translateX(-40px); } | |
| } | |
| @keyframes collapse-open { | |
| 0% { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; } | |
| 100% { max-height: 2000px; opacity: 1; } | |
| } | |
| @keyframes collapse-close { | |
| 0% { max-height: 2000px; opacity: 1; } | |
| 100% { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; } | |
| } | |
| @keyframes shimmer-fast { | |
| 0% { background-position: -200% 0; } | |
| 100% { background-position: 200% 0; } | |
| } | |
| @keyframes count-badge { | |
| 0% { transform: scale(0.3); opacity: 0; } | |
| 60% { transform: scale(1.1); } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| @keyframes menu-slide-in { | |
| 0% { opacity: 0; transform: scale(0.95) translateY(-4px); } | |
| 100% { opacity: 1; transform: scale(1) translateY(0); } | |
| } | |
| @keyframes indicator-dash { | |
| to { stroke-dashoffset: -100; } | |
| } | |
| @keyframes skeleton-wave { | |
| 0% { background-position: 200% 50%; } | |
| 100% { background-position: -200% 50%; } | |
| } | |
| @keyframes rotate-180 { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(180deg); } | |
| } | |
| @keyframes rotate-back { | |
| 0% { transform: rotate(180deg); } | |
| 100% { transform: rotate(0deg); } | |
| } | |
| @keyframes highlight-flash { | |
| 0% { background-color: rgba(59,130,246,0.15); } | |
| 100% { background-color: transparent; } | |
| } | |
| @keyframes toast-enter { | |
| 0% { opacity: 0; transform: translateX(100%) scale(0.95); } | |
| 100% { opacity: 1; transform: translateX(0) scale(1); } | |
| } | |
| @keyframes toast-exit { | |
| 0% { opacity: 1; transform: translateX(0) scale(1); } | |
| 100% { opacity: 0; transform: translateX(100%) scale(0.95); } | |
| } | |
| /* Modal 进入动画 */ | |
| @keyframes modal-enter { | |
| 0% { opacity: 0; transform: scale(0.92) translateY(12px); } | |
| 100% { opacity: 1; transform: scale(1) translateY(0); } | |
| } | |
| @keyframes avatar-upload { | |
| 0% { opacity: 0; transform: scale(0.8); } | |
| 100% { opacity: 1; transform: scale(1); } | |
| } | |
| /* 呼吸脉冲 */ | |
| @keyframes breathing { | |
| 0%, 100% { transform: scale(1); opacity: 1; } | |
| 50% { transform: scale(1.06); opacity: 0.85; } | |
| } | |
| /* 统计卡片辉光 */ | |
| @keyframes stat-glow { | |
| 0%, 100% { box-shadow: 0 0 0 0 rgba(59,130,246,0); } | |
| 50% { box-shadow: 0 0 16px 4px rgba(59,130,246,0.15); } | |
| } | |
| /* 数字弹跳计数 */ | |
| @keyframes count-pop { | |
| 0% { transform: translateY(20px); opacity: 0; } | |
| 40% { transform: translateY(-4px); opacity: 1; } | |
| 60% { transform: translateY(2px); } | |
| 100% { transform: translateY(0); opacity: 1; } | |
| } | |
| /* 状态改变脉冲 */ | |
| @keyframes status-pulse { | |
| 0% { transform: scale(1); } | |
| 20% { transform: scale(1.12); } | |
| 100% { transform: scale(1); } | |
| } | |
| /* 字段聚焦波纹 */ | |
| @keyframes field-ripple { | |
| 0% { box-shadow: 0 0 0 0 rgba(59,130,246,0.3); } | |
| 100% { box-shadow: 0 0 0 8px rgba(59,130,246,0); } | |
| } | |
| /* 上传进度环 */ | |
| @keyframes upload-ring { | |
| 0% { stroke-dashoffset: 283; } | |
| 100% { stroke-dashoffset: 0; } | |
| } | |
| /* 404 浮动动画 */ | |
| @keyframes float-404 { | |
| 0%, 100% { transform: translateY(0) rotate(0deg); } | |
| 25% { transform: translateY(-12px) rotate(2deg); } | |
| 75% { transform: translateY(-6px) rotate(-2deg); } | |
| } | |
| /* 筛选芯片切换 */ | |
| @keyframes chip-pop { | |
| 0% { transform: scale(0.85); opacity: 0; } | |
| 60% { transform: scale(1.05); } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| /* 状态点闪烁 */ | |
| @keyframes status-dot-pulse { | |
| 0%, 100% { opacity: 1; transform: scale(1); } | |
| 50% { opacity: 0.5; transform: scale(1.3); } | |
| } | |
| /* 加载进度条条纹 */ | |
| @keyframes progress-stripes { | |
| 0% { background-position: 1rem 0; } | |
| 100% { background-position: 0 0; } | |
| } | |
| /* 不确定进度条(条纹流动效果) */ | |
| @keyframes indeterminate-progress { | |
| 0% { background-position: 200% 0; } | |
| 100% { background-position: -200% 0; } | |
| } | |
| /* 面板滑入 */ | |
| @keyframes panel-slide-up { | |
| 0% { opacity: 0; transform: translateY(20px) scale(0.97); } | |
| 100% { opacity: 1; transform: translateY(0) scale(1); } | |
| } | |
| /* 遮罩淡入 */ | |
| @keyframes backdrop-in { | |
| 0% { opacity: 0; backdrop-filter: blur(0); } | |
| 100% { opacity: 1; backdrop-filter: blur(4px); } | |
| } | |
| /* 缩放呼吸 */ | |
| @keyframes scale-breathing { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.04); } | |
| } | |
| /* 下拉菜单分隔线动画 */ | |
| @keyframes menu-divider-grow { | |
| 0% { transform: scaleX(0); } | |
| 100% { transform: scaleX(1); } | |
| } | |
| /* 头像光环旋转 */ | |
| @keyframes avatar-ring-rotate { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| /* 库存低库存脉冲 */ | |
| @keyframes low-stock-pulse { | |
| 0%, 100% { background-color: rgba(239,68,68,0.05); } | |
| 50% { background-color: rgba(239,68,68,0.15); } | |
| } | |
| /* 值高亮闪烁 */ | |
| @keyframes value-highlight { | |
| 0% { color: #2563eb; transform: scale(1.05); } | |
| 50% { color: #3b82f6; } | |
| 100% { color: inherit; transform: scale(1); } | |
| } | |
| /* 徽章摆动 */ | |
| @keyframes badge-swing { | |
| 0%, 100% { transform: rotate(0deg); } | |
| 25% { transform: rotate(5deg); } | |
| 75% { transform: rotate(-5deg); } | |
| } | |
| /* Toast 进度条收缩 */ | |
| @keyframes progress-shrink { | |
| 0% { width: 100%; } | |
| 100% { width: 0%; } | |
| } | |
| /* ================================================================ | |
| Additional Micro-Interaction Utilities | |
| ================================================================ */ | |
| /* 滑动入场(上) */ | |
| .animate-slide-up { | |
| animation: slide-up-in 0.4s ease-out both; | |
| } | |
| /* 心脏跳动动画 */ | |
| .animate-heart-beat { | |
| animation: heart-beat 0.4s ease-in-out; | |
| } | |
| /* 计数徽章弹入 */ | |
| .animate-count-badge { | |
| animation: count-badge 0.3s ease-out both; | |
| } | |
| /* 滑动删除指示器 */ | |
| .animate-swipe-out { | |
| animation: swipe-out 0.3s ease-in forwards; | |
| } | |
| /* 复选框选中弹跳 */ | |
| .animate-check-pop { | |
| animation: check-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) both; | |
| } | |
| /* 输入框聚焦光晕 */ | |
| .input-glow:focus-within { | |
| box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.15); | |
| border-color: #059669; | |
| } | |
| /* 列表项拖拽手柄 */ | |
| .drag-handle { | |
| cursor: grab; | |
| opacity: 0.3; | |
| transition: opacity 0.2s ease; | |
| } | |
| .drag-handle:hover, | |
| .drag-handle:active { | |
| opacity: 0.6; | |
| } | |
| .drag-handle:active { | |
| cursor: grabbing; | |
| } | |
| /* 可折叠区域指示器 */ | |
| .collapse-indicator { | |
| transition: transform 0.3s ease; | |
| } | |
| .collapse-indicator.open { | |
| transform: rotate(180deg); | |
| } | |
| /* 模态框缩放入场 */ | |
| .modal-scale-enter { | |
| animation: modal-scale-in 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) both; | |
| } | |
| /* 列表项移除动画 */ | |
| .list-item-exit { | |
| animation: list-item-exit 0.3s ease-in forwards; | |
| } | |
| /* 长按涟漪效果 */ | |
| .longpress-ripple { | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .longpress-ripple::after { | |
| content: ''; | |
| position: absolute; | |
| inset: 0; | |
| background: radial-gradient(circle, rgba(5, 150, 105, 0.2) 0%, transparent 70%); | |
| opacity: 0; | |
| transition: opacity 0.3s ease; | |
| } | |
| .longpress-ripple:active::after { | |
| opacity: 1; | |
| } | |
| /* 选中高亮闪烁 */ | |
| .selection-flash { | |
| animation: highlight-flash 0.6s ease-out; | |
| } | |
| /* 数据刷新旋转 */ | |
| .refresh-spin { | |
| animation: spin 0.8s linear; | |
| } | |
| /* 打字光标闪烁 */ | |
| .cursor-blink { | |
| animation: blink-caret 0.8s step-end infinite; | |
| } | |
| /* 加载骨架 - 头像圆形 */ | |
| .skeleton-avatar { | |
| border-radius: 50%; | |
| background: linear-gradient(90deg, #e5e7eb 25%, #f3f4f6 50%, #e5e7eb 75%); | |
| background-size: 200% 100%; | |
| animation: skeleton-wave 1.5s ease-in-out infinite; | |
| } | |
| /* 空状态浮动图标 */ | |
| .empty-state-animated .empty-state-icon { | |
| animation: float 3s ease-in-out infinite; | |
| } | |
| .empty-state-animated .empty-state-title { | |
| animation: fade-in-up 0.5s ease-out 0.3s both; | |
| } | |
| .empty-state-animated .empty-state-desc { | |
| animation: fade-in-up 0.5s ease-out 0.5s both; | |
| } | |
| /* 页面过渡 - 淡入 */ | |
| .page-enter { | |
| animation: crossfade-in 0.35s ease-out both; | |
| } | |
| .page-exit { | |
| animation: crossfade-out 0.2s ease-in both; | |
| } | |
| /* 连接状态指示器脉冲 */ | |
| .connection-dot { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| display: inline-block; | |
| } | |
| .connection-dot.online { | |
| background: #10b981; | |
| animation: status-dot-pulse 2s ease-in-out infinite; | |
| } | |
| .connection-dot.offline { | |
| background: #ef4444; | |
| } | |
| .connection-dot.reconnecting { | |
| background: #f59e0b; | |
| animation: status-dot-pulse 1s ease-in-out infinite; | |
| } | |
| /* 拖拽排序占位 */ | |
| .sortable-placeholder { | |
| border: 2px dashed #d1d5db; | |
| border-radius: 8px; | |
| background: #f9fafb; | |
| min-height: 48px; | |
| opacity: 0.6; | |
| } | |
| /* 快捷操作工具栏 */ | |
| .quick-actions-bar { | |
| backdrop-filter: blur(8px); | |
| background: rgba(255, 255, 255, 0.85); | |
| border-top: 1px solid rgba(0, 0, 0, 0.06); | |
| transition: transform 0.3s ease; | |
| } | |
| .quick-actions-bar.hidden-bar { | |
| transform: translateY(100%); | |
| } | |
| /* 键盘快捷键提示 */ | |
| .kbd { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| min-width: 20px; | |
| height: 20px; | |
| padding: 0 4px; | |
| font-size: 10px; | |
| font-family: inherit; | |
| font-weight: 500; | |
| color: #6b7280; | |
| background: #f3f4f6; | |
| border: 1px solid #e5e7eb; | |
| border-radius: 4px; | |
| border-bottom-width: 2px; | |
| } | |
| /* ================================================================ | |
| Additional Keyframes | |
| ================================================================ */ | |
| @keyframes swipe-out { | |
| 0% { transform: translateX(0); opacity: 1; } | |
| 100% { transform: translateX(100%); opacity: 0; } | |
| } | |
| @keyframes check-pop { | |
| 0% { transform: scale(0); } | |
| 50% { transform: scale(1.3); } | |
| 100% { transform: scale(1); } | |
| } | |
| @keyframes modal-scale-in { | |
| 0% { transform: scale(0.9); opacity: 0; } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| @keyframes list-item-exit { | |
| 0% { max-height: 80px; opacity: 1; margin-bottom: 8px; } | |
| 100% { max-height: 0; opacity: 0; margin-bottom: 0; padding-top: 0; padding-bottom: 0; } | |
| } | |
| /* ================================================================ | |
| Page Transition Keyframes(路由切换动画) | |
| ================================================================ */ | |
| /* 前进(PUSH):从右侧滑入 / 向左侧退出 */ | |
| @keyframes page-slide-from-right { | |
| 0% { opacity: 0; transform: translateX(40px); } | |
| 100% { opacity: 1; transform: translateX(0); } | |
| } | |
| @keyframes page-slide-exit-left { | |
| 0% { opacity: 1; transform: translateX(0); } | |
| 100% { opacity: 0; transform: translateX(-40px); } | |
| } | |
| /* 后退(POP):从左侧滑入 / 向右侧退出 */ | |
| @keyframes page-slide-from-left { | |
| 0% { opacity: 0; transform: translateX(-40px); } | |
| 100% { opacity: 1; transform: translateX(0); } | |
| } | |
| @keyframes page-slide-exit-right { | |
| 0% { opacity: 1; transform: translateX(0); } | |
| 100% { opacity: 0; transform: translateX(40px); } | |
| } | |
| /* 淡入淡出 */ | |
| @keyframes page-crossfade-in { | |
| 0% { opacity: 0; } | |
| 100% { opacity: 1; } | |
| } | |
| @keyframes page-crossfade-out { | |
| 0% { opacity: 1; } | |
| 100% { opacity: 0; } | |
| } | |
| /* 缩放入场 */ | |
| @keyframes page-scale-in { | |
| 0% { opacity: 0; transform: scale(0.95); } | |
| 100% { opacity: 1; transform: scale(1); } | |
| } | |
| @keyframes page-scale-out { | |
| 0% { opacity: 1; transform: scale(1); } | |
| 100% { opacity: 0; transform: scale(0.95); } | |
| } | |
| /* PageTransition 组件使用的 CSS 类 */ | |
| .page-transition-wrapper { | |
| --duration: var(--page-transition-duration, 300ms); | |
| } | |
| /* slide 进入 */ | |
| .page-slide-enter { | |
| animation: page-slide-from-right var(--duration) cubic-bezier(.16,1,.3,1) both; | |
| } | |
| .page-slide-enter.page-from-left { | |
| animation: page-slide-from-left var(--duration) cubic-bezier(.16,1,.3,1) both; | |
| } | |
| /* slide 退出 */ | |
| .page-slide-exit { | |
| animation: page-slide-exit-left var(--duration) cubic-bezier(.5,0,.75,0) both; | |
| } | |
| .page-slide-exit.page-exit-right { | |
| animation: page-slide-exit-right var(--duration) cubic-bezier(.5,0,.75,0) both; | |
| } | |
| /* crossfade */ | |
| .page-crossfade-enter { | |
| animation: page-crossfade-in var(--duration) ease-out both; | |
| } | |
| .page-crossfade-exit { | |
| animation: page-crossfade-out var(--duration) ease-in both; | |
| } | |
| /* scale */ | |
| .page-scale-enter { | |
| animation: page-scale-in var(--duration) cubic-bezier(.34,1.2,.64,1) both; | |
| } | |
| .page-scale-exit { | |
| animation: page-scale-out var(--duration) ease-in both; | |
| } | |
| /* ================================================================ | |
| Micro-Interaction Keyframes | |
| ================================================================ */ | |
| @keyframes pulse-dot-ring { | |
| 0% { transform: scale(1); opacity: 0.8; } | |
| 50% { transform: scale(2.2); opacity: 0; } | |
| 100% { transform: scale(2.2); opacity: 0; } | |
| } | |
| @keyframes skeleton-shimmer-wave { | |
| 0% { background-position: 200% 50%; } | |
| 100% { background-position: -200% 50%; } | |
| } | |
| @keyframes text-reveal-fade { | |
| 0% { opacity: 0; transform: translateY(4px); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes text-reveal-up { | |
| 0% { opacity: 0; transform: translateY(16px); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes typing-blink { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0; } | |
| } | |
| /* 进度环动画 */ | |
| @keyframes progress-ring-fill { | |
| 0% { stroke-dashoffset: var(--ring-circumference, 283); } | |
| } | |
| /* 横幅滑入 */ | |
| @keyframes banner-slide-down { | |
| 0% { transform: translateY(-100%); opacity: 0; } | |
| 100% { transform: translateY(0); opacity: 1; } | |
| } | |
| /* 触觉反馈闪烁 */ | |
| @keyframes haptic-flash { | |
| 0% { box-shadow: 0 0 0 0 var(--haptic-color, rgba(59,130,246,0.4)); } | |
| 50% { box-shadow: 0 0 0 8px rgba(59,130,246,0); } | |
| 100% { box-shadow: 0 0 0 0 rgba(59,130,246,0); } | |
| } | |
| /* 爪印弹跳 */ | |
| @keyframes paw-bounce { | |
| 0%, 100% { transform: scale(1) rotate(0deg); } | |
| 30% { transform: scale(1.1) rotate(5deg); } | |
| 60% { transform: scale(0.95) rotate(-3deg); } | |
| } | |
| /* 心跳线绘制 */ | |
| @keyframes heartbeat-draw { | |
| 0% { stroke-dashoffset: 60; } | |
| 40% { stroke-dashoffset: 0; } | |
| 60% { stroke-dashoffset: 0; } | |
| 100% { stroke-dashoffset: -60; } | |
| } | |
| /* 心跳脉冲 */ | |
| @keyframes heartbeat-pulse { | |
| 0%, 100% { transform: scale(1); opacity: 1; } | |
| 15% { transform: scale(1.6); opacity: 0.7; } | |
| 30% { transform: scale(1); opacity: 1; } | |
| 45% { transform: scale(1.3); opacity: 0.8; } | |
| 60% { transform: scale(1); opacity: 1; } | |
| } | |
| /* DNA 波浪 */ | |
| @keyframes dna-wave { | |
| 0%, 100% { opacity: 0.3; } | |
| 50% { opacity: 1; } | |
| } | |
| /* DNA 横杠 */ | |
| @keyframes dna-bar { | |
| 0%, 100% { opacity: 0.2; } | |
| 50% { opacity: 0.8; } | |
| } | |
| /* 侧边栏活跃指示条滑入 */ | |
| @keyframes sidebar-active-indicator { | |
| 0% { transform: scaleY(0); opacity: 0; } | |
| 100% { transform: scaleY(1); opacity: 1; } | |
| } | |
| /* ================================================================ | |
| 深度动画系统 (v2) — 15项升级 | |
| ================================================================ */ | |
| /* ----- 1. float-in:元素从下方浮动进入(弹性曲线)----- */ | |
| @keyframes float-in { | |
| 0% { opacity: 0; transform: translateY(20px); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| /* ----- 2. glow-border:边框发光脉冲(input/card 聚焦)----- */ | |
| @keyframes glow-border-pulse { | |
| 0%, 100% { box-shadow: 0 0 0 0 rgba(59,130,246,0.3), 0 0 4px rgba(59,130,246,0.15); } | |
| 50% { box-shadow: 0 0 0 4px rgba(59,130,246,0.12), 0 0 12px rgba(59,130,246,0.25); } | |
| } | |
| /* ----- 3. count-up:数字滚动增量的视觉准备(配合 JS)----- */ | |
| @keyframes count-up-slide { | |
| 0% { transform: translateY(1em); opacity: 0; } | |
| 60% { transform: translateY(-0.15em); opacity: 1; } | |
| 80% { transform: translateY(0.05em); } | |
| 100% { transform: translateY(0); opacity: 1; } | |
| } | |
| /* ----- 4. typewriter-enhanced:增强打字机逐字显示 ----- */ | |
| @keyframes typewriter-cursor-blink { | |
| 0%, 100% { opacity: 1; } | |
| 50% { opacity: 0; } | |
| } | |
| /* ----- 5. spotlight:聚光灯扫描(由 JS 设置 --mouse-x/--mouse-y)----- */ | |
| /* 该效果完全通过工具类的 background 属性实现,无需 @keyframes */ | |
| /* ----- 6. morph-bg:多色渐变背景缓慢流动 ----- */ | |
| @keyframes morph-bg-flow { | |
| 0% { background-position: 0% 50%; } | |
| 25% { background-position: 50% 0%; } | |
| 50% { background-position: 100% 50%; } | |
| 75% { background-position: 50% 100%; } | |
| 100% { background-position: 0% 50%; } | |
| } | |
| /* ----- 7. breathe-scale:呼吸缩放(吸引注意力)----- */ | |
| @keyframes breathe-scale { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| } | |
| @keyframes breathe-scale-slow { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.03); } | |
| } | |
| /* ----- 8. stagger-list:列表逐项延迟出现(父/子配合)----- */ | |
| @keyframes stagger-item-in { | |
| 0% { opacity: 0; transform: translateY(12px); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| /* ----- 9. draw-underline:下划线从左到右绘制(::after + scaleX)----- */ | |
| /* 完全通过工具类的 ::after 伪元素 + transition 实现,无需 @keyframes */ | |
| /* ----- 10. flip-card:3D 卡片翻转 ----- */ | |
| @keyframes flip-card-in { | |
| 0% { transform: perspective(800px) rotateY(0deg); } | |
| 100% { transform: perspective(800px) rotateY(180deg); } | |
| } | |
| @keyframes flip-card-out { | |
| 0% { transform: perspective(800px) rotateY(180deg); } | |
| 100% { transform: perspective(800px) rotateY(0deg); } | |
| } | |
| /* ----- 11. wave-ripple:水波纹从点击位置扩散(配合 JS)----- */ | |
| @keyframes wave-ripple-expand { | |
| 0% { width: 0; height: 0; opacity: 0.5; transform: translate(-50%, -50%) scale(0); } | |
| 100% { width: 300px; height: 300px; opacity: 0; transform: translate(-50%, -50%) scale(1); } | |
| } | |
| /* ----- 12. elastic-bounce:弹性弹跳(模拟物理掉落)----- */ | |
| @keyframes elastic-bounce { | |
| 0% { transform: translateY(-60px); opacity: 0; } | |
| 15% { transform: translateY(0); opacity: 1; } | |
| 30% { transform: translateY(-20px); } | |
| 45% { transform: translateY(0); } | |
| 57% { transform: translateY(-7px); } | |
| 68% { transform: translateY(0); } | |
| 76% { transform: translateY(-2px); } | |
| 84% { transform: translateY(0); } | |
| 100% { transform: translateY(0); opacity: 1; } | |
| } | |
| /* ----- 13. dissolve-out:烟雾消散(删除确认/消失提示)----- */ | |
| @keyframes dissolve-out { | |
| 0% { opacity: 1; transform: scale(1); filter: blur(0); } | |
| 50% { opacity: 0.6; transform: scale(1.05); filter: blur(2px); } | |
| 100% { opacity: 0; transform: scale(0.9); filter: blur(8px); } | |
| } | |
| /* ----- 14. orbit-spin:轨道旋转加载动画 ----- */ | |
| @keyframes orbit-spin { | |
| 0% { transform: rotate(0deg) translateX(20px) rotate(0deg); } | |
| 100% { transform: rotate(360deg) translateX(20px) rotate(-360deg); } | |
| } | |
| /* ----- 15. success-burst:成功撒花(多条彩色线条爆开)----- */ | |
| @keyframes success-burst-particle { | |
| 0% { opacity: 1; transform: translate(0, 0) scale(1); } | |
| 100% { opacity: 0; transform: translate(var(--burst-x), var(--burst-y)) scale(0); } | |
| } | |
| @keyframes success-burst-rotate { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| /* ===== #12 Tab 内容切换 ===== */ | |
| @keyframes tab-crossfade-enter { | |
| 0% { opacity: 0; transform: translateY(8px); } | |
| 100% { opacity: 1; transform: translateY(0); } | |
| } | |
| @keyframes tab-crossfade-exit { | |
| 0% { opacity: 1; transform: translateY(0); } | |
| 100% { opacity: 0; transform: translateY(8px); } | |
| } | |
| /* ===== #14 下拉菜单弹性动画 ===== */ | |
| @keyframes dropdown-scale-in { | |
| 0% { opacity: 0; transform: scaleY(0.85); } | |
| 100% { opacity: 1; transform: scaleY(1); } | |
| } | |
| @keyframes dropdown-scale-out { | |
| 0% { opacity: 1; transform: scaleY(1); } | |
| 100% { opacity: 0; transform: scaleY(0.85); } | |
| } | |
| /* ===== 新增组件 keyframes ===== */ | |
| @keyframes dissolve-in { | |
| 0% { opacity: 0; transform: scale(0.85); } | |
| 100% { opacity: 1; transform: scale(1); } | |
| } | |
| @keyframes dissolve-out { | |
| 0% { opacity: 1; transform: scale(1); } | |
| 100% { opacity: 0; transform: scale(0.85); } | |
| } | |
| @keyframes tooltip-fade-in { | |
| 0% { opacity: 0; transform: scale(0.95); } | |
| 100% { opacity: 1; transform: scale(1); } | |
| } | |
| @keyframes modal-scale-out { | |
| 0% { transform: scale(1); opacity: 1; } | |
| 100% { transform: scale(0.9); opacity: 0; } | |
| } | |
| @keyframes backdrop-out { | |
| 0% { opacity: 1; } | |
| 100% { opacity: 0; } | |
| } | |
| /* 面包屑滑入 */ | |
| @keyframes breadcrumb-slide-in { | |
| 0% { opacity: 0; transform: translateX(-8px); } | |
| 100% { opacity: 1; transform: translateX(0); } | |
| } | |
| /* 登录表单 shake */ | |
| @keyframes login-shake { | |
| 0%, 100% { transform: translateX(0); } | |
| 10%, 50%, 90% { transform: translateX(-5px); } | |
| 30%, 70% { transform: translateX(5px); } | |
| } | |
| /* 趋势箭头弹入 */ | |
| @keyframes trend-bounce-in { | |
| 0% { opacity: 0; transform: translateY(8px) scale(0.8); } | |
| 100% { opacity: 1; transform: translateY(0) scale(1); } | |
| } | |
| @keyframes trend-arrow-pop { | |
| 0% { transform: scale(0); opacity: 0; } | |
| 60% { transform: scale(1.3); } | |
| 100% { transform: scale(1); opacity: 1; } | |
| } | |
| /* 验证图标弹入 */ | |
| @keyframes validation-pop-in { | |
| 0% { transform: translateY(-50%) scale(0); } | |
| 60% { transform: translateY(-50%) scale(1.2); } | |
| 100% { transform: translateY(-50%) scale(1); } | |
| } | |
| /* ================================================================ | |
| Print Styles - Medical(增强版) | |
| 打印病历时隐藏 UI 组件,优化 SOAP 内容展示,添加页眉页脚 | |
| ================================================================ */ | |
| @media print { | |
| /* ---- 隐藏不必要元素 ---- */ | |
| .no-print, | |
| nav, | |
| button, | |
| header, | |
| aside, | |
| .skip-to-content, | |
| [class*="Sidebar"], | |
| [class*="Toast"], | |
| [class*="toast"], | |
| .btn-primary, | |
| .btn-secondary, | |
| .btn-ghost, | |
| .btn-danger, | |
| .install-banner, | |
| .scroll-to-top { | |
| display: none ; | |
| } | |
| /* 打印专用元素可见 */ | |
| .print-only { display: block ; } | |
| /* ---- 页面基础样式 ---- */ | |
| body { | |
| font-size: 12px; | |
| line-height: 1.6; | |
| color: #000 ; | |
| background: #fff ; | |
| } | |
| /* 将所有灰色文字转为黑色,确保打印清晰 */ | |
| .text-gray-700, | |
| .text-gray-800, | |
| .text-gray-900, | |
| .text-gray-600, | |
| .text-gray-500, | |
| .text-gray-400 { | |
| color: #000 ; | |
| } | |
| /* ---- 卡片打印样式 ---- */ | |
| .card { | |
| box-shadow: none ; | |
| border: 1px solid #ccc ; | |
| break-inside: avoid; | |
| } | |
| /* ---- 表格样式 ---- */ | |
| table { | |
| border-collapse: collapse; | |
| width: 100%; | |
| } | |
| table th { | |
| background: #e5e7eb ; | |
| color: #000 ; | |
| font-weight: 600; | |
| -webkit-print-color-adjust: exact; | |
| print-color-adjust: exact; | |
| } | |
| table td, table th { | |
| border: 1px solid #d1d5db; | |
| padding: 6px 8px; | |
| text-align: left; | |
| } | |
| /* ---- 标题分页控制:避免标题后立即分页 ---- */ | |
| h1, h2, h3, h4, h5, h6 { | |
| page-break-after: avoid; | |
| color: #000 ; | |
| } | |
| p, ul, ol, dl, blockquote { | |
| orphans: 3; /* 段落底部至少保留 3 行 */ | |
| widows: 3; /* 段落顶部至少保留 3 行 */ | |
| } | |
| /* ---- SOAP 内容:取消 max-height/overflow 限制,完整展示 ---- */ | |
| [class*="soap"], | |
| [class*="SOAP"], | |
| .soap-content, | |
| .record-content, | |
| .medical-record-content { | |
| max-height: none ; | |
| overflow: visible ; | |
| height: auto ; | |
| } | |
| /* ---- 页面设置 ---- */ | |
| @page { | |
| margin: 1.5cm 1.8cm; | |
| size: A4; | |
| /* 打印专用页眉:医院名称 + 日期 */ | |
| @top-center { | |
| content: "VetCopilot - " attr(data-hospital-name); | |
| font-size: 10px; | |
| color: #666; | |
| font-family: "Microsoft YaHei", "Noto Sans SC", sans-serif; | |
| } | |
| @top-right { | |
| content: attr(data-print-date); | |
| font-size: 9px; | |
| color: #999; | |
| } | |
| /* 打印专用页脚:页码 + 生成时间 */ | |
| @bottom-center { | |
| content: "第 " counter(page) " 页,共 " counter(pages) " 页"; | |
| font-size: 9px; | |
| color: #999; | |
| } | |
| @bottom-right { | |
| content: "生成时间: " attr(data-print-time); | |
| font-size: 8px; | |
| color: #aaa; | |
| } | |
| } | |
| /* ---- 病历编号水印(每页底部斜体浅灰)---- */ | |
| body::after { | |
| content: attr(data-record-serial); | |
| position: fixed; | |
| bottom: 0.8cm; | |
| left: 1.8cm; | |
| font-size: 8px; | |
| color: rgba(0, 0, 0, 0.12); | |
| font-style: italic; | |
| font-family: monospace; | |
| pointer-events: none; | |
| z-index: -1; | |
| } | |
| /* ---- 链接显示原始 URL ---- */ | |
| a[href]::after { | |
| content: " (" attr(href) ")"; | |
| font-size: 10px; | |
| color: #666; | |
| word-break: break-all; | |
| } | |
| /* ---- 页面内部分页控制 ---- */ | |
| .page-break-before { page-break-before: always; } | |
| .page-break-after { page-break-after: always; } | |
| .avoid-break { break-inside: avoid; } | |
| /* ---- 背景色和边框保留 ---- */ | |
| * { | |
| -webkit-print-color-adjust: exact ; | |
| print-color-adjust: exact ; | |
| } | |
| } | |
| /* ================================================================ | |
| Mobile (Capacitor) - Safe Area & Touch | |
| ================================================================ */ | |
| /* iOS notch / status bar 安全区域 */ | |
| .safe-top { padding-top: env(safe-area-inset-top, 0px); } | |
| .safe-bottom { padding-bottom: env(safe-area-inset-bottom, 0px); } | |
| .safe-left { padding-left: env(safe-area-inset-left, 0px); } | |
| .safe-right { padding-right: env(safe-area-inset-right, 0px); } | |
| /* 移动端触摸优化 - 消除 300ms 延迟 */ | |
| @media (max-width: 768px) { | |
| /* 按钮和可交互元素使用 touch-action: manipulation 消除双击缩放延迟 */ | |
| button, a, [role="button"], input[type="submit"], input[type="button"] { | |
| cursor: pointer; | |
| -webkit-tap-highlight-color: transparent; | |
| touch-action: manipulation; | |
| } | |
| /* 去掉 iOS 默认样式 */ | |
| input, textarea, select { | |
| -webkit-appearance: none; | |
| border-radius: 0; | |
| } | |
| /* 长按菜单禁用(可编辑区域除外) */ | |
| body { | |
| -webkit-touch-callout: none; | |
| -webkit-user-select: none; | |
| user-select: none; | |
| } | |
| input, textarea, [contenteditable] { | |
| -webkit-user-select: text; | |
| user-select: text; | |
| } | |
| } | |
| /* ================================================================ | |
| 触摸设备专属优化(无 hover 能力 + 粗指针设备) | |
| ================================================================ */ | |
| /* 无 hover 能力的设备(触摸屏):用 active 替代 hover */ | |
| @media (hover: none) { | |
| /* 移动端 hover 会粘滞,改为 active 反馈 */ | |
| .card-hover:hover { | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04) ; | |
| border-color: #e5e7eb ; | |
| } | |
| .card-hover:active { | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04) ; | |
| border-color: #d1d5db ; | |
| } | |
| /* 按钮 hover → active 映射 */ | |
| .btn-primary:hover { background-color: inherit; } | |
| .btn-secondary:hover { background-color: #ffffff; } | |
| .btn-ghost:hover { background-color: transparent; } | |
| .btn-primary:active { filter: brightness(0.9); } | |
| .btn-secondary:active { background-color: #f3f4f6; } | |
| .btn-ghost:active { background-color: #f3f4f6; } | |
| /* 表格行 hover → active */ | |
| table tbody tr:hover { background-color: transparent; } | |
| table tbody tr:active { background-color: #f9fafb; } | |
| /* 链接 hover → active */ | |
| a:hover { opacity: 1; } | |
| a:active { opacity: 0.7; } | |
| } | |
| /* 粗指针设备(手指触摸)额外优化 */ | |
| @media (pointer: coarse) { | |
| /* 可滚动区域启用 iOS 惯性滚动 */ | |
| .scrollable-area, | |
| [class*="overflow-auto"], | |
| [class*="overflow-y-auto"], | |
| [class*="overflow-scroll"] { | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| /* 确保所有可交互元素有足够大的触控面积 */ | |
| button, a, [role="button"], input[type="submit"], input[type="button"], | |
| input[type="checkbox"], input[type="radio"], select { | |
| min-height: 44px; | |
| min-width: 44px; | |
| } | |
| } | |
| /* ================================================================ | |
| 移动端表单输入优化 | |
| ================================================================ */ | |
| /* 防止 iOS 在聚焦输入框时自动缩放(font-size >= 16px) */ | |
| @media (max-width: 768px) { | |
| input[type="text"], | |
| input[type="tel"], | |
| input[type="email"], | |
| input[type="number"], | |
| input[type="date"], | |
| input[type="password"], | |
| textarea, | |
| select, | |
| .input-field { | |
| font-size: 16px ; | |
| } | |
| } | |
| /* ================================================================ | |
| 点击高亮控制工具类 | |
| ================================================================ */ | |
| /* 移除点击高亮(用于卡片、容器等非交互区域或自定义样式的交互元素) */ | |
| .tap-highlight-none { | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| /* 自定义点击高亮颜色(用于需要反馈的列表项、菜单项) */ | |
| .tap-highlight-subtle { | |
| -webkit-tap-highlight-color: rgba(0, 0, 0, 0.06); | |
| } | |
| .tap-highlight-primary { | |
| -webkit-tap-highlight-color: rgba(59, 130, 246, 0.15); | |
| } | |
| /* Electron 桌面端专用 */ | |
| @media (display-mode: standalone) or (env(electron)) { | |
| /* 桌面端更大的字体和间距可通过此处覆盖 */ | |
| } | |