+
+
+
diff --git a/apps/kimi-web/src/components/mobile/MobileSwitcherSheet.vue b/apps/kimi-web/src/components/mobile/MobileSwitcherSheet.vue
index da5d73cbd..4a87b0cc0 100644
--- a/apps/kimi-web/src/components/mobile/MobileSwitcherSheet.vue
+++ b/apps/kimi-web/src/components/mobile/MobileSwitcherSheet.vue
@@ -394,7 +394,7 @@ async function onDeleteWorkspace(ws: WorkspaceView): Promise {
}
.mgh-name {
font-size: var(--ui-font-size-lg);
- font-weight: 500;
+ font-weight: 550;
color: var(--color-text);
overflow: hidden;
text-overflow: ellipsis;
@@ -402,6 +402,7 @@ async function onDeleteWorkspace(ws: WorkspaceView): Promise {
}
.mgh-path {
font-size: var(--text-base);
+ font-weight: 425;
color: var(--color-text-faint);
overflow: hidden;
text-overflow: ellipsis;
@@ -430,12 +431,14 @@ async function onDeleteWorkspace(ws: WorkspaceView): Promise {
.srow .m { flex: 1; min-width: 0; }
.srow .m .t {
font-size: var(--text-base);
+ font-weight: 450;
+ line-height: var(--leading-tight);
color: var(--color-text);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
-.srow.cur .m .t { font-weight: 500; color: var(--color-accent-hover); }
+.srow.cur .m .t { color: var(--color-accent-hover); }
/* Running indicator — pulse dot in the indent gutter left of the title,
mirroring the desktop SessionRow (.t.run::before). */
@@ -471,6 +474,8 @@ async function onDeleteWorkspace(ws: WorkspaceView): Promise {
}
.srow .m .s {
font-size: var(--text-base);
+ font-weight: 475;
+ font-variant-numeric: tabular-nums;
color: var(--color-text-faint);
margin-top: 1px;
overflow: hidden;
diff --git a/apps/kimi-web/src/components/ui/MenuItem.vue b/apps/kimi-web/src/components/ui/MenuItem.vue
index a44bb31d9..cc9cf0d69 100644
--- a/apps/kimi-web/src/components/ui/MenuItem.vue
+++ b/apps/kimi-web/src/components/ui/MenuItem.vue
@@ -38,9 +38,9 @@ defineEmits<{ click: [event: MouseEvent] }>();
border: none;
border-radius: var(--radius-sm);
background: transparent;
- color: var(--color-text-muted);
+ color: var(--color-text);
font-family: var(--font-ui);
- font-size: var(--text-sm);
+ font-size: var(--text-base);
text-align: left;
cursor: pointer;
transition: background var(--duration-base), color var(--duration-base);
diff --git a/apps/kimi-web/src/components/ui/ShortcutKey.vue b/apps/kimi-web/src/components/ui/ShortcutKey.vue
new file mode 100644
index 000000000..67c87a182
--- /dev/null
+++ b/apps/kimi-web/src/components/ui/ShortcutKey.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
diff --git a/apps/kimi-web/src/composables/useKimiWebClient.ts b/apps/kimi-web/src/composables/useKimiWebClient.ts
index 9b61944bb..0e2b7adf5 100644
--- a/apps/kimi-web/src/composables/useKimiWebClient.ts
+++ b/apps/kimi-web/src/composables/useKimiWebClient.ts
@@ -1380,7 +1380,7 @@ function formatTime(iso: string, _status: string): string {
const diffD = diffMs / 86400000;
if (diffD < 7) return `${Math.round(diffD)}d`;
if (diffD < 30) return `${Math.round(diffD / 7)}w`;
- if (diffD < 365) return `${Math.round(diffD / 30)}m`;
+ if (diffD < 365) return `${Math.round(diffD / 30)}mo`;
return `${Math.round(diffD / 365)}y`;
} catch {
return iso;
diff --git a/apps/kimi-web/src/i18n/locales/en/header.ts b/apps/kimi-web/src/i18n/locales/en/header.ts
index bf046bee4..4273de01d 100644
--- a/apps/kimi-web/src/i18n/locales/en/header.ts
+++ b/apps/kimi-web/src/i18n/locales/en/header.ts
@@ -10,6 +10,11 @@ export default {
gitTooltip: 'Open Files > Changed',
detached: 'detached',
openPr: 'Open pull request',
+ prStatusOpen: 'open',
+ prStatusClosed: 'closed',
+ prStatusMerged: 'merged',
+ prStatusDraft: 'draft',
+ prStatusUnknown: 'unknown',
options: 'Options',
copySessionId: 'Copy Session ID',
renameSession: 'Rename',
diff --git a/apps/kimi-web/src/i18n/locales/en/sidebar.ts b/apps/kimi-web/src/i18n/locales/en/sidebar.ts
index 3bb705ca3..70adc2e5e 100644
--- a/apps/kimi-web/src/i18n/locales/en/sidebar.ts
+++ b/apps/kimi-web/src/i18n/locales/en/sidebar.ts
@@ -31,9 +31,9 @@ export default {
language: 'Language',
daemon: 'Daemon',
noSessions: 'No conversations yet',
- showMore: 'Load more ({count})',
+ showMore: 'Load {count} more conversations',
showLess: 'Show less',
- showAll: 'Show all ({count})',
+ showAll: 'Show {count} more conversations',
loadingMore: 'Loading…',
collapseSidebar: 'Collapse sidebar',
expandSidebar: 'Expand sidebar',
diff --git a/apps/kimi-web/src/i18n/locales/en/status.ts b/apps/kimi-web/src/i18n/locales/en/status.ts
index fc4ca8cc4..8b7f02278 100644
--- a/apps/kimi-web/src/i18n/locales/en/status.ts
+++ b/apps/kimi-web/src/i18n/locales/en/status.ts
@@ -12,23 +12,32 @@ export default {
permissionYoloDesc: 'Auto-approve tool actions, but agent may still ask questions',
// Plan mode pill
planLabel: 'Plan',
+ planDesc: 'Have the agent make a plan before changing files',
planOn: 'on',
planOff: 'off',
planTooltip: 'Toggle plan mode (research before editing)',
// Mode selector (Plan / Goal / Swarm)
modesLabel: 'Mode',
goalLabel: 'Goal',
+ goalDesc: 'Track one objective until it is complete',
swarmLabel: 'Swarm',
+ swarmDesc: 'Run parallel agents for broader exploration',
modeOff: 'Off',
goalPlaceholder: 'What should the agent achieve?',
goalStart: 'Start',
goalPause: 'Pause',
goalResume: 'Resume',
goalCancel: 'Cancel',
+ goalStatusActive: 'Active',
+ goalStatusPaused: 'Paused',
+ goalStatusBlocked: 'Blocked',
+ goalStatusComplete: 'Complete',
modeNotSupported: 'Not supported',
// Thinking selector
thinkingLabel: 'thinking',
thinkingTooltip: 'Toggle thinking mode',
+ thinkingOn: 'On',
+ thinkingOff: 'Off',
starredModels: 'Starred',
moreModels: 'More models…',
// Status panel
diff --git a/apps/kimi-web/src/i18n/locales/en/tools.ts b/apps/kimi-web/src/i18n/locales/en/tools.ts
index aaddeb334..13cc18211 100644
--- a/apps/kimi-web/src/i18n/locales/en/tools.ts
+++ b/apps/kimi-web/src/i18n/locales/en/tools.ts
@@ -13,6 +13,10 @@ export default {
task: 'Task',
swarm: 'Swarm',
ask_user: 'Question',
+ goal_create: 'Start Goal',
+ goal_get: 'Read Goal',
+ goal_budget: 'Set Goal Budget',
+ goal_update: 'Update Goal',
},
swarm: {
progress: '{done} / {total}',
@@ -32,6 +36,17 @@ export default {
created: 'created',
todos: '{count} items',
},
+ goal: {
+ objectiveWithCriterion: '{objective} · {criterion}',
+ status: 'Status: {status}',
+ budget: '{value} {unit}',
+ turns: '{value} turns',
+ tokens: '{value} tokens',
+ milliseconds: '{value} ms',
+ seconds: '{value} sec',
+ minutes: '{value} min',
+ hours: '{value} hr',
+ },
group: {
title: '{count} tool call | {count} tool calls',
running: 'running',
diff --git a/apps/kimi-web/src/i18n/locales/zh/composer.ts b/apps/kimi-web/src/i18n/locales/zh/composer.ts
index 6c1ec1926..719f7adb7 100644
--- a/apps/kimi-web/src/i18n/locales/zh/composer.ts
+++ b/apps/kimi-web/src/i18n/locales/zh/composer.ts
@@ -22,7 +22,7 @@ export default {
emptyConversationTitle: 'Kimi Code',
emptyConversation: '还没有消息 —— 在下方输入开始对话',
quickStartPlaceholder: '输入消息开始新对话…',
- thinkingSuffix: ' · thinking',
- thinkingSuffixEffort: ' · thinking: {level}',
+ thinkingSuffix: ' · 思考',
+ thinkingSuffixEffort: ' · 思考: {level}',
} as const;
diff --git a/apps/kimi-web/src/i18n/locales/zh/header.ts b/apps/kimi-web/src/i18n/locales/zh/header.ts
index 543cece6c..687845609 100644
--- a/apps/kimi-web/src/i18n/locales/zh/header.ts
+++ b/apps/kimi-web/src/i18n/locales/zh/header.ts
@@ -10,6 +10,11 @@ export default {
gitTooltip: '打开「文件 > 改动」',
detached: '游离',
openPr: '打开 Pull Request',
+ prStatusOpen: '已打开',
+ prStatusClosed: '已关闭',
+ prStatusMerged: '已合并',
+ prStatusDraft: '草稿',
+ prStatusUnknown: '未知',
options: '选项',
copySessionId: '复制 Session ID',
renameSession: '重命名',
diff --git a/apps/kimi-web/src/i18n/locales/zh/sidebar.ts b/apps/kimi-web/src/i18n/locales/zh/sidebar.ts
index bea56f556..9e92e43bd 100644
--- a/apps/kimi-web/src/i18n/locales/zh/sidebar.ts
+++ b/apps/kimi-web/src/i18n/locales/zh/sidebar.ts
@@ -31,9 +31,9 @@ export default {
language: '语言',
daemon: '后台',
noSessions: '暂无对话',
- showMore: '加载更多 ({count})',
+ showMore: '加载更多 {count} 个对话',
showLess: '收起',
- showAll: '展开 ({count})',
+ showAll: '展开剩余 {count} 个对话',
loadingMore: '加载中…',
collapseSidebar: '收起侧边栏',
expandSidebar: '展开侧边栏',
diff --git a/apps/kimi-web/src/i18n/locales/zh/status.ts b/apps/kimi-web/src/i18n/locales/zh/status.ts
index 98287e9d5..0256b119b 100644
--- a/apps/kimi-web/src/i18n/locales/zh/status.ts
+++ b/apps/kimi-web/src/i18n/locales/zh/status.ts
@@ -8,27 +8,36 @@ export default {
permissionAuto: '完全自主',
permissionYolo: '自动通过',
permissionManualDesc: '每个工具操作都需要你手动确认',
- permissionAutoDesc: '完全自主运行,agent 自己做决定,不再询问',
+ permissionAutoDesc: '完全自主运行,智能体自己做决定,不再询问',
permissionYoloDesc: '自动批准工具操作,但遇到关键问题仍会询问',
// 计划模式
planLabel: '计划',
+ planDesc: '先让智能体梳理计划,再修改文件',
planOn: '开',
planOff: '关',
planTooltip: '切换计划模式(先调研再修改)',
// 模式选择器(计划 / 目标 / Swarm)
modesLabel: '模式',
goalLabel: '目标',
+ goalDesc: '持续跟踪一个目标,直到任务完成',
swarmLabel: 'Swarm',
+ swarmDesc: '并行运行多个智能体,适合大范围探索',
modeOff: '未启用',
- goalPlaceholder: '让 Agent 完成什么目标?',
+ goalPlaceholder: '让智能体完成什么目标?',
goalStart: '开始',
goalPause: '暂停',
goalResume: '继续',
goalCancel: '取消',
+ goalStatusActive: '进行中',
+ goalStatusPaused: '已暂停',
+ goalStatusBlocked: '已阻塞',
+ goalStatusComplete: '已完成',
modeNotSupported: '暂不支持',
// 思考强度选择
thinkingLabel: '思考',
thinkingTooltip: '切换思考模式',
+ thinkingOn: '开',
+ thinkingOff: '关',
starredModels: '收藏',
moreModels: '更多模型…',
// 状态面板
diff --git a/apps/kimi-web/src/i18n/locales/zh/tools.ts b/apps/kimi-web/src/i18n/locales/zh/tools.ts
index 0cee01058..f9560e3da 100644
--- a/apps/kimi-web/src/i18n/locales/zh/tools.ts
+++ b/apps/kimi-web/src/i18n/locales/zh/tools.ts
@@ -13,6 +13,10 @@ export default {
task: '任务',
swarm: 'Swarm',
ask_user: '提问',
+ goal_create: '启动目标',
+ goal_get: '读取目标',
+ goal_budget: '设置目标预算',
+ goal_update: '更新目标',
},
swarm: {
progress: '{done} / {total}',
@@ -32,6 +36,17 @@ export default {
created: '已创建',
todos: '{count} 项',
},
+ goal: {
+ objectiveWithCriterion: '{objective} · {criterion}',
+ status: '状态:{status}',
+ budget: '{value} {unit}',
+ turns: '{value} 轮',
+ tokens: '{value} token',
+ milliseconds: '{value} 毫秒',
+ seconds: '{value} 秒',
+ minutes: '{value} 分钟',
+ hours: '{value} 小时',
+ },
group: {
title: '{count} 个工具调用',
running: '运行中',
diff --git a/apps/kimi-web/src/lib/icons.ts b/apps/kimi-web/src/lib/icons.ts
index e41f0b1e4..a6e1ab5d2 100644
--- a/apps/kimi-web/src/lib/icons.ts
+++ b/apps/kimi-web/src/lib/icons.ts
@@ -43,6 +43,7 @@ import RiExpandRightLine from '~icons/ri/expand-right-line';
import RiExternalLinkLine from '~icons/ri/external-link-line';
import RiFileAddLine from '~icons/ri/file-add-line';
import RiFileCopyLine from '~icons/ri/file-copy-line';
+import RiFileEditLine from '~icons/ri/file-edit-line';
import RiFileLine from '~icons/ri/file-line';
import RiFileTextLine from '~icons/ri/file-text-line';
import RiFlashlightLine from '~icons/ri/flashlight-line';
@@ -61,6 +62,7 @@ import RiLoginBoxLine from '~icons/ri/login-box-line';
import RiMailLine from '~icons/ri/mail-line';
import RiMessageLine from '~icons/ri/message-line';
import RiMoreLine from '~icons/ri/more-line';
+import RiPauseFill from '~icons/ri/pause-fill';
import RiPencilLine from '~icons/ri/pencil-line';
import RiPlayFill from '~icons/ri/play-fill';
import RiQuestionLine from '~icons/ri/question-line';
@@ -72,6 +74,7 @@ import RiStarFill from '~icons/ri/star-fill';
import RiStarLine from '~icons/ri/star-line';
import RiStopFill from '~icons/ri/stop-fill';
import RiSubtractLine from '~icons/ri/subtract-line';
+import RiTargetLine from '~icons/ri/target-line';
import RiTerminalBoxLine from '~icons/ri/terminal-box-line';
import RiTimeLine from '~icons/ri/time-line';
import RiToolsLine from '~icons/ri/tools-line';
@@ -104,6 +107,7 @@ import RawExpandRightLine from '~icons/ri/expand-right-line?raw';
import RawExternalLinkLine from '~icons/ri/external-link-line?raw';
import RawFileAddLine from '~icons/ri/file-add-line?raw';
import RawFileCopyLine from '~icons/ri/file-copy-line?raw';
+import RawFileEditLine from '~icons/ri/file-edit-line?raw';
import RawFileLine from '~icons/ri/file-line?raw';
import RawFileTextLine from '~icons/ri/file-text-line?raw';
import RawFlashlightLine from '~icons/ri/flashlight-line?raw';
@@ -122,6 +126,7 @@ import RawLoginBoxLine from '~icons/ri/login-box-line?raw';
import RawMailLine from '~icons/ri/mail-line?raw';
import RawMessageLine from '~icons/ri/message-line?raw';
import RawMoreLine from '~icons/ri/more-line?raw';
+import RawPauseFill from '~icons/ri/pause-fill?raw';
import RawPencilLine from '~icons/ri/pencil-line?raw';
import RawPlayFill from '~icons/ri/play-fill?raw';
import RawQuestionLine from '~icons/ri/question-line?raw';
@@ -133,6 +138,7 @@ import RawStarFill from '~icons/ri/star-fill?raw';
import RawStarLine from '~icons/ri/star-line?raw';
import RawStopFill from '~icons/ri/stop-fill?raw';
import RawSubtractLine from '~icons/ri/subtract-line?raw';
+import RawTargetLine from '~icons/ri/target-line?raw';
import RawTerminalBoxLine from '~icons/ri/terminal-box-line?raw';
import RawTimeLine from '~icons/ri/time-line?raw';
import RawToolsLine from '~icons/ri/tools-line?raw';
@@ -177,6 +183,7 @@ export type IconName =
| 'folder-solid'
| 'file'
| 'file-text'
+ | 'file-edit'
| 'file-plus'
| 'file-off'
| 'image-off'
@@ -197,6 +204,8 @@ export type IconName =
| 'alert-triangle'
| 'clock'
| 'sparkles'
+ | 'target'
+ | 'pause'
| 'play'
| 'stop'
| 'star'
@@ -256,6 +265,7 @@ export const ICONS: Record = {
'folder-solid': entry(RiFolderFill, RawFolderFill),
file: entry(RiFileLine, RawFileLine),
'file-text': entry(RiFileTextLine, RawFileTextLine),
+ 'file-edit': entry(RiFileEditLine, RawFileEditLine),
'file-plus': entry(RiFileAddLine, RawFileAddLine),
'file-off': entry(RiFileLine, RawFileLine),
'image-off': entry(RiImageLine, RawImageLine),
@@ -276,6 +286,8 @@ export const ICONS: Record = {
'alert-triangle': entry(RiAlertLine, RawAlertLine),
clock: entry(RiTimeLine, RawTimeLine),
sparkles: entry(RiSparklingLine, RawSparklingLine),
+ target: entry(RiTargetLine, RawTargetLine),
+ pause: entry(RiPauseFill, RawPauseFill),
play: entry(RiPlayFill, RawPlayFill),
stop: entry(RiStopFill, RawStopFill),
star: entry(RiStarFill, RawStarFill),
@@ -353,6 +365,7 @@ export const ICON_GROUPS: ReadonlyArray
'folder-solid',
'file',
'file-text',
+ 'file-edit',
'file-plus',
'file-off',
'image-off',
@@ -365,6 +378,7 @@ export const ICON_GROUPS: ReadonlyArray
'check-list',
'bolt',
'git-pull-request',
+ 'target',
'calendar-schedule',
'calendar-todo',
'calendar-close',
@@ -379,6 +393,7 @@ export const ICON_GROUPS: ReadonlyArray
'alert-triangle',
'clock',
'sparkles',
+ 'pause',
'play',
'stop',
'star',
diff --git a/apps/kimi-web/src/lib/toolMeta.ts b/apps/kimi-web/src/lib/toolMeta.ts
index 6ecfd4c00..a2b011132 100644
--- a/apps/kimi-web/src/lib/toolMeta.ts
+++ b/apps/kimi-web/src/lib/toolMeta.ts
@@ -25,6 +25,10 @@ const TOOL_LABEL_KEYS: Record = {
task: 'tools.label.task',
agentswarm: 'tools.label.swarm',
askuserquestion: 'tools.label.ask_user',
+ creategoal: 'tools.label.goal_create',
+ getgoal: 'tools.label.goal_get',
+ setgoalbudget: 'tools.label.goal_budget',
+ updategoal: 'tools.label.goal_update',
};
// ---------------------------------------------------------------------------
@@ -60,6 +64,10 @@ const NAME_ALIASES: Record = {
subagent: 'task',
websearch: 'search',
web_search: 'search',
+ create_goal: 'creategoal',
+ get_goal: 'getgoal',
+ set_goal_budget: 'setgoalbudget',
+ update_goal: 'updategoal',
};
export function normalizeToolName(name: string): string {
@@ -93,6 +101,10 @@ const TOOL_GLYPH: Record = {
task: 'sparkles',
agentswarm: 'git-pull-request',
askuserquestion: 'help-circle',
+ creategoal: 'target',
+ getgoal: 'target',
+ setgoalbudget: 'target',
+ updategoal: 'target',
// Cron scheduling tools share a calendar motif: schedule / list / cancel.
croncreate: 'calendar-schedule',
cronlist: 'calendar-todo',
@@ -182,6 +194,41 @@ function filePath(d: Record): string | undefined {
return str(d.path) ?? str(d.file_path) ?? str(d.filePath) ?? str(d.filename);
}
+const GOAL_STATUS_KEYS: Record = {
+ active: 'status.goalStatusActive',
+ blocked: 'status.goalStatusBlocked',
+ complete: 'status.goalStatusComplete',
+};
+
+function goalStatusLabel(value: unknown): string | undefined {
+ const status = str(value);
+ if (!status) return undefined;
+ const key = GOAL_STATUS_KEYS[status];
+ return key ? t(key) : status;
+}
+
+function goalBudgetSummary(d: Record): string | undefined {
+ const value = num(d.value);
+ const unit = str(d.unit);
+ if (value === undefined || !unit) return undefined;
+ switch (unit) {
+ case 'turns':
+ return t('tools.goal.turns', { value });
+ case 'tokens':
+ return t('tools.goal.tokens', { value });
+ case 'milliseconds':
+ return t('tools.goal.milliseconds', { value });
+ case 'seconds':
+ return t('tools.goal.seconds', { value });
+ case 'minutes':
+ return t('tools.goal.minutes', { value });
+ case 'hours':
+ return t('tools.goal.hours', { value });
+ default:
+ return t('tools.goal.budget', { value, unit });
+ }
+}
+
const BASH_MAX = 64;
/**
@@ -255,6 +302,27 @@ export function toolSummary(name: string, arg: string, full = false): string {
if (items) return c(t('tools.chip.todos', { count: items.length }));
return fallback();
}
+ case 'creategoal': {
+ if (full) return fallback();
+ const objective = str(d.objective);
+ const criterion = str(d.completionCriterion);
+ if (objective && criterion) return c(t('tools.goal.objectiveWithCriterion', { objective, criterion }));
+ return objective ? c(objective) : fallback();
+ }
+ case 'getgoal': {
+ if (full) return fallback();
+ return '';
+ }
+ case 'setgoalbudget': {
+ if (full) return fallback();
+ const summary = goalBudgetSummary(d);
+ return summary ? c(summary) : fallback();
+ }
+ case 'updategoal': {
+ if (full) return fallback();
+ const status = goalStatusLabel(d.status);
+ return status ? c(t('tools.goal.status', { status })) : fallback();
+ }
default:
return fallback();
}
diff --git a/apps/kimi-web/src/main.ts b/apps/kimi-web/src/main.ts
index d546f7ae6..55475a234 100644
--- a/apps/kimi-web/src/main.ts
+++ b/apps/kimi-web/src/main.ts
@@ -2,7 +2,8 @@ import { createApp } from 'vue';
import App from './App.vue';
import i18n from './i18n';
import { installClientErrorCapture } from './debug/trace';
-import '@fontsource-variable/inter/wght.css';
+import '@fontsource-variable/inter/opsz.css';
+import '@fontsource-variable/inter/opsz-italic.css';
import '@fontsource-variable/jetbrains-mono/wght.css';
import './style.css';
diff --git a/apps/kimi-web/src/style.css b/apps/kimi-web/src/style.css
index dda829b72..1f9ae2e50 100644
--- a/apps/kimi-web/src/style.css
+++ b/apps/kimi-web/src/style.css
@@ -206,9 +206,8 @@ summary {
--content-font-size: calc(var(--base-ui-font-size) + 1px);
--sidebar-ui-font-size: calc(var(--base-ui-font-size) + 1px);
--mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
- /* Body/UI font follows the design-system canonical token (system UI font
- first; Inter intentionally NOT in the body chain — it stays reserved for
- --font-display headings). Mirrors --font-ui so the two can never drift. */
+ /* Body/UI font follows the design-system canonical token. Mirrors --font-ui
+ so the legacy alias can never drift from the current text face. */
--sans: var(--font-ui);
color-scheme: light dark;
}
@@ -454,14 +453,15 @@ html[data-color-scheme="dark"][data-accent="mono"] {
--duration-slow: 260ms;
/* -- type families ------------------------------------------------------- */
- /* UI/body use the platform's native UI font first (design-system §02);
- Inter is intentionally NOT in this chain — it is reserved for
- --font-display (optional headings / brand wordmarks) below. */
- --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
- "Hiragino Sans GB", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans SC",
- Roboto, Ubuntu, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji",
- "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- --font-display: "Inter Variable", "Inter", var(--font-ui);
+ /* UI/body use self-hosted Inter first. CJK and platform system UI families
+ stay late in the fallback chain so Latin glyphs resolve to Inter while
+ Chinese text can still fall through to native CJK fonts. */
+ --font-ui: "Inter Variable", "Inter", "Helvetica Neue", Arial,
+ "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Source Han Sans SC",
+ "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
+ Ubuntu, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
+ "Segoe UI Symbol", "Noto Color Emoji";
+ --font-display: var(--font-ui);
--font-mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace,
"SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
@@ -643,6 +643,7 @@ body {
font-size: var(--ui-font-size);
font-weight: 400;
line-height: 1.6;
+ font-optical-sizing: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: auto;
diff --git a/apps/kimi-web/src/views/DesignSystemView.vue b/apps/kimi-web/src/views/DesignSystemView.vue
index 7053cfce0..358d777e2 100644
--- a/apps/kimi-web/src/views/DesignSystemView.vue
+++ b/apps/kimi-web/src/views/DesignSystemView.vue
@@ -227,18 +227,19 @@ onUnmounted(() => {
All disabled controls use opacity:.5 + cursor:not-allowed uniformly; do not separately grey out or recolor.
Font families
-
Kimi Web uses two font families: --font-ui (UI and body, system fonts first) and --font-mono (code and monospace). Components always reference the variables; do not hard-code font names.
+
Kimi Web uses two font families: --font-ui (UI and body, Inter first) and --font-mono (code and monospace). Components always reference the variables; do not hard-code font names.
-
--font-ui · UI & body (system fonts first)
-
Body and UI use each platform's native UI font — close to the system feel, comfortable for long text and CJK. Fallback chain:
Body and UI use self-hosted Inter as the primary face. CJK and platform system UI fonts sit late in the fallback chain so Latin glyphs resolve to Inter while Chinese text can fall through to native CJK fonts: