- 动效基元:ai-dot 波动(三点竖跳)、ai-stream 不确定进度条、ai-breathe 呼吸微光(均带 reduced-motion 回退) - ThinkingIndicator 升级为明显波动;新增 Spinner / StreamingBar / GenerationSkeleton 原子件;Button 加 loading 态 - 写作台:首 token 前正文区『AI 正在构思本章…』占位(补最大缺口,不再空白像卡死)+ 流式顶部进度条 - 整章重写流式进度条;续写/润色忙碌骨架 + 触发键转圈;生成器/角色/世界观改用 Button loading
256 lines
6.1 KiB
CSS
256 lines
6.1 KiB
CSS
@tailwind base;
|
||
@tailwind components;
|
||
@tailwind utilities;
|
||
|
||
/* 纸感设计 token(UX_SPEC §2.1) */
|
||
:root,
|
||
[data-theme="paper"] {
|
||
/* 面色阶:底 → 分隔带 → 内容卡(比底暗一步)→ 选中强调 → 浮起面板 */
|
||
--color-bg: #f5f1e8;
|
||
--color-surface-soft: #efe9dc;
|
||
--color-surface-card: #ece4d3;
|
||
--color-surface-strong: #e4d9c4;
|
||
--color-panel: #fbf8f1;
|
||
/* 文字色阶(5 级):标题 → 强调段 → 正文 → 次级 → 说明/细则 */
|
||
--color-ink: #2b2620;
|
||
--color-body-strong: #3a342b;
|
||
--color-body: #4a4234;
|
||
--color-ink-soft: #6b6356;
|
||
/* muted-soft 达 WCAG AA 小字(≥4.5:1)于 bg/card/panel/soft 各面(P4-1)。 */
|
||
--color-muted-soft: #6f6556;
|
||
/* 边框:主边框 + 同带内更弱分隔 */
|
||
--color-line: #e5ddcd;
|
||
--color-line-soft: #ece4d5;
|
||
/* 朱砂 coral:主色 + 按压变深 + 奶油化禁用 + 淡底 */
|
||
--color-cinnabar: #a23b2e;
|
||
--color-cinnabar-active: #8a2f24;
|
||
--color-cinnabar-disabled: #d9cdbd;
|
||
--color-cinnabar-wash: #a23b2e14;
|
||
--color-conflict: #b5543a;
|
||
--color-overdue: #c8893a;
|
||
--color-pass: #5a6b4f;
|
||
--color-info: #4a5a6b;
|
||
--color-conflict-mark: #b5543a26;
|
||
--color-conflict-mark-strong: #b5543a8c;
|
||
/* 暖深色 callout:仅用于英雄/CTA 时刻(对标 DESIGN.md cta-band-dark),非内容底。 */
|
||
--color-callout: #201d18;
|
||
--color-on-callout: #f2ede2;
|
||
--color-on-callout-soft: #b8ae9c;
|
||
--shadow-paper: #2b26200f;
|
||
color-scheme: light;
|
||
}
|
||
|
||
/* 动效 token(与主题无关,单处定义;夜读模式不覆盖) */
|
||
:root {
|
||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||
--dur-fast: 120ms;
|
||
--dur-base: 180ms;
|
||
}
|
||
|
||
[data-theme="night"] {
|
||
/* 面色阶:底 → 分隔带 → 浮起面板 → 内容卡(暗面向上抬)→ 选中强调 */
|
||
--color-bg: #181614;
|
||
--color-surface-soft: #1e1b17;
|
||
--color-surface-card: #2a2620;
|
||
--color-surface-strong: #332e26;
|
||
--color-panel: #221f1b;
|
||
/* 文字色阶(5 级) */
|
||
--color-ink: #efe6d7;
|
||
--color-body-strong: #ddd2c0;
|
||
--color-body: #cdc0ab;
|
||
--color-ink-soft: #b9ab96;
|
||
/* muted-soft 达 AA 小字(≥4.5:1)于夜读 bg/card/soft 各面(P4-1)。 */
|
||
--color-muted-soft: #9a8e7c;
|
||
/* 边框 */
|
||
--color-line: #3c352c;
|
||
--color-line-soft: #2f2a23;
|
||
/* 朱砂 coral */
|
||
--color-cinnabar: #e07866;
|
||
--color-cinnabar-active: #c85f4d;
|
||
--color-cinnabar-disabled: #3c352c;
|
||
--color-cinnabar-wash: #e0786620;
|
||
--color-conflict: #ef8a72;
|
||
--color-overdue: #d8a65d;
|
||
--color-pass: #95b47d;
|
||
--color-info: #8ca8ca;
|
||
--color-conflict-mark: #ef8a7230;
|
||
--color-conflict-mark-strong: #ef8a7290;
|
||
/* 夜读下 callout 为更深的凹陷暖井,仍与 bg 拉开层次。 */
|
||
--color-callout: #100e0c;
|
||
--color-on-callout: #efe6d7;
|
||
--color-on-callout-soft: #a89d8a;
|
||
--shadow-paper: #00000045;
|
||
color-scheme: dark;
|
||
}
|
||
|
||
html {
|
||
background: var(--color-bg);
|
||
}
|
||
|
||
body {
|
||
background: var(--color-bg);
|
||
color: var(--color-ink);
|
||
}
|
||
|
||
::selection {
|
||
background: var(--color-cinnabar-wash);
|
||
color: var(--color-ink);
|
||
}
|
||
|
||
/* 流式打字机光标:朱砂闪烁;尊重 prefers-reduced-motion(UX §10)。 */
|
||
.typewriter-cursor {
|
||
animation: typewriter-blink 1s step-end infinite;
|
||
}
|
||
|
||
@keyframes typewriter-blink {
|
||
50% {
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
/* 冲突就地标注锚点:朱砂波浪下划线(UX §8.3)。 */
|
||
.conflict-anchor {
|
||
text-decoration: underline wavy var(--color-conflict);
|
||
text-underline-offset: 3px;
|
||
transition: background-color 0.15s ease;
|
||
}
|
||
|
||
/* 终稿正文:冲突原文持续高亮(朱砂淡底),点锚点定位时闪烁一下(UX §8.3)。 */
|
||
.draft-mark {
|
||
background-color: var(--color-conflict-mark);
|
||
border-radius: 2px;
|
||
}
|
||
.draft-mark-flash {
|
||
animation: draft-mark-flash 0.9s ease-out;
|
||
}
|
||
|
||
@keyframes draft-mark-flash {
|
||
0%,
|
||
100% {
|
||
background-color: var(--color-conflict-mark);
|
||
}
|
||
30% {
|
||
background-color: var(--color-conflict-mark-strong);
|
||
}
|
||
}
|
||
|
||
/* 主题切换图标:显隐由 data-theme 决定(而非 JS 状态),两个图标始终在 DOM 里,
|
||
服务端/客户端首帧结构一致——既避免水合不一致,又无首帧闪烁。 */
|
||
.theme-icon-moon {
|
||
display: inline-block;
|
||
}
|
||
.theme-icon-sun {
|
||
display: none;
|
||
}
|
||
[data-theme="night"] .theme-icon-moon {
|
||
display: none;
|
||
}
|
||
[data-theme="night"] .theme-icon-sun {
|
||
display: inline-block;
|
||
}
|
||
|
||
/* Toast 入场:淡入 + 轻微上移(尊重 prefers-reduced-motion,见下)。 */
|
||
.toast-enter {
|
||
animation: toast-in var(--dur-base) var(--ease-standard);
|
||
}
|
||
@keyframes toast-in {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(6px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
/* AI 工作中·三点波动(比 animate-pulse 更明显:竖向弹跳 + 亮度,供 ThinkingIndicator 用)。 */
|
||
.ai-dot {
|
||
animation: ai-dot 1.2s ease-in-out infinite;
|
||
}
|
||
@keyframes ai-dot {
|
||
0%,
|
||
80%,
|
||
100% {
|
||
transform: translateY(0);
|
||
opacity: 0.4;
|
||
}
|
||
40% {
|
||
transform: translateY(-3px);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
/* AI 流式/处理中·不确定进度条(细条来回扫,明确传达"正在工作")。 */
|
||
.ai-stream-track {
|
||
position: relative;
|
||
overflow: hidden;
|
||
background: var(--color-cinnabar-wash);
|
||
}
|
||
.ai-stream-track::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset-block: 0;
|
||
left: -40%;
|
||
width: 40%;
|
||
border-radius: 9999px;
|
||
background: var(--color-cinnabar);
|
||
animation: ai-stream 1.4s ease-in-out infinite;
|
||
}
|
||
@keyframes ai-stream {
|
||
0% {
|
||
left: -40%;
|
||
width: 35%;
|
||
}
|
||
50% {
|
||
width: 55%;
|
||
}
|
||
100% {
|
||
left: 100%;
|
||
width: 35%;
|
||
}
|
||
}
|
||
|
||
/* AI 构思中·占位微光(正文区首 token 前的呼吸感,比骨架更"活")。 */
|
||
.ai-breathe {
|
||
animation: ai-breathe 1.8s ease-in-out infinite;
|
||
}
|
||
@keyframes ai-breathe {
|
||
0%,
|
||
100% {
|
||
opacity: 0.55;
|
||
}
|
||
50% {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.ai-dot {
|
||
animation: none;
|
||
opacity: 0.85;
|
||
}
|
||
.ai-stream-track::after {
|
||
animation: none;
|
||
left: 0;
|
||
width: 100%;
|
||
opacity: 0.35;
|
||
}
|
||
.ai-breathe {
|
||
animation: none;
|
||
}
|
||
.typewriter-cursor {
|
||
animation: none;
|
||
}
|
||
.conflict-anchor {
|
||
transition: none;
|
||
}
|
||
.draft-mark-flash {
|
||
animation: none;
|
||
outline: 2px solid var(--color-conflict);
|
||
}
|
||
.toast-enter {
|
||
animation: none;
|
||
}
|
||
}
|