Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
225fcb49ea | ||
|
|
70a860ce2a | ||
|
|
e42212a16f |
@@ -52,15 +52,16 @@
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
/* §四.5 Toast:右下角堆叠,220ms 上移入场;成功绿点 / 失败红点。 */
|
||||
.toast-host {
|
||||
position: fixed;
|
||||
top: 72px;
|
||||
right: 20px;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
max-width: min(360px, calc(100vw - 32px));
|
||||
max-width: min(400px, calc(100vw - 32px));
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast {
|
||||
@@ -69,23 +70,10 @@
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
padding: 12px 14px;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-surface);
|
||||
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
|
||||
animation: toast-in 0.22s ease-out;
|
||||
}
|
||||
.toast.success {
|
||||
border-color: rgba(34, 197, 94, 0.45);
|
||||
box-shadow:
|
||||
0 12px 32px rgba(0, 0, 0, 0.45),
|
||||
0 0 0 1px rgba(34, 197, 94, 0.12);
|
||||
}
|
||||
.toast.error {
|
||||
border-color: rgba(239, 68, 68, 0.5);
|
||||
}
|
||||
.toast.info {
|
||||
border-color: rgba(59, 130, 246, 0.45);
|
||||
border-radius: var(--r-lg);
|
||||
background: var(--float-bg);
|
||||
box-shadow: var(--shadow-float);
|
||||
animation: toast-in var(--d-enter) var(--ease-out);
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
@@ -101,17 +89,17 @@
|
||||
background: currentColor;
|
||||
}
|
||||
.toast.success .badge {
|
||||
color: var(--success);
|
||||
color: var(--ok);
|
||||
}
|
||||
.toast.error .badge {
|
||||
color: var(--error);
|
||||
color: var(--err);
|
||||
}
|
||||
.toast.info .badge {
|
||||
color: var(--info);
|
||||
color: var(--text-2);
|
||||
}
|
||||
.msg {
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
font-size: var(--fs-body);
|
||||
line-height: 1.4;
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
@@ -127,10 +115,12 @@
|
||||
padding: 0 2px;
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
border-radius: 4px;
|
||||
border-radius: var(--r-sm);
|
||||
}
|
||||
.dismiss:hover {
|
||||
color: var(--text-primary);
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.dismiss:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
.dismiss:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
@@ -139,7 +129,7 @@
|
||||
@keyframes toast-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px);
|
||||
transform: translateY(8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
@@ -151,9 +141,11 @@
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
:global(:root[data-reduce='1']) .toast {
|
||||
animation: none;
|
||||
}
|
||||
@media (max-width: 760px) {
|
||||
.toast-host {
|
||||
top: auto;
|
||||
bottom: 20px;
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
function segClass(key: string): string {
|
||||
const state = stats.stage_status?.[key];
|
||||
if (state === 'confirmed') return 'seg-confirmed';
|
||||
if (state === 'running' || state === 'awaiting_confirm') return 'seg-draft';
|
||||
if (state === 'running') return 'seg-running';
|
||||
if (state === 'awaiting_confirm') return 'seg-draft';
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@
|
||||
return { cls: 'st-progress', label: `${stageName} · ${t('workbench.state.running')}` };
|
||||
}
|
||||
if (state === 'awaiting_confirm') {
|
||||
return { cls: 'st-progress', label: `${stageName} · ${t('workbench.state.draft')}` };
|
||||
return { cls: 'st-pending', label: `${stageName} · ${t('workbench.state.draft')}` };
|
||||
}
|
||||
if (stats.stage_confirmed > 0) {
|
||||
return { cls: 'st-progress', label: `${stageName} · ${t('home.statusProgress')}` };
|
||||
@@ -329,7 +330,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(22, 19, 10, 0.82);
|
||||
color: color-mix(in srgb, var(--accent-ink) 82%, transparent);
|
||||
opacity: 0.9;
|
||||
}
|
||||
.status-tag {
|
||||
@@ -340,7 +341,7 @@
|
||||
border-radius: 999px;
|
||||
font-size: 10.5px;
|
||||
font-weight: 600;
|
||||
background: rgba(13, 14, 17, 0.78);
|
||||
background: var(--media-scrim);
|
||||
border: 1px solid var(--border-strong);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
@@ -350,7 +351,10 @@
|
||||
color: var(--text-2);
|
||||
}
|
||||
.st-progress {
|
||||
color: var(--accent);
|
||||
color: var(--run);
|
||||
}
|
||||
.st-pending {
|
||||
color: var(--warn);
|
||||
}
|
||||
.st-done {
|
||||
color: var(--success);
|
||||
@@ -409,8 +413,11 @@
|
||||
border-radius: 2px;
|
||||
background: var(--surface-3);
|
||||
}
|
||||
.seg-running {
|
||||
background: var(--run);
|
||||
}
|
||||
.seg-draft {
|
||||
background: var(--accent);
|
||||
background: var(--warn);
|
||||
}
|
||||
.seg-confirmed {
|
||||
background: var(--success);
|
||||
@@ -425,8 +432,8 @@
|
||||
margin-left: auto;
|
||||
padding: 1px 8px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
background: var(--run-soft);
|
||||
color: var(--run);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
@@ -462,7 +469,7 @@
|
||||
height: 28px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 7px;
|
||||
background: rgba(13, 14, 17, 0.6);
|
||||
background: var(--media-scrim);
|
||||
color: var(--text-2);
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
|
||||
@@ -341,14 +341,14 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 进行数徽章 (spec §3): accent-dim capsule with amber count */
|
||||
/* 进行数徽章:进行中计数用信号青 */
|
||||
.nav-badge {
|
||||
margin-left: auto;
|
||||
min-width: 20px;
|
||||
padding: 1px 7px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
background: var(--run-soft);
|
||||
color: var(--run);
|
||||
font-size: 10.5px;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
@@ -384,7 +384,7 @@
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* §5 连接状态点: green = probe passed, amber breathing = testing,
|
||||
/* 连接状态点: cyan = online, cyan breathing = testing,
|
||||
red = failed, gray = no connection configured. */
|
||||
.dot {
|
||||
width: 7px;
|
||||
@@ -396,13 +396,13 @@
|
||||
margin-top: 5px;
|
||||
}
|
||||
.dot.ok {
|
||||
background: var(--success);
|
||||
background: var(--run);
|
||||
}
|
||||
.dot.fail {
|
||||
background: var(--error);
|
||||
}
|
||||
.dot.testing {
|
||||
background: var(--accent);
|
||||
background: var(--run);
|
||||
animation: shell-breathe 2s cubic-bezier(0.16, 1, 0.3, 1) infinite;
|
||||
}
|
||||
@keyframes shell-breathe {
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
color: var(--accent);
|
||||
}
|
||||
.slot-empty.invalid {
|
||||
border-color: rgba(229, 72, 77, 0.65);
|
||||
border-color: var(--err-line);
|
||||
}
|
||||
.slot-empty:disabled {
|
||||
cursor: default;
|
||||
|
||||
@@ -1897,7 +1897,7 @@
|
||||
color: var(--text-3);
|
||||
}
|
||||
.h3-hint p.warn {
|
||||
color: var(--accent);
|
||||
color: var(--warn);
|
||||
}
|
||||
.studio-page {
|
||||
display: grid;
|
||||
@@ -1990,10 +1990,10 @@
|
||||
}
|
||||
.f-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.f-input.invalid {
|
||||
border-color: rgba(229, 72, 77, 0.65);
|
||||
border-color: var(--err-line);
|
||||
}
|
||||
.f-error {
|
||||
display: block;
|
||||
@@ -2139,13 +2139,10 @@
|
||||
font-weight: 600;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.tag.info {
|
||||
color: var(--info);
|
||||
background: var(--info-dim);
|
||||
}
|
||||
.tag.info,
|
||||
.tag.cloud {
|
||||
color: var(--cloud);
|
||||
background: var(--cloud-dim);
|
||||
color: var(--text-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
.task-body {
|
||||
margin-top: 12px;
|
||||
@@ -2168,9 +2165,9 @@
|
||||
.progress .fill {
|
||||
height: 100%;
|
||||
border-radius: 999px;
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 10px var(--accent-glow);
|
||||
transition: width 300ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
background: var(--run-grad);
|
||||
box-shadow: 0 0 8px var(--run-soft);
|
||||
transition: width var(--d-progress) linear;
|
||||
}
|
||||
.task-meta {
|
||||
font-size: 11px;
|
||||
@@ -2238,7 +2235,7 @@
|
||||
display: block;
|
||||
}
|
||||
.thumb:hover {
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.thumb.selected {
|
||||
border: 2px solid var(--accent);
|
||||
@@ -2571,7 +2568,7 @@
|
||||
color: var(--success);
|
||||
}
|
||||
.st.run {
|
||||
color: var(--accent);
|
||||
color: var(--run);
|
||||
}
|
||||
.st.queue {
|
||||
color: var(--text-3);
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
import Spinner from './Spinner.svelte';
|
||||
|
||||
interface Props {
|
||||
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
|
||||
size?: 'sm' | 'md';
|
||||
/** `danger` = outlined (list rows); `danger-solid` = confirm dialogs only. */
|
||||
variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'danger-solid';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
/** Stretch to the container width (e.g. a panel's main action). */
|
||||
block?: boolean;
|
||||
disabled?: boolean;
|
||||
@@ -32,6 +33,7 @@
|
||||
{type}
|
||||
class="a-btn btn {variant}"
|
||||
class:sm={size === 'sm'}
|
||||
class:lg={size === 'lg'}
|
||||
class:block
|
||||
class:loading
|
||||
disabled={disabled || loading}
|
||||
@@ -49,7 +51,7 @@
|
||||
</button>
|
||||
|
||||
<style>
|
||||
/* Look comes from the shared `.a-btn` rules in app.css (§5). */
|
||||
/* Look comes from the shared `.a-btn` rules in app.css (§四.1). */
|
||||
.btn {
|
||||
position: relative;
|
||||
}
|
||||
@@ -72,10 +74,14 @@
|
||||
justify-content: center;
|
||||
}
|
||||
.btn.primary .btn-spinner {
|
||||
--spinner-track: rgba(22, 19, 10, 0.3);
|
||||
--spinner-arc: var(--accent-contrast);
|
||||
--spinner-track: color-mix(in srgb, var(--accent-ink) 30%, transparent);
|
||||
--spinner-arc: var(--accent-ink);
|
||||
}
|
||||
.btn.danger .btn-spinner {
|
||||
--spinner-arc: var(--error);
|
||||
--spinner-arc: var(--err);
|
||||
}
|
||||
.btn.danger-solid .btn-spinner {
|
||||
--spinner-track: color-mix(in srgb, var(--on-media) 30%, transparent);
|
||||
--spinner-arc: var(--on-media);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -46,16 +46,18 @@
|
||||
.card {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
border-radius: var(--r-lg);
|
||||
}
|
||||
.card.hoverable {
|
||||
transition:
|
||||
border-color 150ms ease,
|
||||
transform 150ms ease;
|
||||
border-color var(--d-state) ease,
|
||||
transform var(--d-state) var(--ease-out);
|
||||
}
|
||||
.card.hoverable:hover {
|
||||
border-color: #3f3f46;
|
||||
transform: translateY(-1px);
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.card.hoverable:hover {
|
||||
border-color: var(--line-2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
{#snippet footer()}
|
||||
<Button variant="ghost" onclick={() => (open = false)}>{cancelLabel}</Button
|
||||
>
|
||||
<Button variant={danger ? 'danger' : 'primary'} onclick={handleConfirm}
|
||||
<Button variant={danger ? 'danger-solid' : 'primary'} onclick={handleConfirm}
|
||||
>{confirmLabel}</Button
|
||||
>
|
||||
{/snippet}
|
||||
|
||||
@@ -144,22 +144,19 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
background: rgba(5, 5, 8, 0.6);
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
animation: modal-fade 150ms ease-out;
|
||||
background: var(--overlay);
|
||||
animation: modal-fade var(--d-state) ease-out;
|
||||
}
|
||||
.modal-panel {
|
||||
width: min(520px, 100%);
|
||||
max-height: calc(100vh - 96px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
|
||||
background: var(--float-bg);
|
||||
border-radius: var(--r-lg);
|
||||
box-shadow: var(--shadow-float);
|
||||
outline: none;
|
||||
animation: modal-rise 180ms ease-out;
|
||||
animation: modal-rise var(--d-pop) var(--ease-out);
|
||||
}
|
||||
.modal-panel.size-lg {
|
||||
width: min(920px, 100%);
|
||||
@@ -177,7 +174,7 @@
|
||||
.modal-title {
|
||||
margin: 0;
|
||||
font-family: var(--font-display);
|
||||
font-size: 16px;
|
||||
font-size: var(--fs-title);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
@@ -194,12 +191,14 @@
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 150ms ease,
|
||||
color 150ms ease;
|
||||
background-color var(--d-state) ease,
|
||||
color var(--d-state) ease;
|
||||
}
|
||||
.modal-close:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: var(--text-primary);
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.modal-close:hover {
|
||||
background: var(--bg-4);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
.modal-close:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
indeterminate?: boolean;
|
||||
label?: string;
|
||||
size?: 'sm' | 'md';
|
||||
/** §5 进度条: running = amber, done = green, failed = red (static). */
|
||||
tone?: 'accent' | 'success' | 'error';
|
||||
/** 进度条: running = 信号青, done = green, failed = red (static). */
|
||||
tone?: 'run' | 'success' | 'error';
|
||||
/** Track only — no label / percentage row. */
|
||||
bare?: boolean;
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
indeterminate = false,
|
||||
label,
|
||||
size = 'md',
|
||||
tone = 'accent',
|
||||
tone = 'run',
|
||||
bare = false,
|
||||
}: Props = $props();
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
{#if indeterminate}
|
||||
<div class="fill indeterminate"></div>
|
||||
{:else}
|
||||
<div class="fill" style:width={pct + '%'}></div>
|
||||
<div class="fill" style:transform="scaleX({pct / 100})"></div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,8 +75,8 @@
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: var(--surface-3);
|
||||
border-radius: 999px;
|
||||
background: var(--bg-4);
|
||||
border-radius: var(--r-pill);
|
||||
}
|
||||
.progress-sm .track {
|
||||
height: 4px;
|
||||
@@ -86,15 +86,18 @@
|
||||
}
|
||||
.fill {
|
||||
height: 100%;
|
||||
background: var(--accent);
|
||||
border-radius: 999px;
|
||||
transition: width 300ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
background: var(--run-grad);
|
||||
box-shadow: 0 0 8px var(--run-soft);
|
||||
transform-origin: left;
|
||||
transition: transform var(--d-progress) linear;
|
||||
}
|
||||
.tone-success .fill {
|
||||
background: var(--success);
|
||||
background: var(--ok);
|
||||
box-shadow: none;
|
||||
}
|
||||
.tone-error .fill {
|
||||
background: var(--error);
|
||||
background: var(--err);
|
||||
box-shadow: none;
|
||||
}
|
||||
.fill.indeterminate {
|
||||
position: absolute;
|
||||
@@ -104,10 +107,11 @@
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
var(--accent) 40%,
|
||||
var(--accent) 60%,
|
||||
var(--run) 40%,
|
||||
var(--run) 60%,
|
||||
transparent
|
||||
);
|
||||
box-shadow: none;
|
||||
transition: none;
|
||||
animation: progress-slide 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -19,36 +19,26 @@
|
||||
></div>
|
||||
|
||||
<style>
|
||||
/* §四.9 骨架屏:--bg-3 圆角块,1.4s 呼吸透明度;减少动态时静态。 */
|
||||
.skeleton {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: var(--bg-elevated);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--bg-3);
|
||||
border-radius: var(--r-sm);
|
||||
animation: skeleton-breath 1.4s ease-in-out infinite;
|
||||
}
|
||||
.skeleton.circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.skeleton::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.06),
|
||||
transparent
|
||||
);
|
||||
transform: translateX(-100%);
|
||||
animation: skeleton-shimmer 1.6s ease-in-out infinite;
|
||||
}
|
||||
@keyframes skeleton-shimmer {
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
@keyframes skeleton-breath {
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.skeleton::after {
|
||||
display: none;
|
||||
.skeleton {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
:global(:root[data-reduce='1']) .skeleton {
|
||||
animation: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,27 +6,27 @@
|
||||
|
||||
let { status, label }: Props = $props();
|
||||
|
||||
type Tone = 'success' | 'info' | 'muted' | 'error' | 'warning' | 'accent';
|
||||
type Tone = 'ok' | 'run' | 'muted' | 'err' | 'warn';
|
||||
|
||||
const toneByStatus: Record<string, Tone> = {
|
||||
ready: 'success',
|
||||
done: 'success',
|
||||
completed: 'success',
|
||||
running: 'info',
|
||||
generating: 'info',
|
||||
queued: 'info',
|
||||
ready: 'ok',
|
||||
done: 'ok',
|
||||
completed: 'ok',
|
||||
running: 'run',
|
||||
generating: 'run',
|
||||
in_progress: 'run',
|
||||
queued: 'muted',
|
||||
pending: 'muted',
|
||||
idle: 'muted',
|
||||
draft: 'muted',
|
||||
failed: 'error',
|
||||
error: 'error',
|
||||
paused: 'warning',
|
||||
in_progress: 'accent',
|
||||
failed: 'err',
|
||||
error: 'err',
|
||||
paused: 'warn',
|
||||
};
|
||||
|
||||
const key = $derived(status.trim().toLowerCase());
|
||||
const tone: Tone = $derived(toneByStatus[key] ?? 'muted');
|
||||
const pulsing = $derived(key === 'running');
|
||||
const pulsing = $derived(tone === 'run');
|
||||
</script>
|
||||
|
||||
<span class="chip chip-{tone}">
|
||||
@@ -35,59 +35,48 @@
|
||||
</span>
|
||||
|
||||
<style>
|
||||
/* §四.2 状态标签:20px 高、--r-sm、12px;语义色文字 + 13% 软底。 */
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 3px 9px;
|
||||
border: 1px solid;
|
||||
border-radius: 999px;
|
||||
font-size: 10px;
|
||||
gap: var(--sp-2);
|
||||
height: 20px;
|
||||
padding: 0 var(--sp-2);
|
||||
border-radius: var(--r-sm);
|
||||
font-size: var(--fs-aux);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.chip-success {
|
||||
color: var(--success);
|
||||
background: color-mix(in srgb, var(--success) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--success) 35%, transparent);
|
||||
.chip-ok {
|
||||
color: var(--ok);
|
||||
background: var(--ok-soft);
|
||||
}
|
||||
.chip-info {
|
||||
color: var(--info);
|
||||
background: color-mix(in srgb, var(--info) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--info) 35%, transparent);
|
||||
.chip-run {
|
||||
color: var(--run);
|
||||
background: var(--run-soft);
|
||||
}
|
||||
.chip-error {
|
||||
color: var(--error);
|
||||
background: color-mix(in srgb, var(--error) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--error) 35%, transparent);
|
||||
.chip-err {
|
||||
color: var(--err);
|
||||
background: var(--err-soft);
|
||||
}
|
||||
.chip-warning {
|
||||
color: var(--warning);
|
||||
background: color-mix(in srgb, var(--warning) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--warning) 35%, transparent);
|
||||
}
|
||||
.chip-accent {
|
||||
color: var(--accent);
|
||||
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
||||
border-color: color-mix(in srgb, var(--accent) 35%, transparent);
|
||||
.chip-warn {
|
||||
color: var(--warn);
|
||||
background: var(--warn-soft);
|
||||
}
|
||||
.chip-muted {
|
||||
color: var(--text-secondary);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border-color: var(--border);
|
||||
color: var(--text-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
.dot.pulsing {
|
||||
animation: chip-pulse 1.2s ease-in-out infinite;
|
||||
animation: chip-pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes chip-pulse {
|
||||
0%,
|
||||
@@ -103,4 +92,7 @@
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
:global(:root[data-reduce='1']) .dot.pulsing {
|
||||
animation: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
let { checked, label, disabled = false, onchange }: Props = $props();
|
||||
</script>
|
||||
|
||||
<!-- §5 开关: 34×19 capsule; on = amber track + dark knob, off = --surface-3. -->
|
||||
<!-- §3.10 开关: 34×19 capsule; on = --accent-lo track + ink knob, off = --bg-4. -->
|
||||
<button
|
||||
type="button"
|
||||
class="switch"
|
||||
@@ -28,38 +28,38 @@
|
||||
flex-shrink: 0;
|
||||
width: 34px;
|
||||
height: 19px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border-strong);
|
||||
background: var(--surface-3);
|
||||
border-radius: var(--r-pill);
|
||||
border: 1px solid var(--line-2);
|
||||
background: var(--bg-4);
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
transition:
|
||||
background-color 150ms,
|
||||
border-color 150ms;
|
||||
background-color var(--d-state) ease,
|
||||
border-color var(--d-state) ease;
|
||||
}
|
||||
.switch:disabled {
|
||||
opacity: 0.4;
|
||||
opacity: 0.45;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.knob {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 999px;
|
||||
border-radius: var(--r-pill);
|
||||
background: var(--text-3);
|
||||
transition:
|
||||
transform 150ms cubic-bezier(0.16, 1, 0.3, 1),
|
||||
background-color 150ms;
|
||||
transform var(--d-state) var(--ease-out),
|
||||
background-color var(--d-state) ease;
|
||||
}
|
||||
.switch.on {
|
||||
background: var(--accent);
|
||||
border-color: var(--accent);
|
||||
background: var(--accent-lo);
|
||||
border-color: var(--accent-lo);
|
||||
}
|
||||
.switch.on .knob {
|
||||
transform: translateX(15px);
|
||||
background: var(--accent-contrast);
|
||||
background: var(--accent-ink);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -369,7 +369,7 @@
|
||||
}
|
||||
.wb-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.wb-input::placeholder {
|
||||
color: var(--text-3);
|
||||
@@ -438,7 +438,7 @@
|
||||
}
|
||||
.btn.ghost:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.btn.gen {
|
||||
color: var(--accent);
|
||||
|
||||
@@ -60,8 +60,8 @@
|
||||
background: var(--surface-3);
|
||||
}
|
||||
.st-running {
|
||||
color: var(--accent);
|
||||
background: var(--accent-dim);
|
||||
color: var(--run);
|
||||
background: var(--run-soft);
|
||||
}
|
||||
.st-done {
|
||||
color: var(--success);
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
}
|
||||
.wb-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.wb-input::placeholder {
|
||||
color: var(--text-3);
|
||||
@@ -294,7 +294,7 @@
|
||||
}
|
||||
.btn.ghost:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.btn.sm {
|
||||
padding: 6px 12px;
|
||||
|
||||
@@ -341,7 +341,7 @@
|
||||
}
|
||||
.wb-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.wb-input::placeholder {
|
||||
color: var(--text-3);
|
||||
@@ -412,7 +412,7 @@
|
||||
}
|
||||
.btn.ghost:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.btn.gen {
|
||||
color: var(--accent);
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import { t } from '$lib/i18n.svelte';
|
||||
|
||||
/**
|
||||
* Five-stage stepper (a2): one step per agent with the spec §2.1 semantic
|
||||
* colors — gray=待开始, amber=进行中/待确认 (+breath while running),
|
||||
* green=已确认, blue=用户改过草稿. A step unlocks when itself or any
|
||||
* Five-stage stepper (a2): one step per agent with the fusion status
|
||||
* colors — gray=待开始, cyan=进行中 (+breath), amber=待确认,
|
||||
* green=已确认, --info=用户改过草稿. A step unlocks when itself or any
|
||||
* earlier stage has content; later steps stay clickable only after the
|
||||
* previous one is confirmed.
|
||||
*/
|
||||
@@ -159,7 +159,7 @@
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #edeef0;
|
||||
color: var(--text);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -188,12 +188,14 @@
|
||||
.st-todo {
|
||||
color: var(--text-3);
|
||||
}
|
||||
.st-running,
|
||||
.st-running {
|
||||
color: var(--run);
|
||||
}
|
||||
.st-draft {
|
||||
color: var(--accent);
|
||||
color: var(--warn);
|
||||
}
|
||||
.st-edited {
|
||||
color: var(--info);
|
||||
color: var(--warn);
|
||||
}
|
||||
.st-confirmed {
|
||||
color: var(--success);
|
||||
@@ -201,14 +203,14 @@
|
||||
|
||||
.step-btn.active[data-state='running'] .avatar,
|
||||
.step-btn[data-state='running'] .avatar {
|
||||
box-shadow: 0 0 10px rgba(232, 163, 61, 0.35);
|
||||
box-shadow: 0 0 10px var(--run-soft);
|
||||
}
|
||||
|
||||
.breath {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
background: var(--run);
|
||||
animation: wb-breath 2s cubic-bezier(0.16, 1, 0.3, 1) infinite;
|
||||
}
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@
|
||||
}
|
||||
.wb-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.wb-input::placeholder {
|
||||
color: var(--text-3);
|
||||
@@ -386,7 +386,7 @@
|
||||
}
|
||||
.btn.ghost:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.btn:disabled {
|
||||
opacity: 0.4;
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
}
|
||||
.dir-card.chosen {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 10px rgba(232, 163, 61, 0.35);
|
||||
box-shadow: 0 0 10px var(--accent-glow);
|
||||
}
|
||||
.dir-card input[type='radio'] {
|
||||
position: absolute;
|
||||
@@ -310,7 +310,7 @@
|
||||
}
|
||||
.wb-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.wb-input::placeholder {
|
||||
color: var(--text-3);
|
||||
@@ -375,7 +375,7 @@
|
||||
}
|
||||
.btn.ghost:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.btn:disabled {
|
||||
opacity: 0.4;
|
||||
|
||||
@@ -245,11 +245,11 @@
|
||||
return parts.filter(Boolean).join(' · ');
|
||||
}
|
||||
|
||||
function jobBar(job: Job): { value: number; tone: 'accent' | 'success' | 'error' } {
|
||||
function jobBar(job: Job): { value: number; tone: 'run' | 'success' | 'error' } {
|
||||
if (job.status === 'done') return { value: 100, tone: 'success' };
|
||||
if (job.status === 'failed') return { value: 100, tone: 'error' };
|
||||
if (job.status === 'running') return { value: progressFor(job.id)?.progress ?? 3, tone: 'accent' };
|
||||
return { value: 0, tone: 'accent' };
|
||||
if (job.status === 'running') return { value: progressFor(job.id)?.progress ?? 3, tone: 'run' };
|
||||
return { value: 0, tone: 'run' };
|
||||
}
|
||||
|
||||
function jobStatusLabel(status: string): string {
|
||||
@@ -493,7 +493,7 @@
|
||||
<aside class="tasks">
|
||||
<div class="tasks-head">
|
||||
<h2>{t('home.tasksTitle')}</h2>
|
||||
<span class="chip" class:amber={activeJobCount > 0}>
|
||||
<span class="chip" class:run={activeJobCount > 0}>
|
||||
{t('home.activeJobs', { n: activeJobCount })}
|
||||
</span>
|
||||
</div>
|
||||
@@ -580,9 +580,9 @@
|
||||
font-size: 11.5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.chip.amber {
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
.chip.run {
|
||||
background: var(--run-soft);
|
||||
color: var(--run);
|
||||
}
|
||||
|
||||
.entry-btn {
|
||||
@@ -616,7 +616,7 @@
|
||||
color: var(--text);
|
||||
}
|
||||
.entry-btn.secondary:hover {
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.entry-btn:active {
|
||||
transform: scale(0.98);
|
||||
@@ -651,7 +651,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--accent);
|
||||
color: var(--text-2);
|
||||
}
|
||||
.entry-card h2 {
|
||||
margin: 4px 0 0;
|
||||
@@ -736,10 +736,10 @@
|
||||
}
|
||||
.f-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.f-input.invalid {
|
||||
border-color: rgba(229, 72, 77, 0.65);
|
||||
border-color: var(--err-line);
|
||||
}
|
||||
.f-hint {
|
||||
display: block;
|
||||
@@ -908,13 +908,10 @@
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.tag-local {
|
||||
background: var(--info-dim);
|
||||
color: var(--info);
|
||||
}
|
||||
.tag-local,
|
||||
.tag-cloud {
|
||||
background: var(--cloud-dim);
|
||||
color: var(--cloud);
|
||||
background: var(--bg-4);
|
||||
color: var(--text-2);
|
||||
}
|
||||
.job-name {
|
||||
flex: 1;
|
||||
@@ -950,7 +947,7 @@
|
||||
color: var(--success);
|
||||
}
|
||||
.running-text {
|
||||
color: var(--accent);
|
||||
color: var(--run);
|
||||
}
|
||||
.queued-text {
|
||||
color: var(--text-3);
|
||||
@@ -966,8 +963,8 @@
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 10px var(--accent-glow);
|
||||
background: var(--run);
|
||||
box-shadow: 0 0 10px var(--run-soft);
|
||||
}
|
||||
.dot.breathe {
|
||||
animation: breathe 2s ease-in-out infinite;
|
||||
|
||||
@@ -1133,11 +1133,11 @@
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #edeef0;
|
||||
color: var(--text);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.avatar.dark {
|
||||
color: #16130a;
|
||||
color: var(--accent-ink);
|
||||
}
|
||||
.avatar.lg {
|
||||
width: 42px;
|
||||
@@ -1294,8 +1294,8 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
.status-tag.busy {
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
background: var(--run-soft);
|
||||
color: var(--run);
|
||||
}
|
||||
.chat-head-actions {
|
||||
display: flex;
|
||||
@@ -1618,7 +1618,7 @@
|
||||
background: var(--success);
|
||||
}
|
||||
.dot.amber {
|
||||
background: var(--accent);
|
||||
background: var(--run);
|
||||
}
|
||||
.dot.amber.breathing {
|
||||
animation: breathe 2s ease-in-out infinite;
|
||||
|
||||
+401
-149
@@ -4,84 +4,201 @@
|
||||
|
||||
:root {
|
||||
/* ------------------------------------------------------------------
|
||||
* A「片场暗房」design tokens — spec-v2 §2 (HEL-603 confirmed).
|
||||
* Single source of truth for the whole app: do not hardcode colors in
|
||||
* pages or components, and do not override these with ad-hoc CSS.
|
||||
* 融合视觉 design tokens — HEL-649 整站施工规范 §一(流水台结构 ×
|
||||
* 放映厅配色)。Single source of truth for the whole app: pages and
|
||||
* components reference these variables only — no hardcoded colors,
|
||||
* no ad-hoc overrides. Gold is for key actions and the current
|
||||
* selection only; status colors each carry exactly one meaning.
|
||||
* ------------------------------------------------------------------ */
|
||||
--bg: #0d0e11;
|
||||
--surface: #14161b;
|
||||
--surface-2: #1b1e25;
|
||||
--surface-3: #22262f;
|
||||
--border: rgba(255, 255, 255, 0.07);
|
||||
--border-strong: rgba(255, 255, 255, 0.14);
|
||||
--border-hover: rgba(255, 255, 255, 0.24);
|
||||
--text: #edeef0;
|
||||
--text-2: #9ba1ab;
|
||||
--text-3: #5c626c;
|
||||
--accent: #e8a33d;
|
||||
--accent-hover: #f1b155; /* +8% brightness (§5 主按钮) */
|
||||
--accent-contrast: #16130a;
|
||||
--accent-dim: rgba(232, 163, 61, 0.14);
|
||||
--accent-glow: rgba(232, 163, 61, 0.35);
|
||||
--accent-focus: rgba(232, 163, 61, 0.6);
|
||||
--success: #3fb97f;
|
||||
--success-dim: rgba(63, 185, 127, 0.14);
|
||||
--info: #5b8def;
|
||||
--info-dim: rgba(91, 141, 239, 0.14);
|
||||
--error: #e5484d;
|
||||
--error-dim: rgba(229, 72, 77, 0.14);
|
||||
--error-border: rgba(229, 72, 77, 0.4);
|
||||
--cloud: #b98be0;
|
||||
--cloud-dim: rgba(185, 139, 224, 0.14);
|
||||
|
||||
/* Avatar five-color set (§2.1) — five agents only */
|
||||
/* 底色:蓝黑四阶,逐层浮起 (§1.1) */
|
||||
--bg: #07090e;
|
||||
--bg-2: #0c0f16;
|
||||
--bg-3: #121724;
|
||||
--bg-4: #1a2133;
|
||||
--line: #1b2233;
|
||||
--line-2: #2a3450;
|
||||
--page-glow: radial-gradient(1200px 500px at 70% -10%, rgba(38, 52, 92, 0.25), transparent 60%);
|
||||
--float-bg: linear-gradient(180deg, #10152a, var(--bg-2));
|
||||
--overlay: rgba(4, 6, 10, 0.6);
|
||||
--media-scrim: rgba(7, 9, 14, 0.65);
|
||||
--on-media: #fff;
|
||||
--on-media-line: rgba(255, 255, 255, 0.05);
|
||||
|
||||
/* 放映金:主按钮、当前选中、改过的参数、聚焦框、Toast 动作 (§1.2) */
|
||||
--accent: #f2c784;
|
||||
--accent-ink: #23170a;
|
||||
--accent-soft: rgba(242, 199, 132, 0.13);
|
||||
--accent-hi: #f7d9a2;
|
||||
--accent-lo: #ecaf63;
|
||||
--accent-glow: rgba(236, 175, 99, 0.28);
|
||||
--accent-line: rgba(242, 199, 132, 0.55);
|
||||
--accent-grad: linear-gradient(180deg, var(--accent-hi), var(--accent-lo));
|
||||
--accent-grad-hover: linear-gradient(180deg, #fbe3b6, #f0b968);
|
||||
--accent-ring: 0 0 0 1px rgba(242, 199, 132, 0.7), 0 0 22px var(--accent-glow);
|
||||
--btn-glow: 0 2px 14px var(--accent-glow), inset 0 1px 0 rgba(255, 255, 255, 0.35);
|
||||
--btn-glow-hover: 0 4px 18px var(--accent-glow), inset 0 1px 0 rgba(255, 255, 255, 0.4);
|
||||
|
||||
/* 信号色:绿=完成/已确认/通过,青=进行中/在线,红=失败/危险,
|
||||
琥珀=待确认/文件缺失/限额 (§1.3) */
|
||||
--ok: #49cb90;
|
||||
--ok-soft: rgba(73, 203, 144, 0.13);
|
||||
--run: #54dfd2;
|
||||
--run-soft: rgba(84, 223, 210, 0.13);
|
||||
--run-grad: linear-gradient(90deg, #3bbfb4, var(--run));
|
||||
--err: #f0645a;
|
||||
--err-soft: rgba(240, 100, 90, 0.13);
|
||||
--err-line: rgba(240, 100, 90, 0.6);
|
||||
--warn: #f0b45c;
|
||||
--warn-soft: rgba(240, 180, 92, 0.13);
|
||||
|
||||
/* 文字与字体 (§1.4);--text-2 是深底可读性下限,不得再暗 */
|
||||
--text: #f4f6fa;
|
||||
--text-2: #aab2c5;
|
||||
--text-3: #6d7690;
|
||||
--font: 'PingFang SC', 'Noto Sans SC', 'Microsoft YaHei', system-ui, sans-serif;
|
||||
--mono: 'JetBrains Mono', ui-monospace, monospace;
|
||||
--fs-title: 15px;
|
||||
--fs-section: 14px;
|
||||
--fs-body: 13px;
|
||||
--fs-body-sm: 12.5px;
|
||||
--fs-aux: 12px;
|
||||
--fs-mini: 11px;
|
||||
--lh-body: 1.55;
|
||||
|
||||
/* 间距阶梯 4/6/8/10/12/16/20/28,不得出现阶梯外数值 (§1.5) */
|
||||
--sp-1: 4px;
|
||||
--sp-2: 6px;
|
||||
--sp-3: 8px;
|
||||
--sp-4: 10px;
|
||||
--sp-5: 12px;
|
||||
--sp-6: 16px;
|
||||
--sp-7: 20px;
|
||||
--sp-8: 28px;
|
||||
|
||||
/* 圆角与唯一一级阴影 (§1.5);卡片不投影,用底色差分层 */
|
||||
--r-sm: 6px;
|
||||
--r-md: 10px;
|
||||
--r-lg: 14px;
|
||||
--r-pill: 999px;
|
||||
--shadow-float: 0 14px 44px rgba(0, 0, 0, 0.6), 0 0 0 1px var(--line-2);
|
||||
|
||||
/* 专属符号 (§1.7):齿孔只在记录流/输入台分隔带,光晕只在播放舞台 */
|
||||
--sprocket: radial-gradient(circle 2px, var(--line-2) 98%, transparent);
|
||||
--stage-bg:
|
||||
radial-gradient(60% 45% at 50% 38%, rgba(242, 199, 132, 0.07), transparent 70%),
|
||||
radial-gradient(80% 70% at 50% 50%, #0d1220, #05070c);
|
||||
|
||||
/* 动效 (§1.6,取 HEL-648 实测值);只动 transform / opacity */
|
||||
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
|
||||
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
|
||||
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
|
||||
--ease-spring: cubic-bezier(0.34, 1.45, 0.44, 1);
|
||||
--d-press: 120ms;
|
||||
--d-state: 150ms;
|
||||
--d-pop: 180ms;
|
||||
--d-leave: 200ms;
|
||||
--d-enter: 220ms;
|
||||
--d-drawer: 280ms;
|
||||
--d-flash: 900ms;
|
||||
--d-progress: 400ms;
|
||||
--press-scale: 0.97;
|
||||
|
||||
/* Avatar five-color set — five agents only; the one colorful gradient
|
||||
family the spec keeps (§3.6). */
|
||||
--avatar-1: linear-gradient(135deg, #e8a33d, #b96a1b);
|
||||
--avatar-2: linear-gradient(135deg, #5b8def, #3a5fa9);
|
||||
--avatar-3: linear-gradient(135deg, #3fb97f, #2a7a54);
|
||||
--avatar-4: linear-gradient(135deg, #b98be0, #7a4fa9);
|
||||
--avatar-5: linear-gradient(135deg, #d98e6a, #a95535);
|
||||
|
||||
/* Typography (§2.2) */
|
||||
--font-ui: 'Noto Sans SC', 'Noto Sans CJK SC', sans-serif;
|
||||
--font-a-mono: 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, monospace;
|
||||
|
||||
/* Radius / spacing (§2.3) */
|
||||
--radius-sm: 7px;
|
||||
--radius-md: 10px;
|
||||
--radius-lg: 10px;
|
||||
|
||||
--space-xs: 4px;
|
||||
--space-sm: 8px;
|
||||
--space-md: 16px;
|
||||
--space-lg: 24px;
|
||||
--space-xl: 32px;
|
||||
|
||||
/* Legacy token names used by shared primitives — aliases of the A set,
|
||||
so every component renders in the same darkroom palette. */
|
||||
/* ------------------------------------------------------------------
|
||||
* Legacy token names (§六 映射表) — aliases only, never new values,
|
||||
* so every existing component renders in the fusion palette.
|
||||
* ------------------------------------------------------------------ */
|
||||
--surface: var(--bg-2);
|
||||
--surface-2: var(--bg-3);
|
||||
--surface-3: var(--bg-4);
|
||||
--border: var(--line);
|
||||
--border-strong: var(--line-2);
|
||||
--border-hover: var(--line-2);
|
||||
--accent-hover: var(--accent-hi);
|
||||
--accent-contrast: var(--accent-ink);
|
||||
--accent-dim: var(--accent-soft);
|
||||
--accent-focus: var(--accent-line);
|
||||
--success: var(--ok);
|
||||
--success-dim: var(--ok-soft);
|
||||
--info: var(--run);
|
||||
--info-dim: var(--run-soft);
|
||||
--error: var(--err);
|
||||
--error-dim: var(--err-soft);
|
||||
--error-border: var(--err-line);
|
||||
--warning: var(--warn);
|
||||
--bg-primary: var(--bg);
|
||||
--bg-surface: var(--surface);
|
||||
--bg-elevated: var(--surface-2);
|
||||
--bg-surface: var(--bg-2);
|
||||
--bg-elevated: var(--bg-3);
|
||||
--text-primary: var(--text);
|
||||
--text-secondary: var(--text-2);
|
||||
--text-muted: var(--text-3);
|
||||
--warning: var(--accent);
|
||||
--font-display: var(--font-ui);
|
||||
--font-body: var(--font-ui);
|
||||
--font-mono: var(--font-a-mono);
|
||||
--font-ui: var(--font);
|
||||
--font-a-mono: var(--mono);
|
||||
--font-display: var(--font);
|
||||
--font-body: var(--font);
|
||||
--font-mono: var(--mono);
|
||||
--radius-sm: var(--r-sm);
|
||||
--radius-md: var(--r-md);
|
||||
--radius-lg: var(--r-lg);
|
||||
--space-xs: var(--sp-1);
|
||||
--space-sm: var(--sp-3);
|
||||
--space-md: var(--sp-6);
|
||||
--space-lg: var(--sp-7);
|
||||
--space-xl: var(--sp-8);
|
||||
|
||||
/* Omni Composer pill tokens */
|
||||
--pill-bg: var(--surface-2);
|
||||
--pill-border: var(--border-strong);
|
||||
--pill-radius: 9999px;
|
||||
--pill-bg: var(--bg-3);
|
||||
--pill-border: var(--line-2);
|
||||
--pill-radius: var(--r-pill);
|
||||
--pill-height: 36px;
|
||||
--pill-padding: 0 14px;
|
||||
--pill-font-size: 13px;
|
||||
--pill-font-size: var(--fs-body);
|
||||
}
|
||||
|
||||
/* 减少动态效果 (§五):系统设置自动生效,顶栏开关写 data-reduce="1"。
|
||||
位移/缩放/弹入/光晕全部取消,只留 ≤120ms 透明度,进度条直接跳变。 */
|
||||
:root[data-reduce='1'] {
|
||||
--d-press: 0ms;
|
||||
--d-state: 120ms;
|
||||
--d-pop: 120ms;
|
||||
--d-leave: 120ms;
|
||||
--d-enter: 120ms;
|
||||
--d-drawer: 120ms;
|
||||
--d-flash: 0ms;
|
||||
--d-progress: 0ms;
|
||||
--press-scale: 1;
|
||||
--ease-spring: ease;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
:root {
|
||||
--d-press: 0ms;
|
||||
--d-state: 120ms;
|
||||
--d-pop: 120ms;
|
||||
--d-leave: 120ms;
|
||||
--d-enter: 120ms;
|
||||
--d-drawer: 120ms;
|
||||
--d-flash: 0ms;
|
||||
--d-progress: 0ms;
|
||||
--press-scale: 1;
|
||||
--ease-spring: ease;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
background: var(--page-glow), var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font-ui);
|
||||
font-family: var(--font);
|
||||
font-size: var(--fs-body);
|
||||
line-height: var(--lh-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
@@ -89,20 +206,20 @@ body {
|
||||
.a-darkroom {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: var(--font-ui);
|
||||
font-size: 13.5px;
|
||||
line-height: 1.6;
|
||||
font-family: var(--font);
|
||||
font-size: var(--fs-body);
|
||||
line-height: var(--lh-body);
|
||||
}
|
||||
|
||||
code,
|
||||
.mono,
|
||||
.kh {
|
||||
font-family: var(--font-a-mono);
|
||||
font-family: var(--mono);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Shared A controls (§5 组件状态全表). The only definitions of these
|
||||
* Shared controls (§四 组件状态通用规范). The only definitions of these
|
||||
* looks — `ui/Button.svelte` renders `.a-btn`, pages use the classes
|
||||
* directly for links / selects. Page styles may only tweak layout
|
||||
* (width / margin), never re-declare colors.
|
||||
@@ -111,91 +228,120 @@ code,
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
gap: var(--sp-2);
|
||||
min-height: 34px;
|
||||
padding: 0 16px;
|
||||
border-radius: 8px;
|
||||
padding: 0 var(--sp-6);
|
||||
border-radius: var(--r-md);
|
||||
border: 1px solid transparent;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
font-size: var(--fs-body);
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
transition:
|
||||
background-color 150ms cubic-bezier(0.16, 1, 0.3, 1),
|
||||
border-color 150ms,
|
||||
color 150ms,
|
||||
transform 100ms;
|
||||
transform var(--d-press) var(--ease-out),
|
||||
background-color var(--d-state) ease,
|
||||
border-color var(--d-state) ease,
|
||||
box-shadow var(--d-state) ease,
|
||||
color var(--d-state) ease,
|
||||
opacity var(--d-state) ease;
|
||||
}
|
||||
.a-btn.lg {
|
||||
min-height: 38px;
|
||||
padding: 0 var(--sp-7);
|
||||
}
|
||||
.a-btn.sm {
|
||||
min-height: 30px;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
min-height: 28px;
|
||||
padding: 0 var(--sp-4);
|
||||
font-size: var(--fs-aux);
|
||||
border-radius: var(--r-sm);
|
||||
}
|
||||
.a-btn.xs {
|
||||
min-height: 24px;
|
||||
padding: 0 9px;
|
||||
font-size: 11px;
|
||||
padding: 0 var(--sp-3);
|
||||
font-size: var(--fs-mini);
|
||||
border-radius: var(--r-sm);
|
||||
}
|
||||
.a-btn.block {
|
||||
width: 100%;
|
||||
}
|
||||
.a-btn.primary {
|
||||
background: var(--accent);
|
||||
color: var(--accent-contrast);
|
||||
}
|
||||
.a-btn.primary:hover:not(:disabled) {
|
||||
background: var(--accent-hover);
|
||||
background: var(--accent-grad);
|
||||
color: var(--accent-ink);
|
||||
box-shadow: var(--btn-glow);
|
||||
}
|
||||
.a-btn.secondary {
|
||||
background: var(--surface-2);
|
||||
border-color: var(--border-strong);
|
||||
background: var(--bg-3);
|
||||
border-color: var(--line);
|
||||
color: var(--text);
|
||||
}
|
||||
.a-btn.secondary:hover:not(:disabled) {
|
||||
border-color: var(--border-hover);
|
||||
}
|
||||
.a-btn.ghost {
|
||||
background: transparent;
|
||||
color: var(--text-2);
|
||||
}
|
||||
.a-btn.ghost:hover:not(:disabled) {
|
||||
background: var(--surface-3);
|
||||
color: var(--text);
|
||||
}
|
||||
/* 危险两级制:列表行内只用描边红 danger;实心红 danger-solid 只在确认弹层内。 */
|
||||
.a-btn.danger {
|
||||
background: transparent;
|
||||
border-color: var(--error-border);
|
||||
color: var(--error);
|
||||
border-color: var(--err-line);
|
||||
color: var(--err);
|
||||
}
|
||||
.a-btn.danger:hover:not(:disabled) {
|
||||
background: var(--error-dim);
|
||||
.a-btn.danger-solid {
|
||||
background: var(--err);
|
||||
color: var(--on-media);
|
||||
}
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.a-btn.primary:hover:not(:disabled) {
|
||||
background: var(--accent-grad-hover);
|
||||
box-shadow: var(--btn-glow-hover);
|
||||
}
|
||||
.a-btn.secondary:hover:not(:disabled) {
|
||||
border-color: var(--line-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
.a-btn.ghost:hover:not(:disabled) {
|
||||
background: var(--bg-4);
|
||||
color: var(--text);
|
||||
}
|
||||
.a-btn.danger:hover:not(:disabled) {
|
||||
background: var(--err-soft);
|
||||
}
|
||||
.a-btn.danger-solid:hover:not(:disabled) {
|
||||
box-shadow:
|
||||
0 0 0 1px var(--err-line),
|
||||
0 0 18px var(--err-soft);
|
||||
}
|
||||
}
|
||||
.a-btn:active:not(:disabled) {
|
||||
transform: scale(0.98);
|
||||
transform: scale(var(--press-scale));
|
||||
}
|
||||
/* 禁用必须在旁边给出中文原因(§1.2),由调用方渲染。 */
|
||||
.a-btn:disabled,
|
||||
.a-btn[aria-disabled='true'] {
|
||||
opacity: 0.4;
|
||||
opacity: 0.45;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Top-bar status capsule (counts / save state / connection). */
|
||||
/* Top-bar status capsule (queue / connection / save state) — §二 顶栏胶囊. */
|
||||
.status-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 5px 12px;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-3);
|
||||
gap: var(--sp-2);
|
||||
height: 30px;
|
||||
padding: 0 var(--sp-5);
|
||||
border-radius: var(--r-pill);
|
||||
border: 1px solid var(--line);
|
||||
background: var(--bg-2);
|
||||
color: var(--text-2);
|
||||
font-size: 11.5px;
|
||||
font-size: var(--fs-aux);
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.status-chip.accent {
|
||||
background: var(--accent-dim);
|
||||
background: var(--accent-soft);
|
||||
border-color: var(--accent-line);
|
||||
color: var(--accent);
|
||||
}
|
||||
.status-chip-dot {
|
||||
@@ -206,33 +352,122 @@ code,
|
||||
background: currentColor;
|
||||
}
|
||||
.status-chip-dot.ok {
|
||||
background: var(--success);
|
||||
background: var(--ok);
|
||||
}
|
||||
.status-chip-dot.run {
|
||||
background: var(--run);
|
||||
}
|
||||
.status-chip-dot.fail {
|
||||
background: var(--error);
|
||||
background: var(--err);
|
||||
}
|
||||
.status-chip-dot.idle {
|
||||
background: var(--text-3);
|
||||
}
|
||||
|
||||
/* Card / panel surface (§2.3: 10px radius, 1px border, no shadow). */
|
||||
/* Status label (§四.2):语义色文字 + 13% 软底;默认为中性(排队 / 未开始)。 */
|
||||
.a-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-1);
|
||||
height: 20px;
|
||||
padding: 0 var(--sp-2);
|
||||
border-radius: var(--r-sm);
|
||||
background: var(--bg-4);
|
||||
color: var(--text-2);
|
||||
font-size: var(--fs-aux);
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
transition:
|
||||
color var(--d-state) ease,
|
||||
background-color var(--d-state) ease;
|
||||
}
|
||||
.a-tag.accent {
|
||||
color: var(--accent);
|
||||
background: var(--accent-soft);
|
||||
}
|
||||
.a-tag.ok {
|
||||
color: var(--ok);
|
||||
background: var(--ok-soft);
|
||||
}
|
||||
.a-tag.run {
|
||||
color: var(--run);
|
||||
background: var(--run-soft);
|
||||
}
|
||||
.a-tag.err {
|
||||
color: var(--err);
|
||||
background: var(--err-soft);
|
||||
}
|
||||
.a-tag.warn {
|
||||
color: var(--warn);
|
||||
background: var(--warn-soft);
|
||||
}
|
||||
|
||||
/* Real-progress bar (§1.3):<div class="a-progress" style="--p:.42"><i></i></div>.
|
||||
Only for true progress values — never fake progress. */
|
||||
.a-progress {
|
||||
position: relative;
|
||||
height: 4px;
|
||||
border-radius: var(--r-pill);
|
||||
background: var(--bg-4);
|
||||
overflow: hidden;
|
||||
}
|
||||
.a-progress > i {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--run-grad);
|
||||
box-shadow: 0 0 8px var(--run-soft);
|
||||
transform-origin: left;
|
||||
transform: scaleX(var(--p, 0));
|
||||
transition: transform var(--d-progress) linear;
|
||||
}
|
||||
|
||||
/* Film sprocket divider — only between the take feed and the composer (§1.7). */
|
||||
.a-sprocket {
|
||||
height: 6px;
|
||||
background-image: var(--sprocket);
|
||||
background-size: 18px 6px;
|
||||
background-repeat: repeat-x;
|
||||
background-position: center;
|
||||
opacity: 0.55;
|
||||
}
|
||||
:root[data-reduce='1'] .a-sprocket {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* Projection stage — only behind media in the inspector (§1.7). */
|
||||
.a-stage {
|
||||
position: relative;
|
||||
border-radius: var(--r-lg);
|
||||
overflow: hidden;
|
||||
background: var(--stage-bg);
|
||||
box-shadow: 0 0 0 1px var(--line);
|
||||
}
|
||||
|
||||
/* Floating surface for pop / drawer / confirm / toast / lightbox (§四.3). */
|
||||
.a-float {
|
||||
background: var(--float-bg);
|
||||
border-radius: var(--r-lg);
|
||||
box-shadow: var(--shadow-float);
|
||||
}
|
||||
|
||||
/* Card / panel surface (§1.5:卡片不投影,用底色差分层). */
|
||||
.a-panel {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 20px 22px;
|
||||
background: var(--bg-2);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--r-lg);
|
||||
padding: var(--sp-7);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.a-panel-title {
|
||||
margin: 0;
|
||||
font-size: 14.5px;
|
||||
font-size: var(--fs-section);
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
.a-panel-lead {
|
||||
margin: 4px 0 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
margin: var(--sp-1) 0 0;
|
||||
font-size: var(--fs-aux);
|
||||
line-height: var(--lh-body);
|
||||
color: var(--text-3);
|
||||
}
|
||||
|
||||
@@ -243,39 +478,47 @@ code,
|
||||
.field-textarea,
|
||||
.field-select {
|
||||
box-sizing: border-box;
|
||||
background: var(--surface-2);
|
||||
border: 1px solid var(--border-strong);
|
||||
border-radius: 7px;
|
||||
background: var(--bg-3);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--r-md);
|
||||
color: var(--text);
|
||||
font-family: inherit;
|
||||
font-size: 12.5px;
|
||||
transition: border-color 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
font-size: var(--fs-body-sm);
|
||||
transition: border-color var(--d-state) ease;
|
||||
}
|
||||
.a-select {
|
||||
padding: 7px 9px;
|
||||
padding: var(--sp-2) var(--sp-4);
|
||||
cursor: pointer;
|
||||
}
|
||||
.a-input,
|
||||
.field-input,
|
||||
.field-select {
|
||||
width: 100%;
|
||||
padding: 8px 11px;
|
||||
padding: var(--sp-3) var(--sp-5);
|
||||
}
|
||||
.a-textarea,
|
||||
.field-textarea {
|
||||
width: 100%;
|
||||
padding: 9px 11px;
|
||||
padding: var(--sp-4) var(--sp-5);
|
||||
resize: vertical;
|
||||
min-height: 96px;
|
||||
line-height: 1.6;
|
||||
line-height: var(--lh-body);
|
||||
}
|
||||
.a-select:hover,
|
||||
.a-input:hover,
|
||||
.a-textarea:hover,
|
||||
.field-input:hover,
|
||||
.field-textarea:hover,
|
||||
.field-select:hover {
|
||||
border-color: var(--border-hover);
|
||||
.a-input::placeholder,
|
||||
.a-textarea::placeholder,
|
||||
.field-input::placeholder,
|
||||
.field-textarea::placeholder {
|
||||
color: var(--text-3);
|
||||
}
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.a-select:hover,
|
||||
.a-input:hover,
|
||||
.a-textarea:hover,
|
||||
.field-input:hover,
|
||||
.field-textarea:hover,
|
||||
.field-select:hover {
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
}
|
||||
.a-select:focus,
|
||||
.a-input:focus,
|
||||
@@ -284,12 +527,12 @@ code,
|
||||
.field-textarea:focus,
|
||||
.field-select:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-focus);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.a-input.invalid,
|
||||
.a-textarea.invalid,
|
||||
.field-input.invalid {
|
||||
border-color: var(--error);
|
||||
border-color: var(--err);
|
||||
}
|
||||
.a-select option.unavailable {
|
||||
color: var(--text-3);
|
||||
@@ -297,30 +540,30 @@ code,
|
||||
|
||||
.field {
|
||||
display: block;
|
||||
margin-bottom: 14px;
|
||||
margin-bottom: var(--sp-5);
|
||||
}
|
||||
.field-label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-size: var(--fs-aux);
|
||||
font-weight: 500;
|
||||
color: var(--text-2);
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: var(--sp-2);
|
||||
}
|
||||
.field-hint {
|
||||
margin: 6px 0 0;
|
||||
font-size: 11.5px;
|
||||
margin: var(--sp-2) 0 0;
|
||||
font-size: var(--fs-aux);
|
||||
color: var(--text-3);
|
||||
}
|
||||
.field-error {
|
||||
margin: 6px 0 0;
|
||||
font-size: 11.5px;
|
||||
color: var(--error);
|
||||
margin: var(--sp-2) 0 0;
|
||||
font-size: var(--fs-aux);
|
||||
color: var(--err);
|
||||
}
|
||||
|
||||
/* Dark theme scrollbars (Firefox + Chromium) */
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--surface-3) transparent;
|
||||
scrollbar-color: var(--bg-4) transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
@@ -333,8 +576,8 @@ code,
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: var(--surface-3);
|
||||
border-radius: 999px;
|
||||
background: var(--bg-4);
|
||||
border-radius: var(--r-pill);
|
||||
border: 2px solid transparent;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
@@ -349,17 +592,19 @@ code,
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Global keyboard focus fallback: every natively focusable element gets a ring,
|
||||
even before the ui/ primitives are adopted. Component-scoped :focus-visible
|
||||
rules (e.g. .field-input) override this via higher specificity. */
|
||||
/* Global keyboard focus (§四.8): every natively focusable element gets the
|
||||
gold ring. Component-scoped :focus-visible rules override this via higher
|
||||
specificity. */
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 2px;
|
||||
border-radius: var(--r-sm);
|
||||
}
|
||||
|
||||
/* Global reduced-motion baseline. Components that need a styled static fallback
|
||||
(Skeleton shimmer, ProgressBar indeterminate, StatusChip pulse) also handle
|
||||
this in their own scoped styles. */
|
||||
/* Reduced-motion baseline for components that still carry their own
|
||||
durations. Components that need a styled static fallback (Skeleton,
|
||||
ProgressBar indeterminate, StatusChip pulse) also handle this in their
|
||||
scoped styles. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
@@ -369,3 +614,10 @@ code,
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
:root[data-reduce='1'] *,
|
||||
:root[data-reduce='1'] *::before,
|
||||
:root[data-reduce='1'] *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
|
||||
@@ -1654,7 +1654,7 @@
|
||||
transition: border-color 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
.card.failed {
|
||||
border-color: rgba(229, 72, 77, 0.35);
|
||||
border-color: color-mix(in srgb, var(--err) 35%, transparent);
|
||||
}
|
||||
.card-row {
|
||||
display: flex;
|
||||
@@ -1671,7 +1671,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--accent);
|
||||
color: var(--text-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.card-name {
|
||||
@@ -1688,13 +1688,10 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
.tag-local,
|
||||
.tag-lan {
|
||||
color: var(--info);
|
||||
background: var(--info-dim);
|
||||
}
|
||||
.tag-lan,
|
||||
.tag-cloud {
|
||||
color: var(--cloud);
|
||||
background: var(--cloud-dim);
|
||||
color: var(--text-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
.tag-auth {
|
||||
color: var(--text-2);
|
||||
@@ -1743,8 +1740,8 @@
|
||||
background: var(--text-3);
|
||||
}
|
||||
.dot.amber {
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 10px var(--accent-glow);
|
||||
background: var(--run);
|
||||
box-shadow: 0 0 10px var(--run-soft);
|
||||
}
|
||||
.dot.breathing {
|
||||
animation: breathe 2s ease-in-out infinite;
|
||||
@@ -1769,7 +1766,7 @@
|
||||
color: var(--error);
|
||||
}
|
||||
.status-text.amber {
|
||||
color: var(--accent);
|
||||
color: var(--run);
|
||||
}
|
||||
.status-text.gray {
|
||||
color: var(--text-3);
|
||||
@@ -1959,7 +1956,7 @@
|
||||
border-color: var(--error);
|
||||
}
|
||||
.wf-conn-check.warn {
|
||||
border-color: var(--accent);
|
||||
border-color: var(--warn);
|
||||
}
|
||||
.wf-conn-head {
|
||||
display: flex;
|
||||
@@ -1977,7 +1974,7 @@
|
||||
color: var(--error);
|
||||
}
|
||||
.wf-conn-check.warn .wf-conn-head :global(.icon) {
|
||||
color: var(--accent);
|
||||
color: var(--warn);
|
||||
}
|
||||
.wf-conn-title {
|
||||
font-size: 12px;
|
||||
@@ -2067,7 +2064,7 @@
|
||||
cursor: help;
|
||||
}
|
||||
.wf-meta-item.recheck.warn .wf-recheck-text {
|
||||
color: var(--accent);
|
||||
color: var(--warn);
|
||||
}
|
||||
.wf-evidence {
|
||||
margin: 0 0 12px;
|
||||
@@ -2198,15 +2195,15 @@
|
||||
color: var(--error);
|
||||
}
|
||||
.tag-usage {
|
||||
color: var(--accent);
|
||||
background: var(--accent-dim);
|
||||
color: var(--text-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
.tag-disabled {
|
||||
color: var(--text-3);
|
||||
background: var(--surface-3);
|
||||
}
|
||||
.wf-pending-note {
|
||||
color: var(--accent);
|
||||
color: var(--warn);
|
||||
}
|
||||
.wf-row.pending .wf-name {
|
||||
color: var(--text-3);
|
||||
@@ -2252,7 +2249,7 @@
|
||||
line-height: 1.5;
|
||||
}
|
||||
.wf-json.invalid {
|
||||
border-color: rgba(229, 72, 77, 0.65);
|
||||
border-color: var(--err-line);
|
||||
}
|
||||
.file-btn {
|
||||
display: inline-flex;
|
||||
@@ -2271,7 +2268,7 @@
|
||||
}
|
||||
.file-btn:hover {
|
||||
color: var(--text);
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.file-btn input {
|
||||
display: none;
|
||||
@@ -2302,13 +2299,10 @@
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.wf-kind.image {
|
||||
color: var(--info);
|
||||
background: var(--info-dim);
|
||||
}
|
||||
.wf-kind.image,
|
||||
.wf-kind.video {
|
||||
color: var(--accent);
|
||||
background: var(--accent-dim);
|
||||
color: var(--text-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
.wf-name {
|
||||
flex: 1;
|
||||
@@ -2460,14 +2454,14 @@
|
||||
}
|
||||
.f-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.f-input:disabled {
|
||||
color: var(--text-3);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.f-input.invalid {
|
||||
border-color: rgba(229, 72, 77, 0.65);
|
||||
border-color: var(--err-line);
|
||||
}
|
||||
.f-hint {
|
||||
display: block;
|
||||
@@ -2610,7 +2604,7 @@
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 790;
|
||||
background: rgba(5, 5, 8, 0.5);
|
||||
background: var(--overlay);
|
||||
}
|
||||
.wf-import-grid {
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
@@ -929,7 +929,7 @@
|
||||
transition: border-color 150ms cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
.card.failed {
|
||||
border-color: rgba(229, 72, 77, 0.35);
|
||||
border-color: color-mix(in srgb, var(--err) 35%, transparent);
|
||||
}
|
||||
.card-row {
|
||||
display: flex;
|
||||
@@ -946,7 +946,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--accent);
|
||||
color: var(--text-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.card-name {
|
||||
@@ -963,13 +963,10 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
.tag-local,
|
||||
.tag-lan {
|
||||
color: var(--info);
|
||||
background: var(--info-dim);
|
||||
}
|
||||
.tag-lan,
|
||||
.tag-cloud {
|
||||
color: var(--cloud);
|
||||
background: var(--cloud-dim);
|
||||
color: var(--text-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
.tag-default {
|
||||
color: var(--accent);
|
||||
@@ -1010,8 +1007,8 @@
|
||||
background: var(--text-3);
|
||||
}
|
||||
.dot.amber {
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 10px var(--accent-glow);
|
||||
background: var(--run);
|
||||
box-shadow: 0 0 10px var(--run-soft);
|
||||
}
|
||||
.dot.breathing {
|
||||
animation: breathe 2s ease-in-out infinite;
|
||||
@@ -1036,7 +1033,7 @@
|
||||
color: var(--error);
|
||||
}
|
||||
.status-text.amber {
|
||||
color: var(--accent);
|
||||
color: var(--run);
|
||||
}
|
||||
.status-text.gray {
|
||||
color: var(--text-3);
|
||||
@@ -1179,7 +1176,7 @@
|
||||
color: var(--text);
|
||||
}
|
||||
.avatar.dark {
|
||||
color: #16130a;
|
||||
color: var(--accent-ink);
|
||||
}
|
||||
.agent-name {
|
||||
font-size: 12.5px;
|
||||
@@ -1282,14 +1279,14 @@
|
||||
}
|
||||
.f-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.f-input:disabled {
|
||||
color: var(--text-3);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.f-input.invalid {
|
||||
border-color: rgba(229, 72, 77, 0.65);
|
||||
border-color: var(--err-line);
|
||||
}
|
||||
.f-hint {
|
||||
display: block;
|
||||
@@ -1433,7 +1430,7 @@
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 790;
|
||||
background: rgba(5, 5, 8, 0.5);
|
||||
background: var(--overlay);
|
||||
}
|
||||
.agents-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
|
||||
@@ -669,7 +669,7 @@
|
||||
color: var(--text-2);
|
||||
}
|
||||
.note.warn :global(.icon) {
|
||||
color: var(--accent);
|
||||
color: var(--warn);
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
min-height: 56px;
|
||||
}
|
||||
.trow.failed {
|
||||
border-color: rgba(229, 72, 77, 0.35);
|
||||
border-color: color-mix(in srgb, var(--err) 35%, transparent);
|
||||
}
|
||||
|
||||
.tkind {
|
||||
@@ -324,13 +324,10 @@
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.tkind.image {
|
||||
color: var(--info);
|
||||
background: var(--info-dim);
|
||||
}
|
||||
.tkind.image,
|
||||
.tkind.video {
|
||||
color: var(--accent);
|
||||
background: var(--accent-dim);
|
||||
color: var(--text-2);
|
||||
background: var(--bg-4);
|
||||
}
|
||||
|
||||
.tthumb {
|
||||
@@ -412,7 +409,7 @@
|
||||
color: var(--success);
|
||||
}
|
||||
.tst.run {
|
||||
color: var(--accent);
|
||||
color: var(--run);
|
||||
}
|
||||
.tst.queue {
|
||||
color: var(--text-3);
|
||||
|
||||
@@ -670,10 +670,13 @@
|
||||
color: var(--text-2);
|
||||
background: var(--surface-3);
|
||||
}
|
||||
.st-running,
|
||||
.st-running {
|
||||
color: var(--run);
|
||||
background: var(--run-soft);
|
||||
}
|
||||
.st-draft {
|
||||
color: var(--accent);
|
||||
background: var(--accent-dim);
|
||||
color: var(--warn);
|
||||
background: var(--warn-soft);
|
||||
}
|
||||
.st-confirmed {
|
||||
color: var(--success);
|
||||
@@ -684,8 +687,8 @@
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--info);
|
||||
background: var(--info-dim);
|
||||
color: var(--warn);
|
||||
background: var(--warn-soft);
|
||||
}
|
||||
|
||||
.error-banner {
|
||||
@@ -695,7 +698,7 @@
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
background: var(--error-dim);
|
||||
border: 1px solid rgba(229, 72, 77, 0.35);
|
||||
border: 1px solid color-mix(in srgb, var(--err) 35%, transparent);
|
||||
color: var(--error);
|
||||
font-size: 12.5px;
|
||||
line-height: 1.6;
|
||||
@@ -706,9 +709,9 @@
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid rgba(232, 163, 61, 0.3);
|
||||
color: var(--accent);
|
||||
background: var(--warn-soft);
|
||||
border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent);
|
||||
color: var(--warn);
|
||||
font-size: 12.5px;
|
||||
}
|
||||
.running-banner {
|
||||
@@ -766,7 +769,7 @@
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #edeef0;
|
||||
color: var(--text);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.agent-copy {
|
||||
@@ -833,13 +836,10 @@
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.kind-image {
|
||||
background: var(--info-dim);
|
||||
color: var(--info);
|
||||
}
|
||||
.kind-image,
|
||||
.kind-video {
|
||||
background: var(--cloud-dim);
|
||||
color: var(--cloud);
|
||||
background: var(--bg-4);
|
||||
color: var(--text-2);
|
||||
}
|
||||
.job-body {
|
||||
display: flex;
|
||||
@@ -872,7 +872,7 @@
|
||||
color: var(--success);
|
||||
}
|
||||
.job-state.st-running {
|
||||
color: var(--accent);
|
||||
color: var(--run);
|
||||
}
|
||||
.job-state.st-pending {
|
||||
color: var(--text-2);
|
||||
@@ -904,9 +904,11 @@
|
||||
.flow-dot.st-confirmed {
|
||||
background: var(--success);
|
||||
}
|
||||
.flow-dot.st-running,
|
||||
.flow-dot.st-running {
|
||||
background: var(--run);
|
||||
}
|
||||
.flow-dot.st-awaiting_confirm {
|
||||
background: var(--accent);
|
||||
background: var(--warn);
|
||||
}
|
||||
.flow-name {
|
||||
font-size: 12px;
|
||||
@@ -953,7 +955,7 @@
|
||||
}
|
||||
.wb-input:focus {
|
||||
outline: none;
|
||||
border-color: rgba(232, 163, 61, 0.6);
|
||||
border-color: var(--accent-line);
|
||||
}
|
||||
.wb-input::placeholder {
|
||||
color: var(--text-3);
|
||||
@@ -990,7 +992,7 @@
|
||||
}
|
||||
.btn.ghost:hover:not(:disabled) {
|
||||
color: var(--text);
|
||||
border-color: rgba(255, 255, 255, 0.24);
|
||||
border-color: var(--line-2);
|
||||
}
|
||||
.btn.sm {
|
||||
padding: 6px 11px;
|
||||
@@ -1024,7 +1026,7 @@
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
background: var(--run);
|
||||
animation: wb-page-breath 2s cubic-bezier(0.16, 1, 0.3, 1) infinite;
|
||||
}
|
||||
.breath.big {
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
// Colors and radii resolve to the design tokens in src/routes/app.css so the
|
||||
// Tailwind palette can never drift from the single source of truth.
|
||||
module.exports = {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#0a0a0c',
|
||||
surface: '#141418',
|
||||
elevated: '#1e1e24',
|
||||
border: '#2a2a32',
|
||||
muted: '#71717a',
|
||||
accent: '#8b5cf6',
|
||||
'accent-hover': '#7c3aed',
|
||||
primary: 'var(--bg)',
|
||||
surface: 'var(--bg-2)',
|
||||
elevated: 'var(--bg-3)',
|
||||
border: 'var(--line)',
|
||||
muted: 'var(--text-3)',
|
||||
accent: 'var(--accent)',
|
||||
'accent-hover': 'var(--accent-hi)',
|
||||
ok: 'var(--ok)',
|
||||
run: 'var(--run)',
|
||||
err: 'var(--err)',
|
||||
warn: 'var(--warn)',
|
||||
},
|
||||
borderRadius: {
|
||||
sm: '6px',
|
||||
md: '10px',
|
||||
lg: '16px',
|
||||
sm: 'var(--r-sm)',
|
||||
md: 'var(--r-md)',
|
||||
lg: 'var(--r-lg)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user