/* ============================================================= 穿山甲 VPN · Pangolin VPN — Prototype Atoms design/prototype/atoms.css ------------------------------------------------------------- 本文件是「原型公用组件原子层」的唯一真相源(single source)。 canonical CSS 原子类,沉淀自 design/preview/*.html 组件规格、 web/usercenter/components/shared.tsx、web/website/src/styles/website.css 与 client/lib/widgets/*.dart 的交互态语义。 铁律(写/改本文件必守,对齐 design/CLAUDE.md §1): 1. 颜色 / 圆角 / 间距 / 字号 / 阴影 / 字体 一律走 var(--token) (token 定义在 tokens.css)。禁任何硬编码 hex / rgb / 魔法数。 2. 明暗双主题「自动」适配:原子类只引语义 token(--surface / --fg1 …), 主题切换由 tokens.css 的 [data-theme="dark"] 负责—— 本文件里不写任何 [data-theme] 分支。 3. 暖大地色 · 大圆角(按钮全胶囊 radius-full / 卡片 lg–xl / 输入 md)· 柔和暖阴影 · 状态用「色点 + 文字胶囊」非 emoji。 4. 交互态语义:hover 主色加深一档 · press 缩放 .97 · focus clay 光环 (shadow-focus)· disabled sand-200 底 + sand-400 字。 5. 每新增一个原子,须在 design/prototype/index.html 登记(登记簿单源)。 使用前先在页面 引入:tokens.css(令牌)+ 本文件(原子)。 ============================================================= */ /* ============================================================= BUTTONS · .btn + variants 全胶囊圆角 · hover 加深 · press 收缩 .97 · focus clay 光环 变体:.btn-primary(实心 clay) · .btn-ghost(描边/幽灵) · .btn-subtle(次要描边) · .btn-danger · 尺寸 .btn-lg · .btn-icon ============================================================= */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); font-family: var(--font-sans); font-weight: 600; font-size: var(--text-sm); line-height: 1; border: none; border-radius: var(--radius-full); padding: var(--space-3) var(--space-5); cursor: pointer; white-space: nowrap; transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); } .btn > svg { width: 16px; height: 16px; flex-shrink: 0; } .btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); } .btn:active { transform: scale(0.97); } .btn:disabled, .btn.is-disabled { background: var(--sand-200); color: var(--sand-400); cursor: not-allowed; transform: none; box-shadow: none; border-color: transparent; } /* Primary — 实心黏土铜 */ .btn-primary { background: var(--accent); color: var(--fg-on-accent); } .btn-primary:hover { background: var(--accent-hover); } .btn-primary:active { background: var(--accent-press); } /* Ghost — 透明底、clay 字,hover 上 accent-subtle */ .btn-ghost { background: transparent; color: var(--accent); } .btn-ghost:hover { background: var(--accent-subtle); } /* Subtle — surface 底 + 强描边(次要动作) */ .btn-subtle { background: var(--surface); color: var(--fg1); border: 1.5px solid var(--border-strong); } .btn-subtle:hover { border-color: var(--accent); color: var(--accent); } /* Danger — 危险动作(断开 / 移除设备)。文字用语义 --danger(对齐线上 c.danger,随主题翻色) */ .btn-danger { background: var(--danger-subtle); color: var(--danger); } .btn-danger:hover { background: var(--danger); color: var(--fg-on-accent); } /* 尺寸 / 形态修饰 */ .btn-lg { padding: var(--space-4) var(--space-6); font-size: var(--text-body); } .btn-icon { padding: var(--space-3); } /* 正方形图标按钮(配 radius-full 成圆) */ .btn-block { width: 100%; } /* ============================================================= VIEW BODY · .view-body (+ .is-wide) 桌面客户端内容视图统一宽度容器 —— 对齐 Flutter PageBody(client/lib/widgets/page_body.dart)。 默认 600px 居中(单栏内容页:账户/设置/联系我们/统计/订单/通知/邀请); .is-wide 840px(多列网格页:购买套餐)。宽度标量本身无对应 token,字面写死属正常。 ============================================================= */ .view-body{ max-width:600px; margin:0 auto; padding:var(--space-5) var(--space-6) var(--space-6); } .view-body.is-wide{ max-width:840px; } /* ============================================================= CARD · .card surface 底 + border + radius-lg + shadow-sm 圆角对齐线上 cardTheme(PangolinRadius.lg=14);阴影保留 shadow-sm(暖阴影铁律)。 ============================================================= */ .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: var(--space-5); } .card-flush { padding: 0; } /* 列表容器(server-row 组)用,内容自带 padding */ /* ============================================================= INPUT · .input (+ .field / .flabel) 强描边 + radius-md + focus clay 光环 ============================================================= */ .field { display: block; } .flabel { display: block; font-family: var(--font-sans); font-size: var(--text-caption); font-weight: 600; color: var(--fg2); margin-bottom: var(--space-2); } .input { width: 100%; box-sizing: border-box; font-family: var(--font-sans); font-size: var(--text-sm); color: var(--fg1); background: var(--surface); border: 1.5px solid var(--border-strong); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); } .input::placeholder { color: var(--fg3); } .input:focus, .input.is-focused { outline: none; border-color: var(--accent); box-shadow: var(--shadow-focus); } .input:disabled { background: var(--bg-subtle); color: var(--fg3); cursor: not-allowed; } .input.is-error { border-color: var(--danger); } .input.is-error:focus { box-shadow: 0 0 0 4px var(--danger-subtle); } /* ============================================================= BADGE / PILL · .pill (+ status modifiers) 状态胶囊:色点 + 文字(非 emoji)。全胶囊圆角。 状态:.is-success / .is-warning / .is-danger / .is-neutral 变体:.pill-accent(实心 clay,如 PRO) · .pill-outline(accent 描边,如节点属性) ============================================================= */ .pill { display: inline-flex; align-items: center; gap: var(--space-2); font-family: var(--font-sans); font-size: var(--text-caption); font-weight: 600; line-height: 1; padding: var(--space-2) var(--space-3); border-radius: var(--radius-full); background: var(--bg-subtle); color: var(--fg2); } .pill .dot { width: 7px; height: 7px; border-radius: var(--radius-full); background: var(--fg3); flex-shrink: 0; } /* alias:.badge === .pill(语义等价,命名习惯不同) */ .badge { } /* 状态色对齐线上 status_pill.dart:文字用语义档 --success/--warning/--danger(非 -600 深档), neutral 用 --bg-subtle/--fg3(原 sand-100/sand-400 硬编码在深色不翻色,已修)。 */ .pill.is-success { background: var(--success-subtle); color: var(--success); } .pill.is-success .dot { background: var(--success); } .pill.is-warning { background: var(--warning-subtle); color: var(--warning); } .pill.is-warning .dot { background: var(--warning); } .pill.is-danger { background: var(--danger-subtle); color: var(--danger); } .pill.is-danger .dot { background: var(--danger); } .pill.is-neutral { background: var(--bg-subtle); color: var(--fg2); } .pill.is-neutral .dot { background: var(--fg3); } /* 实心 accent(PRO 会员等强调标签) */ .pill-accent { background: var(--accent); color: var(--fg-on-accent); } /* accent 描边(节点属性:流媒体 / P2P 等) */ .pill-outline { background: var(--accent-subtle); color: var(--accent); border: 1px solid var(--accent-border); } /* ============================================================= LANGUAGE SELECT · .langsel (触发药丸) + .menu (绝对定位菜单) 对齐 usercenter shared.tsx::LangSeg / website 的自定义下拉: 不依赖原生