/* ===============
   Hao AI - 全局样式定义
   ========================== */

/* 字体导入 — 拉丁字体轻量，中文回退到系统宋体/黑体 */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400&family=JetBrains+Mono:wght@400;500;600&display=swap');

/* 根元素变量定义 - 统一命名规范 */
:root {
    /* 颜色系统 - 使用 --color-* 前缀 */
    /* 默认主题为极简白 */
    --color-primary: #2d2d2d;
    --color-accent-blue: #1677ff;
    --color-accent-blue-dark: #0958d9;
    --color-accent-blue-rgb: 22, 119, 255;
    --color-primary-light: #555555;
    --color-primary-dark: #1a1a1a;
    --color-primary-rgb: 45, 45, 45;

    --color-success: #22c55e;
    --color-success-light: #4ade80;
    --color-success-rgb: 34, 197, 94;

    --color-error: #ef4444;
    --color-error-light: #f87171;
    --color-error-rgb: 239, 68, 68;
    /* 错误“文字”专用色：#ef4444 当正文只有 3.76:1 → 文字用这个
       #dc2626 在白底 4.83:1 但在灰底/淡红底只有 ~3.9 → 再加深到 #b91c1c（白底 6.47:1，灰底 5.68:1）
       边框/底色继续用 --color-error */
    --color-error-text: #b91c1c;

    --color-warning: #f59e0b;
    --color-warning-rgb: 245, 158, 11;

    --color-bg-main: #f5f5f5;
    --color-bg-secondary: #ffffff;
    --color-bg-tertiary: #f0f0f0;

    --color-text-primary: #1f1f1f;
    --color-text-secondary: #666666;
    /* 弱文字：原 #999 在浅底只有 2.85:1、灰底 2.50:1，不达 AA → #767676（4.54:1） */
    --color-text-muted: #767676;

    --color-border: rgba(0, 0, 0, 0.06);
    --color-border-light: rgba(0, 0, 0, 0.12);

    /* 尺寸系统 - 使用 --radius-* 前缀 */
    --radius-sm: 6px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-xl: 20px;
    --radius-pill: 999px;

    /* 间距系统 - 使用 --space-* 前缀（4px 基线；2xs/s/ms 为补齐的细分档） */
    --space-2xs: 2px;
    --space-xs: 4px;
    --space-s: 6px;
    --space-sm: 8px;
    --space-ms: 12px;
    --space-md: 16px;
    --space-lg: 24px;
    --space-xl: 32px;
    --space-2xl: 48px;

    /* 字号刻度（产品内页；AI_DESIGN_REFERENCE 里的「正文 14px」= --font-size-md） */
    --font-size-xs: 11px;
    --font-size-sm: 12px;
    --font-size-base: 13px;
    --font-size-md: 14px;
    --font-size-lg: 16px;

    /* 层级刻度（禁止随手写 9999） */
    --z-hint: 20;
    --z-dropdown: 1000;
    /* 弹出层（自定义下拉菜单）：必须盖住弹窗 1001、侧边栏 2000、画布浮层 2002，
       但低于全屏浮层（图片/视频预览、流式输出）10000+ */
    --z-popup: 9999;
    --z-overlay: 10000;
    --z-toast: 11000;

    /* 阴影系统 - 使用 --shadow-* 前缀 */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.1);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.06), 0 2px 4px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
    --scrollbar-thumb: rgba(45, 45, 45, 0.2);
    --scrollbar-thumb-hover: rgba(45, 45, 45, 0.4);
    --sidebar-bg: #ffffff;
    --input-bg: #ffffff;
    --card-bg: #ffffff;
    --hover-bg: rgba(0, 0, 0, 0.04);
    --card-gradient-from: #d9d9d9;
    --card-gradient-to: #bfbfbf;

    /* 移动端安全区与底部栏 */
    --safe-area-bottom: env(safe-area-inset-bottom, 0px);
    --safe-area-top: env(safe-area-inset-top, 0px);
    --bottom-bar-height: 56px;

    /* 动画系统 - 使用 --duration-* 和 --easing-* 前缀 */
    --duration-fast: 0.15s;
    --duration-base: 0.25s;
    --duration-slow: 0.35s;
    --easing-standard: ease;
    --easing-out: ease-out;

    /* 字体系统 - 使用 --font-* 前缀 */
    --font-display: 'Playfair Display', 'Noto Serif CJK SC', 'Source Han Serif SC', '思源宋体', 'Songti SC', 'SimSun', Georgia, serif;
    --font-body: 'Inter', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', 'Source Han Sans SC', -apple-system, sans-serif;
    --font-mono: 'JetBrains Mono', 'Monaco', 'Courier New', monospace;
    --font-weight-normal: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;

    /* 兼容旧变量名（逐步废弃） */
    --primary-color: var(--color-primary);
    --bg-main: var(--color-bg-main);
    --bg-secondary: var(--color-bg-secondary);
    --bg-tertiary: var(--color-bg-tertiary);
    --text-primary: var(--color-text-primary);
    --text-secondary: var(--color-text-secondary);
    --text-muted: var(--color-text-muted);
    --border-color: var(--color-border);
    --spacing-xs: var(--space-xs);
    --spacing-sm: var(--space-sm);
    --spacing-md: var(--space-md);
    --spacing-lg: var(--space-lg);
    --spacing-xl: var(--space-xl);
    --spacing-2xl: var(--space-2xl);
    --transition-fast: var(--duration-fast) var(--easing-standard);
    --transition-base: var(--duration-base) var(--easing-standard);
    --transition-slow: var(--duration-slow) var(--easing-out);
    --font-family: var(--font-body);
}

/* ===========================================
   主题系统 - 通过 data-theme 属性切换
   使用方式: <html data-theme="light">
   =========================================== */

/* 护眼（中性暗灰 · 夜间模式） */
[data-theme="dark"] {
    --color-primary: #b9bdc4;
    --color-primary-light: #d5d9df;
    --color-primary-dark: #676d76;
    --color-primary-rgb: 185, 189, 196;
    --color-accent-blue: #8aa4bf;
    --color-accent-blue-dark: #6b84a0;
    --color-accent-blue-rgb: 138, 164, 191;
    --color-bg-main: #212121;
    --color-bg-secondary: #272727;
    --color-bg-tertiary: #303030;
    --color-text-primary: #e6e6e6;
    --color-text-secondary: #b8b8b8;
    /* 原 #8c8c8c 在 #272727 上只有 4.44:1 → #9a9a9a（5.31:1） */
    --color-text-muted: #9a9a9a;
    --color-error-text: #f87171;
    --color-border: rgba(255, 255, 255, 0.08);
    --color-border-light: rgba(255, 255, 255, 0.14);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 6px 16px rgba(0, 0, 0, 0.4);
    --shadow-lg: 0 14px 36px rgba(0, 0, 0, 0.5);
    --scrollbar-thumb: rgba(255, 255, 255, 0.2);
    --scrollbar-thumb-hover: rgba(255, 255, 255, 0.35);
    --sidebar-bg: #262626;
    --input-bg: #2e2e2e;
    --card-bg: #2a2a2a;
    --hover-bg: rgba(255, 255, 255, 0.06);
    --card-gradient-from: #6f6f6f;
    --card-gradient-to: #4a4a4a;
}

/* 白天（极简白 · 默认）*/
[data-theme="light"] {
    --color-primary: #2d2d2d;
    --color-primary-light: #555555;
    --color-primary-dark: #1a1a1a;
    --color-primary-rgb: 45, 45, 45;
    --color-accent-blue: #1677ff;
    --color-accent-blue-dark: #0958d9;
    --color-accent-blue-rgb: 22, 119, 255;
    --color-bg-main: #f5f5f5;
    --color-bg-secondary: #ffffff;
    --color-bg-tertiary: #f0f0f0;
    --color-text-primary: #1f1f1f;
    --color-text-secondary: #666666;
    --color-text-muted: #767676;
    --color-error-text: #b91c1c;
    --color-border: rgba(0, 0, 0, 0.06);
    --color-border-light: rgba(0, 0, 0, 0.12);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.1);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.06), 0 2px 4px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
    --scrollbar-thumb: rgba(22, 119, 255, 0.2);
    --scrollbar-thumb-hover: rgba(22, 119, 255, 0.4);
    --sidebar-bg: #ffffff;
    --input-bg: #ffffff;
    --card-bg: #ffffff;
    --hover-bg: rgba(0, 0, 0, 0.04);
    --card-gradient-from: #d9d9d9;
    --card-gradient-to: #bfbfbf;
}

/* ── 移动端全局基础 ── */
@media (max-width: 768px) {
    html {
        height: -webkit-fill-available;
    }
    body {
        min-height: 100dvh;
        min-height: -webkit-fill-available;
        -webkit-tap-highlight-color: transparent;
        -webkit-overflow-scrolling: touch;
    }
}

/* 重置基础样式 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
}

body {
    background-color: var(--color-bg-main);
    color: var(--color-text-primary);
    font-family: var(--font-body);
    font-size: 14px;
    line-height: 1.6;
    overflow: hidden;
}

/* 滚动条美化 */
::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--scrollbar-thumb-hover);
}

/* 标题 */
h1 {
    font-family: var(--font-display);
    font-size: 72px;
    font-weight: 700;
    letter-spacing: -2px;
}

h2 {
    font-family: var(--font-display);
    font-size: 36px;
    font-weight: 700;
}

h3 {
    font-family: var(--font-display);
    font-size: 24px;
    font-weight: 600;
}

h4 {
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
    letter-spacing: 0.3px;
}

/* 链接 */
a {
    color: var(--color-primary);
    text-decoration: none;
    transition: var(--transition-fast);
}

a:hover {
    opacity: 0.7;
}

/* 按钮基础 */
button {
    font-family: inherit;
    cursor: pointer;
    border: none;
    outline: none;
}

/* 键盘焦点环：上面把 button 的 outline 重置掉了，这里给键盘用户补回来。
   用 :where() 保持 0 特异性，不会覆盖任何组件自己的 focus 样式；:focus-visible 保证鼠标点击不出现光圈 */
:where(button, a, [tabindex]):focus-visible {
    outline: 2px solid var(--color-accent-blue);
    outline-offset: 2px;
}

/* 输入框基础 */
input,
textarea,
select {
    font-family: inherit;
    font-size: inherit;
    color: inherit;
}

/* 代码块 */
code {
    font-family: var(--font-mono);
    background: var(--card-bg);
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 0.9em;
}

pre {
    background: var(--card-bg);
  padding: var(--spacing-md);
    border-radius: var(--radius-md);
    overflow-x: auto;
    margin: var(--spacing-md) 0;
}

pre code {
    background: none;
    padding: 0;
}

/* 列表 */
ul, ol {
    margin-left: var(--spacing-lg);
}

/* 分隔线 */
hr {
    border: none;
  border-top: 1px solid var(--border-color);
    margin: var(--spacing-lg) 0;
}

/* 表格 */
table {
    width: 100%;
    border-collapse: collapse;
    margin: var(--spacing-md) 0;
}

th, td {
    padding: var(--spacing-md);
    text-align: left;
    border-bottom: 1px solid var(--border-color);
}

th {
    background: rgba(var(--color-primary-rgb), 0.05);
    font-weight: 600;
}

/* 禁用状态 */
:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* 文字选择 */
::selection {
    background: rgba(var(--color-primary-rgb), 0.3);
    color: var(--text-primary);
}

::-moz-selection {
    background: rgba(var(--color-primary-rgb), 0.3);
    color: var(--text-primary);
}

/* -- 全局角色管理样式 -- */
.character-management-content {
    display: flex;
    flex-direction: column;
    gap: 20px;
    max-height: 70vh;
}

.series-tabs {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--color-border);
}

.series-tab {
    padding: 10px 20px;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text-secondary);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
}

.series-tab:hover {
    color: var(--color-primary);
    border-color: var(--color-primary);
    background: rgba(var(--color-primary-rgb), 0.06);
}

.series-tab.active {
    color: var(--color-primary);
    border-color: var(--color-primary);
    background: rgba(var(--color-primary-rgb), 0.1);
    font-weight: 600;
}

.category-tabs {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--color-border);
}

.category-tab {
    padding: 8px 16px;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text-secondary);
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
}

.category-tab:hover {
    color: var(--color-primary);
    border-color: var(--color-primary);
    background: rgba(var(--color-primary-rgb), 0.06);
}

.category-tab.active {
    color: var(--color-primary);
    border-color: var(--color-primary);
    background: rgba(var(--color-primary-rgb), 0.1);
    font-weight: 600;
}

#global-character-grid {
    flex: 1;
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 20px;
    padding: 4px;
}

#global-character-grid::-webkit-scrollbar {
    width: 6px;
}

#global-character-grid::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: 3px;
}

.category-count {
    margin-left: 4px;
    padding: 2px 6px;
    background: rgba(var(--color-primary-rgb), 0.2);
    border-radius: 4px;
    font-size: 11px;
    font-weight: 600;
}
.category-tab.active .category-count {
    background: rgba(255, 255, 255, 0.2);
}

/* ── Select 下拉选项样式 ── */
select option {
    background: var(--color-bg-secondary);
    color: var(--color-text-primary);
    padding: 4px 8px;
}

select option:checked {
    background: rgba(var(--color-primary-rgb), 0.15);
    color: var(--color-primary);
    font-weight: 600;
}

select option:hover {
    background: rgba(var(--color-primary-rgb), 0.08);
}

/* 针对聊天栏 select 额外优化 */
.chat-select option,
.form-select option {
    font-size: 12px;
    padding: 6px 8px;
}

/* ==========================
   自定义下拉（js/ui-select.js，选项里可以带 SVG 图标）
   做法：原生 <select> 留在文档流里负责撑出宽高，自定义显示层绝对覆盖在上面，
   所以控件尺寸和改造前的原生下拉完全一致（不需要测量，弹窗/隐藏容器里也准）；
   视觉（底色/边框/圆角/字号/内边距）由 JS 从原生 select 克隆到 .ui-select-trigger。
   两种布局（由 JS 按原生当前的实际显示方式加 is-fitblock 类区分）：
   - 原生是 flex/grid 项（被块级化）→ 外壳用网格，原生仍是网格项，尺寸口径不变
   - 原生是行内块（普通块级容器里的下拉）→ 外壳也行内块、行高归零，原生留在常规流里
     （select 的行高会跟“是否被块级化”差约 2px，两种布局分开才能和原生严格等高）
   想保留原生下拉的元素加 data-ui-select="0"。
   ========================== */
.ui-select {
    position: relative;
    display: grid;
}
.ui-select.is-fitblock {
    display: inline-block;
    line-height: 0;          /* 行盒不额外占高（原生 select 自己带行高，不受影响） */
}
.ui-select-native {
    opacity: 0;
    pointer-events: none;
    vertical-align: top;     /* 行内块布局时不要基线下方的空隙 */
}
.ui-select:not(.is-fitblock) > .ui-select-native {
    grid-area: 1 / 1;
}
/* 触发层绝对覆盖：不参与外层尺寸计算，尺寸完全由原生 select 决定 */
.ui-select-trigger {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    cursor: pointer;
    outline: none;
    text-align: left;
}
/* 文字层绝对定位：不参与网格尺寸计算，只画在触发按钮的内容区上 */
.ui-select-text {
    position: absolute;
    inset: 0;
    box-sizing: border-box;
    padding: inherit;
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    overflow: hidden;
}
.ui-select-text .ui-select-label {
    flex: 0 1 auto;
    min-width: 3em;      /* 窄下拉里先让名称留一截，别被积分标签挤没 */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* 积分标签：和模型名分开单独成一个胶囊，一眼看清消耗。
   配色沿用项目里既有的「消耗胶囊」（.bv-cost-text / .batch-type-cost），
   底色取警示色的淡底 + 常规文字色，保证对比度 */
.ui-select-cost {
    flex: 0 1 auto;
    min-width: 2.6em;     /* 窄下拉里留得住图标 + 个数字，不会挤成一块色饼 */
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    border: 1px solid rgba(var(--color-warning-rgb), 0.28);
    background: rgba(var(--color-warning-rgb), 0.15);
    color: var(--color-text-primary);
    font-size: 0.92em;
    font-weight: 600;
    line-height: 1.6;
    white-space: nowrap;
}
.ui-select-cost-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* 弹出列表里把积分标签推到最右，方便竖向扫读、长名称先省略 */
.ui-select-item .ui-select-cost {
    margin-left: auto;
}
.ui-select-caret {
    position: absolute;
    right: 6px;
    top: 50%;
    display: inline-flex;
    transform: translateY(-50%);
    pointer-events: none;
    opacity: 0.65;
    transition: transform 0.15s ease;
}
.ui-select-caret svg {
    width: 12px;
    height: 12px;
}
.ui-select.is-open .ui-select-caret {
    transform: translateY(-50%) rotate(180deg);
}
.ui-select-trigger:focus-visible {
    outline: 2px solid var(--color-accent-blue, var(--color-primary));
    outline-offset: 2px;
}
.ui-select.is-open .ui-select-trigger {
    border-color: var(--color-primary);
}
.ui-select.is-disabled {
    opacity: 0.5;
}
.ui-select.is-disabled .ui-select-trigger {
    cursor: not-allowed;
}
/* 弹层规格与项目既有的操作菜单（.chat-action-menu）保持一致。
   注意 z-index 用 --z-popup：菜单挂在 body 下，若沿用 --z-dropdown(1000) 会被
   弹窗（.modal 是 1001）盖住 —— 表现为“弹窗里的下拉点了没反应” */
.ui-select-menu {
    position: fixed;
    z-index: var(--z-popup);
    max-height: 280px;
    max-width: min(560px, 94vw);
    overflow-y: auto;
    overflow-x: hidden;
    padding: var(--space-xs);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-secondary);
    box-shadow: var(--shadow-lg);
}
/* 每项一行；宽度按最长文案自适应（实在放不下才省略号 + 悬停看全文） */
.ui-select-item {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    min-height: 28px;
    padding: var(--space-s) var(--space-sm);
    border-radius: var(--radius-sm);
    color: var(--color-text-primary);
    font-size: var(--font-size-sm);
    line-height: 1.4;
    white-space: nowrap;
    overflow: hidden;
    cursor: pointer;
}
.ui-select-item .ui-select-label {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* 供应商等次要信息用次文字色，和项目其它列表一致 */
.ui-select-provider {
    flex: none;
    color: var(--color-text-muted);
}
.ui-select-item:hover,
.ui-select-item:focus {
    background: var(--color-bg-tertiary);
    outline: none;
}
.ui-select-item.is-selected {
    color: var(--color-primary);
    font-weight: 600;
}
.ui-select-item.is-hint {
    color: var(--color-text-muted);
    cursor: default;
    justify-content: center;
}
.ui-select-item.is-hint:hover {
    background: transparent;
}
.ui-select-check {
    width: 14px;
    height: 14px;
    flex: none;
}

/* ===============
   媒体懒加载占位（配合 js/lazy-load.js）
   状态类由 JS 加在媒体元素的父容器上：is-loading / is-loaded / is-error
   ========================== */

/* 父容器原本没有定位时补上，供转圈/破图提示定位（由 JS 判断后添加，不会覆盖已有的绝对定位） */
.lazy-media-host--rel {
    position: relative;
}

/* 容器高度原本靠图片撑开（图片未加载时会塌陷成 0）→ 给个兜底高度，
   否则转圈会被 overflow:hidden 裁掉、看不见；加载完成后该 class 会被移除。 */
.lazy-media-host--seized {
    min-height: 88px;
}

/* 加载中：容器中央转圈 */
.lazy-media-host.is-loading::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 26px;
    height: 26px;
    margin: -13px 0 0 -13px;
    border: 2px solid var(--color-border-light);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    pointer-events: none;
    z-index: 2;
}

/* 加载中：隐藏替换元素自带的 alt 文本 */
.lazy-media-host.is-loading > img.lazy-media,
.lazy-media-host.is-loading > video.lazy-media {
    color: transparent;
}

/* 加载完成：图片淡入，避免生硬切换 */
.lazy-media-host.is-loaded > img.lazy-media {
    animation: fadeIn 0.25s ease;
}

/* 加载失败：覆盖破图提示，避免看起来"一直在加载" */
.lazy-media-host.is-error::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--color-bg-tertiary) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23999999' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='18' height='18' rx='2' ry='2'/%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'/%3E%3Cpolyline points='21 15 16 10 5 21'/%3E%3C/svg%3E") center / 22px 22px no-repeat;
    pointer-events: none;
    z-index: 2;
}

/* ===============
   UI 图标规范（所有界面图标都必须走这里，禁止使用 emoji 当图标）
   1. 图标 = 内联 SVG：<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" aria-hidden="true">…</svg>，颜色继承 currentColor（主题令牌），不要硬编码颜色
   2. .icon 跟随所处文字的字号（约 1em），所以同一份图标在标题/正文/按钮里都合适；
      需要更大时加 .icon-lg，语义色用 .is-primary / .is-success / .is-warning / .is-error
   3. 「进行中」用 .spinner（CSS 转圈），不要用 之类的字符
   4. 状态点用 .status-dot（小圆点 + 语义色），不要用 注意：这类字符
   5. <option> / textContent 等放不了 SVG 的地方只写纯中文文案（如「30 积分」）
   ========================== */
.icon {
    width: 0.95em;
    height: 0.95em;
    flex: none;
    vertical-align: -0.12em;
}
.icon-lg {
    width: 1.15em;
    height: 1.15em;
}
.icon.is-primary { color: var(--color-primary); }
.icon.is-success { color: var(--color-success); }
.icon.is-warning { color: var(--color-warning); }
.icon.is-error { color: var(--color-error); }
.icon.is-muted { color: var(--color-text-muted); }

/* 统一转圈：任何「加载中/处理中」都用它（.chat-inline-spinner 是聊天区的历史别名） */
.spinner,
.chat-inline-spinner {
    display: inline-block;
    width: 11px;
    height: 11px;
    margin-right: 6px;
    vertical-align: -1px;
    border: 2px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}
.spinner-lg {
    width: 18px;
    height: 18px;
}

/* 状态点：成功/警告/失败/进行中 用颜色区分，不要用 emoji */
.status-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    flex: none;
    border-radius: 50%;
    background: var(--color-text-muted);
}
.status-dot.is-primary { background: var(--color-primary); }
.status-dot.is-success { background: var(--color-success); }
.status-dot.is-warning { background: var(--color-warning); }
.status-dot.is-error { background: var(--color-error); }