diff --git a/src/__testing__/CustomCatalogCard.test.tsx b/src/__testing__/CustomCatalogCard.test.tsx
new file mode 100644
index 000000000..ce1d2801c
--- /dev/null
+++ b/src/__testing__/CustomCatalogCard.test.tsx
@@ -0,0 +1,55 @@
+import { render } from '@testing-library/react';
+import React from 'react';
+import { CustomCatalogCard } from '../custom/CustomCatalog';
+import type { Pattern } from '../custom/CustomCatalog/CustomCard';
+import { SistentThemeProvider } from '../theme';
+
+// CustomCatalogCard -> CustomTooltip -> Markdown -> react-markdown (ESM-only) is
+// excluded by jest's transformIgnorePatterns allowlist, so those leaf modules are stubbed.
+jest.mock('react-markdown', () => ({
+ __esModule: true,
+ default: ({ children }: { children: React.ReactNode }) =>
{children}
+}));
+jest.mock('remark-gfm', () => ({ __esModule: true, default: () => {} }));
+jest.mock('rehype-raw', () => ({ __esModule: true, default: () => {} }));
+
+const renderWithTheme = (ui: React.ReactElement) =>
+ render({ui});
+
+const pattern = {
+ id: 'design-1',
+ userId: 'user-1',
+ patternFile: 'name: API Architecture',
+ name: 'API Architecture',
+ visibility: 'public',
+ avatarUrl: '',
+ user: { firstName: 'Ada', lastName: 'Lovelace' },
+ catalogData: { contentClass: 'community', compatibility: [] }
+} as unknown as Pattern;
+
+// The flipping element is `.innerCard`; its first child is the front face.
+const getFrontFace = (container: HTMLElement) =>
+ container.querySelector('.innerCard')?.firstElementChild as HTMLElement;
+
+describe('CustomCatalogCard', () => {
+ it('gives the front face its own 3D transform when the card flips', () => {
+ // Regression for meshery/meshery#22640: Firefox ignores
+ // `backface-visibility: hidden` on a z-indexed face that has no transform
+ // of its own, painting the front face mirrored over the back on hover.
+ const { container } = renderWithTheme(
+
+ );
+
+ const front = getComputedStyle(getFrontFace(container));
+ expect(front.backfaceVisibility).toBe('hidden');
+ expect(front.transform).toBe('rotateY(0deg)');
+ });
+
+ it('leaves the front face untransformed when the card does not flip', () => {
+ const { container } = renderWithTheme(
+
+ );
+
+ expect(getComputedStyle(getFrontFace(container)).transform).toBe('');
+ });
+});
diff --git a/src/custom/CustomCatalog/style.tsx b/src/custom/CustomCatalog/style.tsx
index 45e3b329b..989de2f13 100644
--- a/src/custom/CustomCatalog/style.tsx
+++ b/src/custom/CustomCatalog/style.tsx
@@ -377,6 +377,9 @@ export const CardFront = styled('div')(({ shouldFlip, isDeta
zIndex: 1,
...(shouldFlip && {
position: 'absolute',
+ // Firefox ignores backface-visibility on a z-indexed face without its own
+ // transform, painting the front mirrored over CardBack (meshery/meshery#22640).
+ transform: 'rotateY(0deg)',
boxShadow,
background
}),