Files
20260512-skg-tk/web/app/globals.css

412 lines
13 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@import "tailwindcss";
@import "tw-animate-css";
@import "@xyflow/react/dist/style.css";
@custom-variant dark (&:is(.dark *));
/* ============================================================
双主题 · 玻璃拟物Rivet/Flowise 风)
============================================================ */
:root {
color-scheme: light;
/* ---- Light · 暖白底 ---- */
--bg-canvas-1: #f6f4ed;
--bg-canvas-2: #ece6d8;
--bg-grid: rgba(0, 0, 0, 0.06);
--bg-aurora-1: rgba(120, 100, 220, 0.15);
--bg-aurora-2: rgba(220, 120, 180, 0.12);
--node-bg: rgba(255, 255, 255, 0.7);
--node-bg-hover: rgba(255, 255, 255, 0.82);
--node-border: rgba(0, 0, 0, 0.08);
--node-border-hover: rgba(0, 0, 0, 0.18);
--node-ring: rgba(255, 255, 255, 0.9);
--node-shadow:
0 1px 1px rgba(0, 0, 0, 0.04),
0 8px 24px -8px rgba(0, 0, 0, 0.12),
0 30px 60px -30px rgba(40, 30, 80, 0.18);
--node-shadow-hover:
0 1px 1px rgba(0, 0, 0, 0.06),
0 12px 32px -10px rgba(40, 30, 80, 0.22),
0 40px 80px -30px rgba(40, 30, 80, 0.3);
--text-strong: oklch(0.18 0.02 280);
--text-soft: oklch(0.45 0.02 280);
--text-faint: oklch(0.6 0.02 280);
--edge-stroke: rgba(60, 50, 120, 0.35);
--edge-glow: rgba(120, 100, 220, 0.4);
--divider: rgba(0, 0, 0, 0.08);
--background: oklch(0.97 0.005 80);
--foreground: oklch(0.18 0.02 280);
--border: var(--node-border);
--ring: rgba(120, 100, 220, 0.5);
--radius: 1rem;
/* 节点头渐变4 类型)*/
--grad-input: linear-gradient(135deg, #6366f1, #a855f7);
--grad-process: linear-gradient(135deg, #f59e0b, #ef4444);
--grad-ai: linear-gradient(135deg, #d946ef, #ec4899);
--grad-output: linear-gradient(135deg, #10b981, #06b6d4);
/* 状态色 */
--status-pending: oklch(0.7 0.02 280);
--status-running: oklch(0.7 0.18 260);
--status-done: oklch(0.7 0.18 160);
--status-failed: oklch(0.65 0.22 25);
}
.dark {
color-scheme: dark;
/* ---- Dark · 深蓝紫 ---- */
--bg-canvas-1: #0a0d1c;
--bg-canvas-2: #14172e;
--bg-grid: rgba(255, 255, 255, 0.04);
--bg-aurora-1: rgba(120, 100, 220, 0.22);
--bg-aurora-2: rgba(220, 80, 180, 0.16);
--node-bg: rgba(22, 26, 48, 0.62);
--node-bg-hover: rgba(30, 35, 60, 0.76);
--node-border: rgba(255, 255, 255, 0.08);
--node-border-hover: rgba(255, 255, 255, 0.18);
--node-ring: rgba(255, 255, 255, 0.05);
--node-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.06),
0 1px 2px rgba(0, 0, 0, 0.4),
0 16px 40px -12px rgba(0, 0, 0, 0.6),
0 30px 80px -20px rgba(80, 50, 200, 0.3);
--node-shadow-hover:
inset 0 1px 0 rgba(255, 255, 255, 0.1),
0 1px 2px rgba(0, 0, 0, 0.5),
0 20px 50px -10px rgba(0, 0, 0, 0.7),
0 40px 100px -20px rgba(120, 80, 240, 0.4);
--text-strong: oklch(0.96 0.005 280);
--text-soft: oklch(0.7 0.015 280);
--text-faint: oklch(0.5 0.015 280);
--edge-stroke: rgba(180, 170, 240, 0.45);
--edge-glow: rgba(120, 100, 220, 0.7);
--divider: rgba(255, 255, 255, 0.08);
--background: oklch(0.1 0.02 280);
--foreground: oklch(0.96 0.005 280);
--border: var(--node-border);
--ring: rgba(180, 160, 255, 0.5);
}
@theme inline {
--font-sans: "Geist", "Geist Fallback";
--font-serif: "Playfair Display", Georgia, serif;
--font-mono: "Geist Mono", "Geist Mono Fallback";
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-border: var(--border);
--color-ring: var(--ring);
--radius-lg: var(--radius);
--radius-md: calc(var(--radius) - 0.25rem);
--radius-sm: calc(var(--radius) - 0.5rem);
--radius-xl: calc(var(--radius) + 0.25rem);
}
@layer base {
* {
border-color: var(--border);
}
html, body {
background: var(--background);
color: var(--foreground);
min-height: 100vh;
}
}
/* ============================================================
画布背景:渐变 + 极光 + 颗粒
============================================================ */
.canvas-bg {
position: fixed;
inset: 0;
z-index: 0;
background:
radial-gradient(ellipse 80% 60% at 20% 10%, var(--bg-aurora-1), transparent 60%),
radial-gradient(ellipse 70% 50% at 80% 90%, var(--bg-aurora-2), transparent 60%),
linear-gradient(180deg, var(--bg-canvas-1), var(--bg-canvas-2));
}
/* ============================================================
节点:玻璃拟物 + 头部 4 色渐变
============================================================ */
.glass-node {
position: relative;
background: var(--node-bg);
backdrop-filter: blur(20px) saturate(140%);
-webkit-backdrop-filter: blur(20px) saturate(140%);
border: 1px solid var(--node-border);
border-radius: var(--radius);
box-shadow: var(--node-shadow);
transition: transform 0.25s cubic-bezier(0.32, 0.72, 0, 1),
box-shadow 0.25s cubic-bezier(0.32, 0.72, 0, 1),
border-color 0.2s,
background 0.2s;
color: var(--text-strong);
overflow: hidden;
}
.glass-node:hover {
background: var(--node-bg-hover);
border-color: var(--node-border-hover);
box-shadow: var(--node-shadow-hover);
transform: translateY(-1px);
}
.glass-node--selected {
border-color: var(--ring);
box-shadow: var(--node-shadow-hover), 0 0 0 3px var(--ring);
}
.glass-node--running::after {
content: "";
position: absolute;
inset: -1px;
border-radius: inherit;
pointer-events: none;
background: conic-gradient(from 0deg, transparent 70%, var(--edge-glow), transparent);
animation: spin 3s linear infinite;
mask:
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
mask-composite: exclude;
-webkit-mask:
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
padding: 1.5px;
opacity: 0.8;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.glass-node__header {
display: flex;
align-items: center;
gap: 0.625rem;
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--divider);
color: white;
font-weight: 600;
letter-spacing: 0.01em;
position: relative;
}
.glass-node__header::before {
content: "";
position: absolute;
inset: 0;
opacity: 0.92;
}
.glass-node__header > * { position: relative; z-index: 1; }
.glass-node[data-type="input"] .glass-node__header::before { background: var(--grad-input); }
.glass-node[data-type="process"] .glass-node__header::before { background: var(--grad-process); }
.glass-node[data-type="ai"] .glass-node__header::before { background: var(--grad-ai); }
.glass-node[data-type="output"] .glass-node__header::before { background: var(--grad-output); }
.glass-node__body { padding: 0.85rem 1rem 1rem; }
/* ============================================================
Kanban 卡片Storyflow/参考图风格)
============================================================ */
.kanban-card {
position: relative;
border-radius: 14px;
padding: 12px 14px;
border: 1px solid rgba(255, 255, 255, 0.08);
transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
}
.kanban-card:hover {
transform: translateY(-1px);
border-color: rgba(255, 255, 255, 0.16);
box-shadow: 0 8px 24px -10px rgba(0, 0, 0, 0.5);
}
/* dark 模式下:低明度彩色 */
.dark .kanban-violet { background: linear-gradient(160deg, rgba(167, 139, 250, 0.18), rgba(139, 92, 246, 0.08)); }
.dark .kanban-pink { background: linear-gradient(160deg, rgba(244, 114, 182, 0.18), rgba(236, 72, 153, 0.08)); }
.dark .kanban-orange { background: linear-gradient(160deg, rgba(251, 146, 60, 0.18), rgba(249, 115, 22, 0.08)); }
.dark .kanban-blue { background: linear-gradient(160deg, rgba(96, 165, 250, 0.18), rgba(59, 130, 246, 0.08)); }
.dark .kanban-green { background: linear-gradient(160deg, rgba(74, 222, 128, 0.18), rgba(34, 197, 94, 0.08)); }
.dark .kanban-cyan { background: linear-gradient(160deg, rgba(34, 211, 238, 0.18), rgba(6, 182, 212, 0.08)); }
.dark .kanban-rose { background: linear-gradient(160deg, rgba(251, 113, 133, 0.18), rgba(244, 63, 94, 0.08)); }
.dark .kanban-amber { background: linear-gradient(160deg, rgba(252, 211, 77, 0.18), rgba(245, 158, 11, 0.08)); }
/* light 模式pastel 暖底 */
:root:not(.dark) .kanban-violet { background: #ede9fe; border-color: rgba(139, 92, 246, 0.18); }
:root:not(.dark) .kanban-pink { background: #fce7f3; border-color: rgba(236, 72, 153, 0.18); }
:root:not(.dark) .kanban-orange { background: #ffedd5; border-color: rgba(249, 115, 22, 0.18); }
:root:not(.dark) .kanban-blue { background: #dbeafe; border-color: rgba(59, 130, 246, 0.18); }
:root:not(.dark) .kanban-green { background: #dcfce7; border-color: rgba(34, 197, 94, 0.18); }
:root:not(.dark) .kanban-cyan { background: #cffafe; border-color: rgba(6, 182, 212, 0.18); }
:root:not(.dark) .kanban-rose { background: #ffe4e6; border-color: rgba(244, 63, 94, 0.18); }
:root:not(.dark) .kanban-amber { background: #fef3c7; border-color: rgba(245, 158, 11, 0.18); }
.kanban-tag {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: 999px;
font-size: 10.5px;
font-weight: 500;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.1);
color: var(--text-soft);
}
:root:not(.dark) .kanban-tag {
background: rgba(255, 255, 255, 0.7);
border-color: rgba(0, 0, 0, 0.06);
color: var(--text-soft);
}
.kanban-meta {
display: flex;
align-items: center;
gap: 8px;
margin-top: 10px;
padding-top: 8px;
border-top: 1px solid rgba(255, 255, 255, 0.06);
font-size: 10.5px;
color: var(--text-faint);
}
:root:not(.dark) .kanban-meta {
border-top-color: rgba(0, 0, 0, 0.06);
}
.glass-node__row {
display: flex; align-items: center; gap: 0.5rem;
font-size: 12px; color: var(--text-soft);
}
.glass-node__kbd {
font-family: var(--font-mono);
font-size: 10.5px;
color: var(--text-faint);
}
/* 状态点 */
.status-dot {
width: 8px; height: 8px; border-radius: 50%;
background: var(--status-pending);
box-shadow: 0 0 0 0 currentColor;
}
.status-dot--running {
background: var(--status-running);
animation: pulse-dot 1.4s ease-in-out infinite;
}
.status-dot--done { background: var(--status-done); }
.status-dot--failed { background: var(--status-failed); }
@keyframes pulse-dot {
0%,100% { box-shadow: 0 0 0 0 var(--status-running); opacity: 1; }
50% { box-shadow: 0 0 0 6px transparent; opacity: 0.7; }
}
@keyframes drawer-in {
from { transform: translateX(-24px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
/* 覆盖 ReactFlow 内置 reserved typeinput/output/default/group的默认白底
提高 specificity用 .react-flow 前缀确保盖过内置 CSS 变量 */
.react-flow .react-flow__node-input,
.react-flow .react-flow__node-output,
.react-flow .react-flow__node-default,
.react-flow .react-flow__node-group {
background: transparent !important;
border: none !important;
padding: 0 !important;
border-radius: 0 !important;
font-size: inherit !important;
color: inherit !important;
text-align: left !important;
box-shadow: none !important;
}
/* 节点 handleReactFlow */
.react-flow__handle {
width: 12px !important;
height: 12px !important;
background: var(--node-bg) !important;
border: 2px solid var(--edge-stroke) !important;
box-shadow: 0 0 0 3px var(--node-ring) !important;
}
.react-flow__handle:hover {
background: var(--edge-glow) !important;
transform: scale(1.2);
}
.react-flow__edge .react-flow__edge-path {
stroke: var(--edge-stroke);
stroke-width: 1.6;
}
.react-flow__edge.animated .react-flow__edge-path {
stroke: var(--edge-glow);
stroke-width: 2;
filter: drop-shadow(0 0 6px var(--edge-glow));
}
.react-flow__controls,
.react-flow__panel {
background: var(--node-bg) !important;
border: 1px solid var(--node-border) !important;
border-radius: 12px !important;
backdrop-filter: blur(16px);
box-shadow: var(--node-shadow) !important;
}
.react-flow__controls button {
background: transparent !important;
border-bottom: 1px solid var(--divider) !important;
color: var(--text-strong) !important;
}
.react-flow__controls button:hover {
background: var(--node-bg-hover) !important;
}
.react-flow__minimap {
background: var(--node-bg) !important;
border-radius: 12px !important;
border: 1px solid var(--node-border) !important;
box-shadow: var(--node-shadow) !important;
}
.react-flow__background pattern circle {
fill: var(--bg-grid) !important;
}
.react-flow__attribution { display: none !important; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: var(--divider); border-radius: 4px; }
::-webkit-scrollbar-track { background: transparent; }
/* 节点内缩略图浮条(横滚)专用:加粗 + 紫色高亮 + 大可拖区,避免在画布 zoom 下拖不到 */
.react-flow__node .overflow-x-auto {
scrollbar-color: rgba(167, 139, 250, 0.65) rgba(255, 255, 255, 0.08);
scrollbar-width: auto;
}
.react-flow__node .overflow-x-auto::-webkit-scrollbar {
height: 14px;
}
.react-flow__node .overflow-x-auto::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.06);
border-radius: 8px;
margin: 0 4px;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.react-flow__node .overflow-x-auto::-webkit-scrollbar-thumb {
background: rgba(167, 139, 250, 0.55);
border-radius: 8px;
border: 2px solid rgba(255, 255, 255, 0.18);
min-width: 48px;
background-clip: padding-box;
}
.react-flow__node .overflow-x-auto::-webkit-scrollbar-thumb:hover {
background: rgba(167, 139, 250, 0.85);
border-color: rgba(255, 255, 255, 0.3);
}
.react-flow__node .overflow-x-auto::-webkit-scrollbar-thumb:active {
background: rgba(217, 70, 239, 0.95);
}