diff --git a/public/images/integrations/claude-managed-agents-dark.webp b/public/images/integrations/claude-managed-agents-dark.webp
new file mode 100644
index 0000000..c8e2d6d
Binary files /dev/null and b/public/images/integrations/claude-managed-agents-dark.webp differ
diff --git a/public/images/integrations/claude-managed-agents-light.webp b/public/images/integrations/claude-managed-agents-light.webp
new file mode 100644
index 0000000..176ff87
Binary files /dev/null and b/public/images/integrations/claude-managed-agents-light.webp differ
diff --git a/src/components/react/ThemeImage.tsx b/src/components/react/ThemeImage.tsx
new file mode 100644
index 0000000..e23e096
--- /dev/null
+++ b/src/components/react/ThemeImage.tsx
@@ -0,0 +1,58 @@
+import type { CSSProperties } from 'react';
+
+interface ThemeImageProps {
+ /** Image shown in light mode. */
+ light: string;
+ /** Image shown in dark mode. */
+ dark: string;
+ alt: string;
+ width?: number | string;
+ height?: number | string;
+ className?: string;
+ style?: CSSProperties;
+}
+
+/**
+ * Renders a light and dark version of an image and swaps between them based on
+ * the active `data-theme`. The swap is pure CSS (see custom.css), so there's no
+ * hydration flash — both `
`s are in the DOM and only one is displayed.
+ *
+ * The images carry their own alpha channel (the flat canvas is keyed out to
+ * transparency), so the artwork floats on any surface — page body, nav, a
+ * callout, the dark-mode ambient texture. That's why this uses transparency
+ * rather than `mix-blend-mode`: a blend only melts into a flat backdrop in the
+ * same stacking context and leaves a seam anywhere the surface isn't that exact
+ * color.
+ */
+export function ThemeImage({
+ light,
+ dark,
+ alt,
+ width,
+ height,
+ className,
+ style,
+}: ThemeImageProps) {
+ return (
+
+
+
+
+ );
+}
diff --git a/src/components/react/index.ts b/src/components/react/index.ts
index 0632b77..5309a73 100644
--- a/src/components/react/index.ts
+++ b/src/components/react/index.ts
@@ -36,4 +36,5 @@ export { SearchDialog } from './SearchDialog';
export { SearchDialogWrapper } from './SearchDialogWrapper';
export { StatusBadge, StatusCodes } from './StatusCodes';
export { StatusIcon } from './StatusIcon';
+export { ThemeImage } from './ThemeImage';
export { ThemeSwitcher } from './ThemeSwitcher';
diff --git a/src/content/docs/integrations/claude-managed-agents.mdx b/src/content/docs/integrations/claude-managed-agents.mdx
index 639b95e..a2e61d6 100644
--- a/src/content/docs/integrations/claude-managed-agents.mdx
+++ b/src/content/docs/integrations/claude-managed-agents.mdx
@@ -3,8 +3,7 @@ title: Claude Managed Agents
description: Run Anthropic Claude Managed Agents with tool execution inside your own Sprites
---
-import { Callout } from '@/components/react';
-import SelfHostedDiagram from '@/components/SelfHostedDiagram.astro';
+import { Callout, ThemeImage } from '@/components/react';
import { Tabs, TabItem } from '@astrojs/starlight/components';
+
The runner authenticates with an **environment key**, the only credential it needs for both the control plane and the per-session calls. Your organization API key never reaches the Sprite.
diff --git a/src/styles/custom.css b/src/styles/custom.css
index 5b6287d..7a204a1 100644
--- a/src/styles/custom.css
+++ b/src/styles/custom.css
@@ -2135,3 +2135,26 @@ h2.method-title {
--co-decoration-hover: #1e3a8a99;
--co-link-hover: #172554;
}
+
+/* Theme-aware image swap (ThemeImage component)
+ Both variants render into the DOM; CSS shows the one matching the active
+ theme. The images have transparent (keyed) backgrounds, so the artwork floats
+ on any surface with no blend mode or matching backdrop needed. */
+.theme-image-frame {
+ display: block;
+ line-height: 0;
+}
+.theme-image {
+ display: block;
+ width: 100%;
+ height: auto;
+}
+.theme-image--dark {
+ display: none;
+}
+[data-theme='dark'] .theme-image--light {
+ display: none;
+}
+[data-theme='dark'] .theme-image--dark {
+ display: block;
+}