/* * 设计基调。 * * 三条规则,其余都是它们的推论: * 1. 层次靠底色深浅和一像素描边,不靠投影 * 2. 不要卡片套卡片。一屏最多两层容器,再深就换成分割线 * 3. 信息密度偏低。行高、间距给足,宁可多滚动也不要挤 * * 颜色只留一个强调色,用在「当前选中」和「主要操作」上。状态色(成功/警告/危险) * 只在真的表示状态时用,不拿来装饰。 * * 唯一的例外是链式代理那一组色(--c-chain-*)。同一屏上有两种「当前选中」——流量最后 * 从哪出去,和流量先经过哪——它们必须一眼分得开,这是含义不是装饰。挑靛蓝是因为它在 * 这套色板里不表示任何状态,红绿琥珀都被状态占了。别把它当成通用的第二强调色。 */ :root { /* 中性色阶。带一点点冷调,避免纯灰的死板 */ --c-bg: #fbfbfc; --c-surface: #ffffff; --c-surface-sunken: #f4f5f7; --c-border: #e4e6ea; --c-border-strong: #d0d3d9; --c-text: #1c1e21; --c-text-soft: #5c6169; --c-text-faint: #8b9098; /* 强调色:偏青的蓝,冷静,不抢戏 */ --c-accent: #2b7a78; --c-accent-soft: #e6f2f1; --c-accent-text: #1f5c5a; /* 链式代理的「当前选中」。靛蓝,和强调色的青绿色相拉得够开 */ --c-chain: #5145cd; --c-chain-soft: #eeedfb; --c-chain-text: #4038a8; --c-danger: #b3261e; --c-danger-soft: #fdedec; --c-warn: #8a6100; --c-warn-soft: #fdf5e3; --c-ok: #1f6b3a; --c-ok-soft: #e9f5ed; /* 间距。低密度的来源,别调小 */ --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px; --s-6: 32px; --s-7: 48px; --r-sm: 6px; --r-md: 10px; --r-lg: 14px; --f-sans: system-ui, -apple-system, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', sans-serif; --f-mono: ui-monospace, 'Cascadia Code', 'JetBrains Mono', Consolas, monospace; --t-xs: 12px; --t-sm: 13px; --t-base: 14px; --t-lg: 16px; --t-xl: 20px; --t-2xl: 26px; --line: 1.7; } /* * 显式选择的主题(web/prefs.ts 在 上写 data-theme)。两个方向都要写: * 深色系统上选浅色也要生效。选择器权重高于 :root 和上面媒体查询里的 :root, * 显式选择压过系统偏好;不标 data-theme 时这两块不命中,媒体查询说了算。 * 只覆盖颜色变量,间距、字号与主题无关。 */ :root[data-theme='light'] { /* 变量之外还要告诉浏览器本身:滚动条、select 弹层这些 UA 部件不看变量,只看 color-scheme */ color-scheme: light; --c-bg: #fbfbfc; --c-surface: #ffffff; --c-surface-sunken: #f4f5f7; --c-border: #e4e6ea; --c-border-strong: #d0d3d9; --c-text: #1c1e21; --c-text-soft: #5c6169; --c-text-faint: #8b9098; --c-accent: #2b7a78; --c-accent-soft: #e6f2f1; --c-accent-text: #1f5c5a; --c-chain: #5145cd; --c-chain-soft: #eeedfb; --c-chain-text: #4038a8; --c-danger: #b3261e; --c-danger-soft: #fdedec; --c-warn: #8a6100; --c-warn-soft: #fdf5e3; --c-ok: #1f6b3a; --c-ok-soft: #e9f5ed; } :root[data-theme='dark'] { color-scheme: dark; --c-bg: #16181c; --c-surface: #1d2025; --c-surface-sunken: #121417; --c-border: #2b2f36; --c-border-strong: #3a3f48; --c-text: #e6e8eb; --c-text-soft: #9ba1a9; --c-text-faint: #6c727a; --c-accent: #4db6ac; --c-accent-soft: #1b3330; --c-accent-text: #7fd4cb; --c-chain: #8b83f0; --c-chain-soft: #241f4a; --c-chain-text: #a9a2f7; --c-danger: #f2b8b5; --c-danger-soft: #3a1f1e; --c-warn: #e8c37a; --c-warn-soft: #33290f; --c-ok: #86d6a0; --c-ok-soft: #16301f; } @media (prefers-color-scheme: dark) { :root { --c-bg: #16181c; --c-surface: #1d2025; --c-surface-sunken: #121417; --c-border: #2b2f36; --c-border-strong: #3a3f48; --c-text: #e6e8eb; --c-text-soft: #9ba1a9; --c-text-faint: #6c727a; --c-accent: #4db6ac; --c-accent-soft: #1b3330; --c-accent-text: #7fd4cb; --c-chain: #8b83f0; --c-chain-soft: #241f4a; --c-chain-text: #a9a2f7; --c-danger: #f2b8b5; --c-danger-soft: #3a1f1e; --c-warn: #e8c37a; --c-warn-soft: #33290f; --c-ok: #86d6a0; --c-ok-soft: #16301f; } } *, *::before, *::after { box-sizing: border-box; } html, body, #app { height: 100%; } /* 页面高度跨过视口阈值时滚动条出现消失,内容会横向抖一下;把滚动条的位置常驻留出来 */ html { scrollbar-gutter: stable; } body { margin: 0; background: var(--c-bg); color: var(--c-text); font-family: var(--f-sans); font-size: var(--t-base); line-height: var(--line); -webkit-font-smoothing: antialiased; } h1, h2, h3, p, figure { margin: 0; } button, input, select, textarea { font: inherit; color: inherit; } code, kbd, .mono { font-family: var(--f-mono); font-size: 0.92em; } :focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; } /* 文本输入的焦点态统一为描边变色,不叠外圈(订阅选择器的形态)。按钮保留外圈,那是键盘可达性 */ input:focus-visible, select:focus-visible, textarea:focus-visible { outline: none; border-color: var(--c-accent); } /* 交互控件的颜色过渡。只过渡颜色类属性,不碰布局;时长以「感知得到但不等待」为准 */ button, input, select { transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease; } /* 对话框入场:快速淡入加一点上移。关闭不做动画,动效只留给打开的那一下 */ dialog[open] { animation: dialog-in 0.15s ease; } dialog[open]::backdrop { animation: backdrop-in 0.15s ease; } @keyframes dialog-in { from { opacity: 0; transform: translateY(6px); } } @keyframes backdrop-in { from { opacity: 0; } } ::selection { background: var(--c-accent-soft); color: var(--c-accent-text); }