diff --git a/.changeset/theme-mailbox-markdown-links.md b/.changeset/theme-mailbox-markdown-links.md
new file mode 100644
index 0000000000..baf3cec9b4
--- /dev/null
+++ b/.changeset/theme-mailbox-markdown-links.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": patch
+---
+
+summary: Mailbox message links now use theme colors instead of default browser blue.
+category: fix
+dev: Markdown anchor states use dashboard tokens in shared MailboxMessageContent styling.
diff --git a/packages/dashboard/app/components/MailboxModal.css b/packages/dashboard/app/components/MailboxModal.css
index c6f9c2d1a5..9d3df9a6f1 100644
--- a/packages/dashboard/app/components/MailboxModal.css
+++ b/packages/dashboard/app/components/MailboxModal.css
@@ -411,6 +411,35 @@ Artifact-registration mail messages now render metadata-driven media and produci
padding-left: var(--space-lg);
}
+/*
+FNXC:Mailbox 2026-07-26-14:39:
+Markdown links in mailbox message bodies must use theme tokens: browser default blue
+and visited purple clash with dark themes and violate the dashboard token system.
+*/
+.mailbox-markdown a {
+ color: var(--accent);
+ text-decoration: underline;
+ text-decoration-color: color-mix(in srgb, var(--accent) 45%, transparent);
+ text-underline-offset: var(--space-2xs);
+ border-radius: var(--radius-sm);
+ overflow-wrap: anywhere;
+ transition: color var(--transition-fast), text-decoration-color var(--transition-fast);
+}
+
+.mailbox-markdown a:visited {
+ color: var(--accent);
+}
+
+.mailbox-markdown a:hover {
+ color: color-mix(in srgb, var(--accent) 85%, var(--text));
+ text-decoration-color: var(--accent);
+}
+
+.mailbox-markdown a:focus-visible {
+ outline: none;
+ box-shadow: var(--focus-ring-strong);
+}
+
.mailbox-markdown :not(pre) > code {
padding: 0 var(--space-xs);
border-radius: var(--radius-sm);
diff --git a/packages/dashboard/app/components/__tests__/MailboxMessageContent.test.tsx b/packages/dashboard/app/components/__tests__/MailboxMessageContent.test.tsx
index a017523f99..3203e3eadf 100644
--- a/packages/dashboard/app/components/__tests__/MailboxMessageContent.test.tsx
+++ b/packages/dashboard/app/components/__tests__/MailboxMessageContent.test.tsx
@@ -1,9 +1,13 @@
+import { readFileSync } from "node:fs";
+import { resolve } from "node:path";
import { describe, it, expect, afterEach, vi } from "vitest";
import { render, cleanup, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { FileBrowserProvider } from "../../context/FileBrowserContext";
import { MailboxMessageContent } from "../MailboxMessageContent";
+const mailboxModalCss = readFileSync(resolve(__dirname, "../MailboxModal.css"), "utf8");
+
// FNXC:Markdown 2026-06-23-03:15: Mock the heavy `mermaid` library so the mermaid
// rendering tests do not pull in the real parser/renderer bundle. The component
// lazy-imports `mermaid` (default export), so we mock the module default.
@@ -61,15 +65,44 @@ describe("MailboxMessageContent", () => {
expect(pre?.textContent).toContain("npm install");
});
- it("renders links with target=_blank and noopener noreferrer", () => {
- render(
- ,
+ it("themes markdown links consistently across inline, autolink, list, and table content", () => {
+ const content = [
+ "See [inline docs](https://example.com/inline).",
+ "Visit https://example.com/autolink.",
+ "- [list docs](https://example.com/list)",
+ "",
+ "| docs |",
+ "| --- |",
+ "| [table docs](https://example.com/table) |",
+ "",
+ "See packages/dashboard/app/App.tsx for context.",
+ ].join("\n");
+ const { container } = render(
+
+
+ ,
);
- const link = screen.getByRole("link", { name: "docs" });
- expect(link.getAttribute("href")).toBe("https://example.com/docs");
- expect(link.getAttribute("target")).toBe("_blank");
- expect(link.getAttribute("rel")).toContain("noopener");
- expect(link.getAttribute("rel")).toContain("noreferrer");
+
+ const links = screen.getAllByRole("link");
+ expect(links).toHaveLength(4);
+ for (const link of links) {
+ expect(link.closest(".mailbox-markdown")).not.toBeNull();
+ expect(link).toHaveAttribute("target", "_blank");
+ expect(link).toHaveAttribute("rel", "noopener noreferrer");
+ }
+ expect(screen.getByRole("button", { name: "packages/dashboard/app/App.tsx" }))
+ .toHaveClass("file-path-link");
+ expect(container.querySelector("a.file-path-link")).toBeNull();
+ });
+
+ it("defines token-only mailbox markdown anchor styles", () => {
+ const anchorRule = mailboxModalCss.match(/\.mailbox-markdown a\s*\{([^}]*)\}/)?.[1];
+ expect(mailboxModalCss).toMatch(/\.mailbox-markdown a\b/);
+ expect(anchorRule).toBeDefined();
+ expect(anchorRule).not.toMatch(/#[0-9a-f]{3,8}\b|rgba\(/i);
+ expect(mailboxModalCss).toMatch(/\.mailbox-markdown a:visited\s*\{/);
+ expect(mailboxModalCss).toMatch(/\.mailbox-markdown a:hover\s*\{/);
+ expect(mailboxModalCss).toMatch(/\.mailbox-markdown a:focus-visible\s*\{/);
});
it("renders GFM tables with the mailbox-scoped class", () => {