diff --git a/.changeset/fix-web-media-alpha-canvas.md b/.changeset/fix-web-media-alpha-canvas.md
new file mode 100644
index 0000000000..828f67ae0a
--- /dev/null
+++ b/.changeset/fix-web-media-alpha-canvas.md
@@ -0,0 +1,5 @@
+---
+"@moonshot-ai/kimi-code": patch
+---
+
+web: Show transparent images over a checkerboard canvas so white and black content stays visible in both light and dark themes.
diff --git a/apps/kimi-web/scripts/check-style.mjs b/apps/kimi-web/scripts/check-style.mjs
index 81480efe96..43a0048494 100644
--- a/apps/kimi-web/scripts/check-style.mjs
+++ b/apps/kimi-web/scripts/check-style.mjs
@@ -115,8 +115,9 @@ function checkFile(abs) {
const trimmed = raw.trim();
const isTokenDef = /^\s*--[\w-]+\s*:/.test(raw);
- // no-gradient-text
- if (/\b(?:linear|radial|conic)-gradient\s*\(/i.test(raw)) {
+ // no-gradient-text (a custom-property definition is never rendered text
+ // itself, so gradient tokens like --media-alpha-canvas don't count)
+ if (!isTokenDef && /\b(?:linear|radial|conic)-gradient\s*\(/i.test(raw)) {
add('no-gradient-text', file, line, trimmed.slice(0, 80));
}
diff --git a/apps/kimi-web/src/components/FilePreview.vue b/apps/kimi-web/src/components/FilePreview.vue
index 1888c2127d..1f3f2f546a 100644
--- a/apps/kimi-web/src/components/FilePreview.vue
+++ b/apps/kimi-web/src/components/FilePreview.vue
@@ -922,6 +922,7 @@ function truncatePath(path: string, maxLen = 55): string {
object-fit: contain;
border: 1px solid var(--line);
border-radius: 4px;
+ background: var(--media-alpha-canvas);
}
.fp-image.actual {
max-width: none;
diff --git a/apps/kimi-web/src/components/chat/Markdown.vue b/apps/kimi-web/src/components/chat/Markdown.vue
index 3e20657ddc..5075ad4d06 100644
--- a/apps/kimi-web/src/components/chat/Markdown.vue
+++ b/apps/kimi-web/src/components/chat/Markdown.vue
@@ -533,6 +533,12 @@ function copyDiff(code: string, idx: number) {
font-size: var(--content-font-size);
}
+/* Themed surfaces swallow white-on-transparent (light) or black-on-transparent
+ (dark) images; the checkerboard canvas keeps both visible. */
+.md :deep(.markdown-renderer img) {
+ background: var(--media-alpha-canvas);
+}
+
/* Emphasis — keep the weight strong, but soften the ink slightly. */
.md :deep(strong) {
color: color-mix(in srgb, var(--color-text) 86%, var(--color-text-muted));
diff --git a/apps/kimi-web/src/components/chat/tool-calls/MediaTool.vue b/apps/kimi-web/src/components/chat/tool-calls/MediaTool.vue
index 36ab629af1..99f43ab966 100644
--- a/apps/kimi-web/src/components/chat/tool-calls/MediaTool.vue
+++ b/apps/kimi-web/src/components/chat/tool-calls/MediaTool.vue
@@ -89,6 +89,7 @@ function openMediaPreview(): void {
display: block;
max-width: 100%;
border-radius: var(--radius-md);
+ background: var(--media-alpha-canvas);
}
.media-video,
.media-audio {
diff --git a/apps/kimi-web/src/style.css b/apps/kimi-web/src/style.css
index da20f80734..153d6e4a22 100644
--- a/apps/kimi-web/src/style.css
+++ b/apps/kimi-web/src/style.css
@@ -396,6 +396,18 @@ html[data-color-scheme="dark"][data-accent="mono"] {
--color-surface: #fafbfc;
--color-surface-raised: #ffffff;
--color-surface-sunken: #f3f5f8;
+ /* Checkerboard canvas behind so transparent PNGs keep white/black
+ content visible and read as transparent. Squares are mixed from the
+ theme's bg/text (≈#858585/#6b6b6b light, ≈#676b72/#7a7e85 dark), each
+ ≥3:1 against both white and black; opaque images simply cover it. */
+ --color-media-alpha-bg-1: color-mix(in srgb, var(--color-bg) 52%, var(--color-text) 48%);
+ --color-media-alpha-bg-2: color-mix(in srgb, var(--color-bg) 42%, var(--color-text) 58%);
+ --media-alpha-canvas: conic-gradient(
+ var(--color-media-alpha-bg-1) 25%,
+ var(--color-media-alpha-bg-2) 0 50%,
+ var(--color-media-alpha-bg-1) 0 75%,
+ var(--color-media-alpha-bg-2) 0
+ ) 0 0 / 16px 16px;
/* Foreground text colours. `--color-text` is the default solid body / UI
colour (headings and emphasis share it); muted / faint step down for
secondary and tertiary copy; on-accent is text drawn on the accent fill. */
diff --git a/apps/kimi-web/src/views/DesignSystemView.vue b/apps/kimi-web/src/views/DesignSystemView.vue
index 0ae9897861..404f445b6f 100644
--- a/apps/kimi-web/src/views/DesignSystemView.vue
+++ b/apps/kimi-web/src/views/DesignSystemView.vue
@@ -194,6 +194,8 @@ onUnmounted(() => {
<img> alpha canvas — color-mix of --color-bg/--color-text (52/48); applied via --media-alpha-canvas (16px period)--color-bg so the session column reads as its own plane