23 / 36
All 36 in 36 Tailwind Stacked Cards
- 01Tailwind Scroll-Driven Scaling Card Stack
- 02Tailwind Swipe Card Deck Drag to Dismiss
- 03Tailwind Glassmorphism Testimonial Card Stack
- 04Tailwind Stacked Cards Expand Accordion on Click
- 05Tailwind Fan Out Photo Stack on Hover
- 06Tailwind 3D Perspective Tilt Card Stack
- 07Tailwind Multi Step Form Card Stack
- 08Tailwind Tabbed Card Stack Bring to Front
- 09Tailwind Click to Front Stacked Cards Cycle
- 10Tailwind Classic Card Deck Stack Shadow
- 11Tailwind Fan Spread Hand of Cards
- 12Tailwind Polaroid Photo Stack Scattered Rotate
- 13Tailwind Staircase Offset Stacked Cards Cascade
- 14Tailwind Cards Spread Out Horizontally on Hover
- 15Tailwind Stacked Cards Lift on Hover Sibling Push
- 16Tailwind Accordion Stacked Cards Slide Out Menu
- 17Tailwind Shuffle Cards Animation Loop Deck
- 18Tailwind File Folder Tab Stacked Cards
- 19Tailwind Scattered Photos Pinch to Centre on Hover
- 20Tailwind Mobile Swipe Card Stack Translate3d
- 21Tailwind Single Accordion Card Nested Layers
- 22Tailwind Isometric Tower Stacked Cards 3D Column
- 23Tailwind 3D Flip Card Stack Reveal Back
- 24Tailwind Card Stack Tilt on Hover Quadrant
- 25Tailwind Notification Stack Pile Dismiss
- 26Tailwind Receipt Roll Unroll Stacked Items
- 27Tailwind Scratch Card Reveal Canvas Mask
- 28Tailwind Stacked Cards Hover Reveal Spread
- 29Tailwind Scroll Activated Sticky Stacking Cards
- 30Tailwind Stacked Testimonial Slider Radio
- 31Tailwind Isometric Overlapping Stacked Cards
- 32Tailwind Bento Grid Stacked Cards Hover Fan
- 33Tailwind Perspective Card Deck Depth Tunnel
- 34Tailwind Peel Back Corner Card Reveal
- 35Tailwind Timeline Stacked Milestone Cards
- 36Tailwind Spiral Tower Rotating Stacked Cards
Tailwind 3D Flip Card Stack Reveal Back
A pricing card that turns 180° to show what is behind it. This is the port where v4's own 3D utilities finally cover the ground: transform-3d, backface-hidden, rotate-y-180 and perspective-distant are all real classes, so the flip needs no arbitrary properties at all. The reduced-motion path is the substantive part — it replaces the turn with a cross-fade rather than a slower turn.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="stk-23 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk23-sans bg-stk23-bg" aria-label="3D flip card stack">
<div class="relative w-[min(280px,90vw)] h-60 [perspective:1200px]">
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:2" aria-hidden="true"></div>
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:1" aria-hidden="true"></div>
<div class="group absolute inset-0 z-5 rounded-[20px] outline-none focus-visible:shadow-[0_0_0_3px_var(--color-stk23-accent)]" tabindex="0">
<div class="relative size-full transform-3d transition-transform duration-600 ease-stk23 group-hover:rotate-y-180 group-focus-visible:rotate-y-180 motion-reduce:transition-none motion-reduce:rotate-y-0!">
<div class="absolute inset-0 flex flex-col justify-center rounded-[20px] p-6.5 text-white backface-hidden bg-linear-[155deg,var(--color-stk23-f1),var(--color-stk23-f2)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] transition-opacity duration-300 motion-reduce:group-hover:opacity-0 motion-reduce:group-focus-visible:opacity-0">
<p class="m-0 font-stk23-mono text-xs font-medium tracking-[0.16em] uppercase text-stk23-accent">Pro plan</p>
<h3 class="my-1.5 text-[44px] font-black leading-none tracking-[-0.03em]">$24<small class="text-base font-semibold text-stk23-muted">/mo</small></h3>
<p class="m-0 text-sm text-stk23-body">Hover or focus to see what’s inside →</p>
</div>
<div class="absolute inset-0 flex flex-col justify-center gap-3.5 rounded-[20px] p-6.5 text-white backface-hidden rotate-y-180 bg-linear-[155deg,var(--color-stk23-accent),var(--color-stk23-deep)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] opacity-100 transition-opacity duration-300 motion-reduce:rotate-y-0! motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100">
<ul class="flex list-none flex-col gap-2.25">
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Unlimited projects</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Priority support</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">SSO & audit log</li>
</ul>
<button class="rounded-[11px] border-0 bg-white px-4 py-2.75 text-sm font-extrabold text-stk23-deep cursor-pointer transition-transform duration-150 hover:scale-[1.02] active:scale-95 focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-2" type="button">Start trial</button>
</div>
</div>
</div>
</div>
</section><section class="stk-23 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk23-sans bg-stk23-bg" aria-label="3D flip card stack">
<div class="relative w-[min(280px,90vw)] h-60 [perspective:1200px]">
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:2" aria-hidden="true"></div>
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:1" aria-hidden="true"></div>
<div class="group absolute inset-0 z-5 rounded-[20px] outline-none focus-visible:shadow-[0_0_0_3px_var(--color-stk23-accent)]" tabindex="0">
<div class="relative size-full transform-3d transition-transform duration-600 ease-stk23 group-hover:rotate-y-180 group-focus-visible:rotate-y-180 motion-reduce:transition-none motion-reduce:rotate-y-0!">
<div class="absolute inset-0 flex flex-col justify-center rounded-[20px] p-6.5 text-white backface-hidden bg-linear-[155deg,var(--color-stk23-f1),var(--color-stk23-f2)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] transition-opacity duration-300 motion-reduce:group-hover:opacity-0 motion-reduce:group-focus-visible:opacity-0">
<p class="m-0 font-stk23-mono text-xs font-medium tracking-[0.16em] uppercase text-stk23-accent">Pro plan</p>
<h3 class="my-1.5 text-[44px] font-black leading-none tracking-[-0.03em]">$24<small class="text-base font-semibold text-stk23-muted">/mo</small></h3>
<p class="m-0 text-sm text-stk23-body">Hover or focus to see what’s inside →</p>
</div>
<div class="absolute inset-0 flex flex-col justify-center gap-3.5 rounded-[20px] p-6.5 text-white backface-hidden rotate-y-180 bg-linear-[155deg,var(--color-stk23-accent),var(--color-stk23-deep)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] opacity-100 transition-opacity duration-300 motion-reduce:rotate-y-0! motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100">
<ul class="flex list-none flex-col gap-2.25">
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Unlimited projects</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Priority support</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">SSO & audit log</li>
</ul>
<button class="rounded-[11px] border-0 bg-white px-4 py-2.75 text-sm font-extrabold text-stk23-deep cursor-pointer transition-transform duration-150 hover:scale-[1.02] active:scale-95 focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-2" type="button">Start trial</button>
</div>
</div>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-stk23-bg: #0f1119;
--color-stk23-bg: oklch(0.18 0.014 275);
--color-stk23-under: #1c1f2b;
--color-stk23-under: oklch(0.25 0.016 275);
--color-stk23-line: #2b2f3d;
--color-stk23-line: oklch(0.32 0.018 275);
--color-stk23-f1: #242838;
--color-stk23-f1: oklch(0.28 0.022 275);
--color-stk23-f2: #181b28;
--color-stk23-f2: oklch(0.23 0.020 275);
--color-stk23-muted: #9aa0b4;
--color-stk23-muted: oklch(0.70 0.018 275);
--color-stk23-body: #c3c7de;
--color-stk23-body: oklch(0.83 0.020 275);
--color-stk23-accent: #7b8fe8;
--color-stk23-accent: oklch(0.66 0.16 265);
--color-stk23-deep: #5c4dc4;
--color-stk23-deep: oklch(0.50 0.16 285);
--font-stk23-sans: 'Archivo', system-ui, sans-serif;
--font-stk23-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk23: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk23-bg: #0f1119;
--color-stk23-bg: oklch(0.18 0.014 275);
--color-stk23-under: #1c1f2b;
--color-stk23-under: oklch(0.25 0.016 275);
--color-stk23-line: #2b2f3d;
--color-stk23-line: oklch(0.32 0.018 275);
--color-stk23-f1: #242838;
--color-stk23-f1: oklch(0.28 0.022 275);
--color-stk23-f2: #181b28;
--color-stk23-f2: oklch(0.23 0.020 275);
--color-stk23-muted: #9aa0b4;
--color-stk23-muted: oklch(0.70 0.018 275);
--color-stk23-body: #c3c7de;
--color-stk23-body: oklch(0.83 0.020 275);
--color-stk23-accent: #7b8fe8;
--color-stk23-accent: oklch(0.66 0.16 265);
--color-stk23-deep: #5c4dc4;
--color-stk23-deep: oklch(0.50 0.16 285);
--font-stk23-sans: 'Archivo', system-ui, sans-serif;
--font-stk23-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk23: cubic-bezier(0.3, 0.9, 0.3, 1);
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-stk23-bg: #0f1119;
--color-stk23-bg: oklch(0.18 0.014 275);
--color-stk23-under: #1c1f2b;
--color-stk23-under: oklch(0.25 0.016 275);
--color-stk23-line: #2b2f3d;
--color-stk23-line: oklch(0.32 0.018 275);
--color-stk23-f1: #242838;
--color-stk23-f1: oklch(0.28 0.022 275);
--color-stk23-f2: #181b28;
--color-stk23-f2: oklch(0.23 0.020 275);
--color-stk23-muted: #9aa0b4;
--color-stk23-muted: oklch(0.70 0.018 275);
--color-stk23-body: #c3c7de;
--color-stk23-body: oklch(0.83 0.020 275);
--color-stk23-accent: #7b8fe8;
--color-stk23-accent: oklch(0.66 0.16 265);
--color-stk23-deep: #5c4dc4;
--color-stk23-deep: oklch(0.50 0.16 285);
--font-stk23-sans: 'Archivo', system-ui, sans-serif;
--font-stk23-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk23: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk23-bg: #0f1119;
--color-stk23-bg: oklch(0.18 0.014 275);
--color-stk23-under: #1c1f2b;
--color-stk23-under: oklch(0.25 0.016 275);
--color-stk23-line: #2b2f3d;
--color-stk23-line: oklch(0.32 0.018 275);
--color-stk23-f1: #242838;
--color-stk23-f1: oklch(0.28 0.022 275);
--color-stk23-f2: #181b28;
--color-stk23-f2: oklch(0.23 0.020 275);
--color-stk23-muted: #9aa0b4;
--color-stk23-muted: oklch(0.70 0.018 275);
--color-stk23-body: #c3c7de;
--color-stk23-body: oklch(0.83 0.020 275);
--color-stk23-accent: #7b8fe8;
--color-stk23-accent: oklch(0.66 0.16 265);
--color-stk23-deep: #5c4dc4;
--color-stk23-deep: oklch(0.50 0.16 285);
--font-stk23-sans: 'Archivo', system-ui, sans-serif;
--font-stk23-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk23: cubic-bezier(0.3, 0.9, 0.3, 1);
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@75..125,400;75..125,600;75..125,900&family=JetBrains+Mono:wght@400;500&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@75..125,400;75..125,600;75..125,900&family=JetBrains+Mono:wght@400;500&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The webfonts load as
<link>tags insetup, not as an@importinside the stylesheet. Tailwind emits user@importrules after its own@layerblocks, and a late@importis invalid CSS — the browser drops it and the demo silently falls back to system fonts. - This is the 3D demo that needs almost no arbitrary properties:
transform-3d,backface-hiddenandrotate-y-180are all real v4 utilities. - Only
[perspective:1200px]stays arbitrary, because the namedperspective-*scale has no entry at that distance. - The reduced-motion path is a different interaction rather than a slower one —
motion-reduce:rotate-y-0!plus opacity swaps turn the flip into a cross-fade. - The checkmark bullets are
before:content-['✓'], so the list needs no extra markup and no::beforerule. - The focus trigger sits on the wrapper (
group-focus-visible:) precisely because the reverse face contains a real focusable button. - Both faces are
absolute inset-0, which is the cheapest guarantee that they are exactly the same size and the turn cannot jump.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind 3D Flip Card Stack Reveal Back
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-3d-flip-card-stack-reveal-back/
A pricing card that turns 180° to show what is behind it. This is the port where v4's own 3D utilities finally cover the ground: transform-3d, backface-hidden, rotate-y-180 and perspective-distant are all real classes, so the flip needs no arbitrary properties at all. The reduced-motion path is the substantive part — it replaces the turn with a cross-fade rather than a slower turn.
## HTML
```html
<section class="stk-23 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk23-sans bg-stk23-bg" aria-label="3D flip card stack">
<div class="relative w-[min(280px,90vw)] h-60 [perspective:1200px]">
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:2" aria-hidden="true"></div>
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:1" aria-hidden="true"></div>
<div class="group absolute inset-0 z-5 rounded-[20px] outline-none focus-visible:shadow-[0_0_0_3px_var(--color-stk23-accent)]" tabindex="0">
<div class="relative size-full transform-3d transition-transform duration-600 ease-stk23 group-hover:rotate-y-180 group-focus-visible:rotate-y-180 motion-reduce:transition-none motion-reduce:rotate-y-0!">
<div class="absolute inset-0 flex flex-col justify-center rounded-[20px] p-6.5 text-white backface-hidden bg-linear-[155deg,var(--color-stk23-f1),var(--color-stk23-f2)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] transition-opacity duration-300 motion-reduce:group-hover:opacity-0 motion-reduce:group-focus-visible:opacity-0">
<p class="m-0 font-stk23-mono text-xs font-medium tracking-[0.16em] uppercase text-stk23-accent">Pro plan</p>
<h3 class="my-1.5 text-[44px] font-black leading-none tracking-[-0.03em]">$24<small class="text-base font-semibold text-stk23-muted">/mo</small></h3>
<p class="m-0 text-sm text-stk23-body">Hover or focus to see what’s inside →</p>
</div>
<div class="absolute inset-0 flex flex-col justify-center gap-3.5 rounded-[20px] p-6.5 text-white backface-hidden rotate-y-180 bg-linear-[155deg,var(--color-stk23-accent),var(--color-stk23-deep)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] opacity-100 transition-opacity duration-300 motion-reduce:rotate-y-0! motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100">
<ul class="flex list-none flex-col gap-2.25">
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Unlimited projects</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Priority support</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">SSO & audit log</li>
</ul>
<button class="rounded-[11px] border-0 bg-white px-4 py-2.75 text-sm font-extrabold text-stk23-deep cursor-pointer transition-transform duration-150 hover:scale-[1.02] active:scale-95 focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-2" type="button">Start trial</button>
</div>
</div>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk23-bg: #0f1119;
--color-stk23-bg: oklch(0.18 0.014 275);
--color-stk23-under: #1c1f2b;
--color-stk23-under: oklch(0.25 0.016 275);
--color-stk23-line: #2b2f3d;
--color-stk23-line: oklch(0.32 0.018 275);
--color-stk23-f1: #242838;
--color-stk23-f1: oklch(0.28 0.022 275);
--color-stk23-f2: #181b28;
--color-stk23-f2: oklch(0.23 0.020 275);
--color-stk23-muted: #9aa0b4;
--color-stk23-muted: oklch(0.70 0.018 275);
--color-stk23-body: #c3c7de;
--color-stk23-body: oklch(0.83 0.020 275);
--color-stk23-accent: #7b8fe8;
--color-stk23-accent: oklch(0.66 0.16 265);
--color-stk23-deep: #5c4dc4;
--color-stk23-deep: oklch(0.50 0.16 285);
--font-stk23-sans: 'Archivo', system-ui, sans-serif;
--font-stk23-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk23: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind 3D Flip Card Stack Reveal Back
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-3d-flip-card-stack-reveal-back/
A pricing card that turns 180° to show what is behind it. This is the port where v4's own 3D utilities finally cover the ground: transform-3d, backface-hidden, rotate-y-180 and perspective-distant are all real classes, so the flip needs no arbitrary properties at all. The reduced-motion path is the substantive part — it replaces the turn with a cross-fade rather than a slower turn.
## HTML
```html
<section class="stk-23 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk23-sans bg-stk23-bg" aria-label="3D flip card stack">
<div class="relative w-[min(280px,90vw)] h-60 [perspective:1200px]">
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:2" aria-hidden="true"></div>
<div class="absolute inset-0 rounded-[20px] border border-stk23-line bg-stk23-under shadow-[0_18px_34px_-22px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*10px),calc(var(--i)*10px))_scale(calc(1-var(--i)*0.04))]" style="--i:1" aria-hidden="true"></div>
<div class="group absolute inset-0 z-5 rounded-[20px] outline-none focus-visible:shadow-[0_0_0_3px_var(--color-stk23-accent)]" tabindex="0">
<div class="relative size-full transform-3d transition-transform duration-600 ease-stk23 group-hover:rotate-y-180 group-focus-visible:rotate-y-180 motion-reduce:transition-none motion-reduce:rotate-y-0!">
<div class="absolute inset-0 flex flex-col justify-center rounded-[20px] p-6.5 text-white backface-hidden bg-linear-[155deg,var(--color-stk23-f1),var(--color-stk23-f2)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] transition-opacity duration-300 motion-reduce:group-hover:opacity-0 motion-reduce:group-focus-visible:opacity-0">
<p class="m-0 font-stk23-mono text-xs font-medium tracking-[0.16em] uppercase text-stk23-accent">Pro plan</p>
<h3 class="my-1.5 text-[44px] font-black leading-none tracking-[-0.03em]">$24<small class="text-base font-semibold text-stk23-muted">/mo</small></h3>
<p class="m-0 text-sm text-stk23-body">Hover or focus to see what’s inside →</p>
</div>
<div class="absolute inset-0 flex flex-col justify-center gap-3.5 rounded-[20px] p-6.5 text-white backface-hidden rotate-y-180 bg-linear-[155deg,var(--color-stk23-accent),var(--color-stk23-deep)] shadow-[0_24px_48px_-26px_rgba(0,0,0,0.85)] opacity-100 transition-opacity duration-300 motion-reduce:rotate-y-0! motion-reduce:opacity-0 motion-reduce:group-hover:opacity-100 motion-reduce:group-focus-visible:opacity-100">
<ul class="flex list-none flex-col gap-2.25">
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Unlimited projects</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">Priority support</li>
<li class="relative pl-5.5 text-sm font-semibold before:absolute before:left-0 before:font-black before:content-['✓']">SSO & audit log</li>
</ul>
<button class="rounded-[11px] border-0 bg-white px-4 py-2.75 text-sm font-extrabold text-stk23-deep cursor-pointer transition-transform duration-150 hover:scale-[1.02] active:scale-95 focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-2" type="button">Start trial</button>
</div>
</div>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk23-bg: #0f1119;
--color-stk23-bg: oklch(0.18 0.014 275);
--color-stk23-under: #1c1f2b;
--color-stk23-under: oklch(0.25 0.016 275);
--color-stk23-line: #2b2f3d;
--color-stk23-line: oklch(0.32 0.018 275);
--color-stk23-f1: #242838;
--color-stk23-f1: oklch(0.28 0.022 275);
--color-stk23-f2: #181b28;
--color-stk23-f2: oklch(0.23 0.020 275);
--color-stk23-muted: #9aa0b4;
--color-stk23-muted: oklch(0.70 0.018 275);
--color-stk23-body: #c3c7de;
--color-stk23-body: oklch(0.83 0.020 275);
--color-stk23-accent: #7b8fe8;
--color-stk23-accent: oklch(0.66 0.16 265);
--color-stk23-deep: #5c4dc4;
--color-stk23-deep: oklch(0.50 0.16 285);
--font-stk23-sans: 'Archivo', system-ui, sans-serif;
--font-stk23-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk23: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```How this works
v4 ships the 3D vocabulary, and it shows. The whole flip reads as ordinary utilities:
<div class="transform-3d transition-transform duration-600
group-hover:rotate-y-180 group-focus-visible:rotate-y-180">
<div class="absolute inset-0 backface-hidden">front</div>
<div class="absolute inset-0 backface-hidden rotate-y-180">back</div>
</div>Compare demos 06 and 22, where nearly every 3D declaration had to be arbitrary: the difference is that flipping is a common enough pattern to have earned a scale, and skewed isometric columns are not.
The two rules that make it work. backface-hidden on both faces, or the far side shows through mirrored; and the back pre-rotated rotate-y-180 so it faces outward once the container turns. Miss either and the symptom is the same — text reading backwards.
Reduced motion is a different interaction, not a slower one. A 180° Y-axis rotation of a large element is exactly the motion vestibular users report as uncomfortable. Under motion-reduce: the container does not rotate at all; instead the front face fades out and the back fades in. The content is equally reachable and nothing spins.
Both faces are real content. The back holds a genuine list and a genuine button, both focusable — which is why the trigger is group-focus-visible: on the wrapper rather than hover: on the card: tabbing to the button inside must not leave it facing away from the viewer.
Make it yours
- Flip on the X axis by swapping
rotate-y-180forrotate-x-180on both the container and the back face. - Change the flip speed with
duration-600. - Restyle either face independently — they share only their box.
- Recolour the reverse through
--color-stk23-accent; the eyebrow, the ring and the button text all read it. - Add more decorative cards behind with the next
--i.
Gotchas — read before shipping
backface-hiddengoes on both faces. On one only, the hidden side bleeds through mirrored.- The back face must be pre-rotated
rotate-y-180, or it is still facing away when the container finishes turning. [perspective:…]belongs on the parent scene, not on the flipping element.- Keep both faces the same size —
absolute inset-0on both is the simplest guarantee. - The reduced-motion override needs
rotate-y-0!to beat thegroup-hover:rotation at equal specificity. - The focus trigger must be on the wrapper, not on the card face, or tabbing to the button on the reverse leaves it pointing away from the user.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms and backface-visibility are broadly supported (Chrome 36+, Safari 9+, Firefox 16+); the transform-3d, backface-hidden and rotate-y-* utilities are Tailwind v4 features, so the floor is v4's own generated sheet.