/* ============================================================
   dsforge Design Tokens —— 界面视觉系统的唯一来源
   规则：所有颜色、间距、圆角、阴影必须来自本文件的 token，
   组件层禁止出现字面量色值。这条规则同时也是 dsforge 生成
   的提示词里对 AI 的强制约束，此处即为自举样例。
   ============================================================ */

:root {
  color-scheme: light dark;

  /* 排版 */
  /* 界面有中 / 英 / 日三种语言，所以简中与日文的字体都得在链上。
     Hiragino Sans GB 是中文字体（GB），日文要的是 Hiragino Sans。 */
  --font-sans: "Inter", "Inter Tight", -apple-system, BlinkMacSystemFont,
    "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
    "Noto Sans SC", "Hiragino Sans", "Yu Gothic UI", "Meiryo",
    "Noto Sans JP", sans-serif;
  /* 拉丁等宽字体一个都不含 CJK 字形，中日文会掉进浏览器自己的兜底。
     实测（Chrome / Windows 11）：不写回退时中文落在 NSimSun，一个衬线体，
     混在无衬线等宽的代码块里字形和字重都对不上——这就是要修的那个问题。
     CJK 表意文字在几乎所有字体里都是整 1em，所以问题不在宽度，在字形。

     顺序按「在代码块里好不好看」排，每一组只在对应系统上存在，不会互相抢：
       1 Sarasa Mono / Noto Sans Mono CJK  真正的 CJK 等宽，装了就是最佳解
       2 PingFang / Hiragino               macOS 自带黑体
       3 Microsoft YaHei / Yu Gothic UI    Windows 自带黑体（中 / 日）
       4 MS Gothic / NSimSun               更老 Windows 的兜底
     黑体必须全部排在宋体（NSimSun）之前：只要有一个宋体插在前面，
     没装 Sarasa 的机器就会一路落到它上面，把后面的雅黑整段跳过去。 */
  --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Mono",
    Menlo, Consolas, "Liberation Mono",
    "Sarasa Mono SC", "Sarasa Mono J", "Noto Sans Mono CJK SC",
    "Noto Sans Mono CJK JP", "PingFang SC", "Hiragino Sans",
    "Microsoft YaHei", "Yu Gothic UI", "MS Gothic", "NSimSun", monospace;

  --text-xs: 0.6875rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-lg: 1.125rem;
  --text-xl: 1.4rem;
  --text-2xl: 1.9rem;
  --text-3xl: 2.6rem;

  /* 4px 基准栅格 */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;
  --radius-full: 999px;

  --dur-fast: 120ms;
  --dur-base: 200ms;
  --dur-slow: 380ms;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  --maxw: 1240px;
}

/* ---------- 浅色（默认定义，任何颜色的唯一真源） ---------- */
:root {
  --bg: #f7f8fa;
  --bg-grid: rgba(15, 23, 42, 0.045);
  --surface: #ffffff;
  --surface-2: #f1f3f7;
  --surface-3: #e7eaf0;
  --border: #dfe3ea;
  --border-strong: #c6cbd6;
  --text: #10131a;
  --text-muted: #5d6577;
  --text-faint: #8d94a5;

  --accent: #3b5bfd;
  --accent-soft: rgba(59, 91, 253, 0.1);
  --accent-text: #2c46d6;

  --ok: #0f9d63;
  --ok-soft: rgba(15, 157, 99, 0.12);
  --warn: #b26a00;
  --warn-soft: rgba(178, 106, 0, 0.12);
  --danger: #cf2e3f;
  --danger-soft: rgba(207, 46, 63, 0.1);
  --violet: #7c4ddb;
  --violet-soft: rgba(124, 77, 219, 0.1);

  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-md: 0 4px 16px -4px rgba(15, 23, 42, 0.12);
  --shadow-lg: 0 18px 48px -12px rgba(15, 23, 42, 0.22);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #08090c;
    --bg-grid: rgba(255, 255, 255, 0.035);
    --surface: #0f1116;
    --surface-2: #15181f;
    --surface-3: #1c2029;
    --border: #23272f;
    --border-strong: #343a45;
    --text: #e9ebf1;
    --text-muted: #949cae;
    --text-faint: #6b7385;

    --accent: #6f8dff;
    --accent-soft: rgba(111, 141, 255, 0.14);
    --accent-text: #9db1ff;

    --ok: #3ecf8e;
    --ok-soft: rgba(62, 207, 142, 0.14);
    --warn: #f0a92c;
    --warn-soft: rgba(240, 169, 44, 0.14);
    --danger: #ff6b6b;
    --danger-soft: rgba(255, 107, 107, 0.14);
    --violet: #a98bfa;
    --violet-soft: rgba(169, 139, 250, 0.14);

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
    --shadow-md: 0 6px 20px -6px rgba(0, 0, 0, 0.6);
    --shadow-lg: 0 24px 60px -16px rgba(0, 0, 0, 0.72);
  }
}

:root[data-theme="dark"] {
  /* 显式深色时必须钉死 color-scheme：:root 上的 "light dark" 只对
     「跟随系统」有效，缺了这行会出现深色页面配浅色下拉框和滚动条。 */
  color-scheme: dark;

  --bg: #08090c;
  --bg-grid: rgba(255, 255, 255, 0.035);
  --surface: #0f1116;
  --surface-2: #15181f;
  --surface-3: #1c2029;
  --border: #23272f;
  --border-strong: #343a45;
  --text: #e9ebf1;
  --text-muted: #949cae;
  --text-faint: #6b7385;

  --accent: #6f8dff;
  --accent-soft: rgba(111, 141, 255, 0.14);
  --accent-text: #9db1ff;

  --ok: #3ecf8e;
  --ok-soft: rgba(62, 207, 142, 0.14);
  --warn: #f0a92c;
  --warn-soft: rgba(240, 169, 44, 0.14);
  --danger: #ff6b6b;
  --danger-soft: rgba(255, 107, 107, 0.14);
  --violet: #a98bfa;
  --violet-soft: rgba(169, 139, 250, 0.14);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 6px 20px -6px rgba(0, 0, 0, 0.6);
  --shadow-lg: 0 24px 60px -16px rgba(0, 0, 0, 0.72);
}

/* ---------------- Reset ---------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  margin: 0;
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 650;
}

p { margin: 0; }
[hidden] { display: none !important; }
img, svg { max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }

code, kbd, pre { font-family: var(--font-mono); font-size: 0.92em; }

a { color: var(--accent-text); text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

::selection { background: var(--accent-soft); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------- 通用原子件 ---------------- */
.mono { font-family: var(--font-mono); }
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge--ok { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 25%, transparent); }
.badge--warn { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 25%, transparent); }
.badge--danger { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 28%, transparent); }
.badge--accent { background: var(--accent-soft); color: var(--accent-text); border-color: color-mix(in srgb, var(--accent) 25%, transparent); }
.badge--neutral { background: var(--surface-2); color: var(--text-muted); border-color: var(--border); }
.badge--violet { background: var(--violet-soft); color: var(--violet); border-color: color-mix(in srgb, var(--violet) 25%, transparent); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 550;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}
.btn:hover { background: var(--surface-2); border-color: var(--border-strong); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.btn--primary:hover { background: color-mix(in srgb, var(--accent) 88%, #000); border-color: transparent; }
.btn--ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn--ghost:hover { background: var(--surface-2); color: var(--text); }
.btn--sm { padding: var(--space-1) var(--space-3); font-size: var(--text-xs); }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

/* 内联 SVG 默认按基线对齐：1em 高的盒子底边坐在基线上，中心落在基线上方
   0.5em，而文字的视觉中心（x-height 中点）只在基线上方约 0.26em——图标因此
   整体偏高约四分之一个字高。vertical-align: middle 把盒子中点对齐到
   「基线 + 半个 x-height」，正好是文字的视觉中心，不需要魔数偏移量。
   作为 flex 子项时该属性被忽略，那些位置本来就由 align-items 居中，无副作用。 */
.icon { width: 1em; height: 1em; flex: none; stroke-width: 2; vertical-align: middle; }

/* <i data-icon> 包裹层：hydrate() 会给它加上这个类。包裹层若保持行内布局，
   其行盒高度由 line-height 决定而不是图标高度，图标在里面仍会浮起来；
   改成 inline-flex 居中，让包裹层的高度就是图标的高度。 */
.icon-slot { display: inline-flex; align-items: center; justify-content: center; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* 显式浅色：系统为深色时，用户仍可强制浅色。
   token 用 :root 的默认值即可，这里只需要把 color-scheme 扳回来。 */
:root[data-theme="light"] {
  color-scheme: light;
}
