13 / 23
All 23 in 23 Tailwind CSS Flip Cards
- 01Tailwind Product Comparison Flip Card with Hover, Tap & Keyboard Reveal
- 02Tailwind Pricing Plan Flip Card with Gradient Price & Feature Reveal
- 03Tailwind Gift Card Flip with Copy-to-Clipboard Coupon Code Reveal
- 04Tailwind Meet the Team Flip Card with Bio, Socials & Contact Reveal
- 05Tailwind Portfolio Flip Card with Animated Skill Bar Proficiency Meters
- 06Tailwind Language Flashcard Flip with Phonetics, Example & Memory Tip
- 07Tailwind Trivia Quiz Flip Card with Answer Reveal & Score Readout
- 08Tailwind Gaming Trading Card Flip with Character Stats & Rarity Glow
- 09Tailwind Photo Gallery Flip Card with EXIF Metadata & Download CTA
- 10Tailwind Video Thumbnail Flip Card with Playlist, Stats & Watch CTA
- 11Tailwind Testimonial Flip Card with Star Rating & Reviewer Profile
- 12Tailwind Digital Business Card Flip with vCard Contacts & QR Panel
- 13Tailwind Restaurant Menu Card with Sliding Ingredient & Nutrition Reveal
- 14Tailwind Process Steps Flip Card Grid with Task Lists & Timelines
- 15Tailwind Vertical Axis Flip Card with rotateX Top-to-Bottom Reveal
- 16Tailwind Click-to-Flip Card with Persisted State & Keyboard Control
- 17Tailwind Auto-Height Flip Card with CSS Grid Stacking & Cross-Fade
- 18Tailwind Responsive Flip Card Grid with Per-Card 3D Perspective
- 19Tailwind Luxury Product Card with Hinged Book-Open 3D Unfold
- 20Tailwind Travel Postcard Flip Card with Diagonal rotate3d Twist
- 21Tailwind Album Card with clip-path Iris Aperture Reveal (No 3D)
- 22Tailwind Event Ticket Card with Bi-Fold Stub Reveal & QR Panel
- 23Tailwind Scratch Card with Diagonal clip-path Peel & Prize Reveal
Tailwind Restaurant Menu Card with Sliding Ingredient & Nutrition Reveal
The one card in the set with no 3D at all: the front slides out left while the back slides in from the right, like pulling a card from a file. It proves the pattern is about the reveal, not the rotation — and because there is no preserve-3d, the frosted price tag's backdrop-blur actually works, which it would not inside a 3D context in Firefox.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tfc-13 w-full min-h-svh grid place-items-center bg-tfc13-bg font-tfc13-sans px-5 py-10 text-tfc13-cream">
<div class="group relative w-[340px] max-w-full h-[470px] overflow-hidden rounded-2xl shadow-[0_1px_2px_oklch(0_0_0/0.5),0_22px_48px_-18px_oklch(0.3_0.08_50/0.7)] has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-tfc13-amber has-[:focus-visible]:outline-offset-4">
<input id="tfc-13-flip" type="checkbox" class="peer sr-only">
<label for="tfc-13-flip" class="absolute inset-0 z-20 cursor-pointer rounded-2xl"><span class="sr-only">Show ingredients, allergens and nutrition for Spaghetti al Ragu</span></label>
<div class="absolute inset-0 flex flex-col rounded-2xl overflow-hidden bg-tfc13-panel border border-tfc13-amber/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:-translate-x-full group-has-checked:-translate-x-full group-has-[:focus-visible]:-translate-x-full motion-reduce:transition-none">
<div class="relative grid h-55 shrink-0 place-items-center overflow-hidden bg-linear-160 from-tfc13-stage via-tfc13-stage2 to-tfc13-stage3 before:absolute before:inset-0 before:bg-[radial-gradient(circle_at_50%_60%,oklch(0.6_0.13_60/0.3),transparent_65%)]">
<svg class="relative z-1" width="180" height="160" viewBox="0 0 180 160" fill="none" role="img" aria-label="Illustration of a plate of spaghetti with meatballs, sauce and basil">
<ellipse cx="90" cy="110" rx="78" ry="30" fill="oklch(0.25 0.03 60 / 0.6)"/>
<ellipse cx="90" cy="105" rx="76" ry="28" fill="#2a1a08"/>
<ellipse cx="90" cy="103" rx="68" ry="24" fill="#1a0e04"/>
<path d="M55 95 Q70 80 85 95 Q100 110 115 95 Q130 80 125 95" stroke="oklch(0.65 0.14 65 / 0.8)" stroke-width="5" fill="none" stroke-linecap="round"/>
<path d="M60 100 Q75 85 90 100 Q105 115 120 100" stroke="oklch(0.58 0.12 55 / 0.7)" stroke-width="4" fill="none" stroke-linecap="round"/>
<path d="M65 90 Q80 75 95 90 Q110 105 125 90" stroke="oklch(0.75 0.15 70 / 0.6)" stroke-width="3" fill="none" stroke-linecap="round"/>
<circle cx="72" cy="88" r="14" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="72" cy="88" r="10" fill="oklch(0.52 0.1 50 / 0.8)"/>
<circle cx="108" cy="93" r="13" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="108" cy="93" r="9" fill="oklch(0.52 0.1 50 / 0.8)"/>
<ellipse cx="90" cy="95" rx="35" ry="12" fill="oklch(0.45 0.18 30 / 0.35)"/>
<circle cx="78" cy="76" r="3" fill="oklch(0.73 0.18 150 / 0.7)"/>
<circle cx="85" cy="74" r="2" fill="oklch(0.73 0.18 150 / 0.6)"/>
<circle cx="95" cy="78" r="2.5" fill="oklch(0.73 0.18 150 / 0.7)"/>
<ellipse cx="90" cy="85" rx="20" ry="6" fill="oklch(0.95 0.06 85 / 0.3)"/>
</svg>
<p class="absolute top-3.5 right-3.5 z-2 rounded-full border border-tfc13-amber/40 bg-black/70 px-3 py-1.5 text-base font-extrabold text-tfc13-amber backdrop-blur-md">$24</p>
</div>
<div class="flex flex-1 flex-col gap-2 p-5">
<p class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Italian · Pasta</p>
<h3 class="text-[22px] font-extrabold tracking-[-0.02em] text-tfc13-cream">Spaghetti al Ragu</h3>
<p class="text-[13px] leading-[1.6] text-tfc13-muted text-pretty">House-made spaghetti with slow-cooked Bolognese, fresh parmesan, and wild basil.</p>
<ul class="mt-1 flex flex-wrap gap-1.5">
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Medium spice</li>
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Chef's pick</li>
</ul>
<p class="mt-auto text-[10px] tracking-[0.08em] text-tfc13-dim">Hover, tap or press Space for ingredients & nutrition →</p>
</div>
</div>
<div class="absolute inset-0 flex translate-x-full flex-col gap-3 rounded-2xl overflow-hidden p-6 bg-linear-160 from-tfc13-back to-tfc13-back2 border border-tfc13-red/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-x-0 group-has-checked:translate-x-0 group-has-[:focus-visible]:translate-x-0 motion-reduce:transition-none">
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Key ingredients</h3>
<ul class="grid grid-cols-2 gap-1.5 text-xs text-tfc13-cream/75">
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Spaghetti pasta</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Beef mince (15%)</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">San Marzano tomato</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Parmigiano 24mo</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Soffritto base</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Fresh basil</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Dry white wine</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Extra virgin olive oil</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Allergens</h3>
<ul class="flex flex-wrap gap-1.5">
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Gluten</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Dairy</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Sulphites</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Nutrition per serving</h3>
<dl class="grid grid-cols-4 gap-1.5">
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">620</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">kcal</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">42g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Carbs</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">38g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Protein</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">22g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Fat</dt></div>
</dl>
<button type="button" class="relative z-30 mt-auto min-h-11 w-full rounded-xl bg-linear-135 from-tfc13-red to-tfc13-amber text-[13px] font-extrabold tracking-[0.04em] text-white transition-opacity duration-150 hover:opacity-90 focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2">Add to order — $24</button>
</div>
</div>
</section><section class="tfc-13 w-full min-h-svh grid place-items-center bg-tfc13-bg font-tfc13-sans px-5 py-10 text-tfc13-cream">
<div class="group relative w-[340px] max-w-full h-[470px] overflow-hidden rounded-2xl shadow-[0_1px_2px_oklch(0_0_0/0.5),0_22px_48px_-18px_oklch(0.3_0.08_50/0.7)] has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-tfc13-amber has-[:focus-visible]:outline-offset-4">
<input id="tfc-13-flip" type="checkbox" class="peer sr-only">
<label for="tfc-13-flip" class="absolute inset-0 z-20 cursor-pointer rounded-2xl"><span class="sr-only">Show ingredients, allergens and nutrition for Spaghetti al Ragu</span></label>
<div class="absolute inset-0 flex flex-col rounded-2xl overflow-hidden bg-tfc13-panel border border-tfc13-amber/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:-translate-x-full group-has-checked:-translate-x-full group-has-[:focus-visible]:-translate-x-full motion-reduce:transition-none">
<div class="relative grid h-55 shrink-0 place-items-center overflow-hidden bg-linear-160 from-tfc13-stage via-tfc13-stage2 to-tfc13-stage3 before:absolute before:inset-0 before:bg-[radial-gradient(circle_at_50%_60%,oklch(0.6_0.13_60/0.3),transparent_65%)]">
<svg class="relative z-1" width="180" height="160" viewBox="0 0 180 160" fill="none" role="img" aria-label="Illustration of a plate of spaghetti with meatballs, sauce and basil">
<ellipse cx="90" cy="110" rx="78" ry="30" fill="oklch(0.25 0.03 60 / 0.6)"/>
<ellipse cx="90" cy="105" rx="76" ry="28" fill="#2a1a08"/>
<ellipse cx="90" cy="103" rx="68" ry="24" fill="#1a0e04"/>
<path d="M55 95 Q70 80 85 95 Q100 110 115 95 Q130 80 125 95" stroke="oklch(0.65 0.14 65 / 0.8)" stroke-width="5" fill="none" stroke-linecap="round"/>
<path d="M60 100 Q75 85 90 100 Q105 115 120 100" stroke="oklch(0.58 0.12 55 / 0.7)" stroke-width="4" fill="none" stroke-linecap="round"/>
<path d="M65 90 Q80 75 95 90 Q110 105 125 90" stroke="oklch(0.75 0.15 70 / 0.6)" stroke-width="3" fill="none" stroke-linecap="round"/>
<circle cx="72" cy="88" r="14" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="72" cy="88" r="10" fill="oklch(0.52 0.1 50 / 0.8)"/>
<circle cx="108" cy="93" r="13" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="108" cy="93" r="9" fill="oklch(0.52 0.1 50 / 0.8)"/>
<ellipse cx="90" cy="95" rx="35" ry="12" fill="oklch(0.45 0.18 30 / 0.35)"/>
<circle cx="78" cy="76" r="3" fill="oklch(0.73 0.18 150 / 0.7)"/>
<circle cx="85" cy="74" r="2" fill="oklch(0.73 0.18 150 / 0.6)"/>
<circle cx="95" cy="78" r="2.5" fill="oklch(0.73 0.18 150 / 0.7)"/>
<ellipse cx="90" cy="85" rx="20" ry="6" fill="oklch(0.95 0.06 85 / 0.3)"/>
</svg>
<p class="absolute top-3.5 right-3.5 z-2 rounded-full border border-tfc13-amber/40 bg-black/70 px-3 py-1.5 text-base font-extrabold text-tfc13-amber backdrop-blur-md">$24</p>
</div>
<div class="flex flex-1 flex-col gap-2 p-5">
<p class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Italian · Pasta</p>
<h3 class="text-[22px] font-extrabold tracking-[-0.02em] text-tfc13-cream">Spaghetti al Ragu</h3>
<p class="text-[13px] leading-[1.6] text-tfc13-muted text-pretty">House-made spaghetti with slow-cooked Bolognese, fresh parmesan, and wild basil.</p>
<ul class="mt-1 flex flex-wrap gap-1.5">
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Medium spice</li>
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Chef's pick</li>
</ul>
<p class="mt-auto text-[10px] tracking-[0.08em] text-tfc13-dim">Hover, tap or press Space for ingredients & nutrition →</p>
</div>
</div>
<div class="absolute inset-0 flex translate-x-full flex-col gap-3 rounded-2xl overflow-hidden p-6 bg-linear-160 from-tfc13-back to-tfc13-back2 border border-tfc13-red/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-x-0 group-has-checked:translate-x-0 group-has-[:focus-visible]:translate-x-0 motion-reduce:transition-none">
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Key ingredients</h3>
<ul class="grid grid-cols-2 gap-1.5 text-xs text-tfc13-cream/75">
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Spaghetti pasta</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Beef mince (15%)</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">San Marzano tomato</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Parmigiano 24mo</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Soffritto base</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Fresh basil</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Dry white wine</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Extra virgin olive oil</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Allergens</h3>
<ul class="flex flex-wrap gap-1.5">
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Gluten</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Dairy</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Sulphites</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Nutrition per serving</h3>
<dl class="grid grid-cols-4 gap-1.5">
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">620</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">kcal</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">42g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Carbs</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">38g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Protein</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">22g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Fat</dt></div>
</dl>
<button type="button" class="relative z-30 mt-auto min-h-11 w-full rounded-xl bg-linear-135 from-tfc13-red to-tfc13-amber text-[13px] font-extrabold tracking-[0.04em] text-white transition-opacity duration-150 hover:opacity-90 focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2">Add to order — $24</button>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-tfc13-bg: #0c0400;
--color-tfc13-bg: oklch(0.13 0.02 45);
--color-tfc13-panel: #111008;
--color-tfc13-panel: oklch(0.17 0.015 80);
--color-tfc13-stage: #1a0800;
--color-tfc13-stage: oklch(0.18 0.05 45);
--color-tfc13-stage2: #2d1200;
--color-tfc13-stage2: oklch(0.24 0.07 50);
--color-tfc13-stage3: #0d0800;
--color-tfc13-stage3: oklch(0.14 0.02 60);
--color-tfc13-back: #0e0800;
--color-tfc13-back: oklch(0.15 0.02 60);
--color-tfc13-back2: #12090a;
--color-tfc13-back2: oklch(0.16 0.02 25);
--color-tfc13-red: #dc2626;
--color-tfc13-red: oklch(0.58 0.21 27);
--color-tfc13-amber: #d97706;
--color-tfc13-amber: oklch(0.68 0.16 60);
--color-tfc13-cream: #fef3c7;
--color-tfc13-cream: oklch(0.96 0.06 92);
--color-tfc13-muted: #c5b48d;
--color-tfc13-muted: oklch(0.79 0.05 90);
--color-tfc13-dim: #8e8265;
--color-tfc13-dim: oklch(0.63 0.03 90);
--font-tfc13-sans: 'Sora', system-ui, sans-serif;
}
.tfc-13 {
width: 100%;
min-height: 100svh;
}
@media (prefers-reduced-motion: reduce) {
.tfc-13 * {
transition-duration: 1ms !important;
}
}@import "tailwindcss";
@theme {
--color-tfc13-bg: #0c0400;
--color-tfc13-bg: oklch(0.13 0.02 45);
--color-tfc13-panel: #111008;
--color-tfc13-panel: oklch(0.17 0.015 80);
--color-tfc13-stage: #1a0800;
--color-tfc13-stage: oklch(0.18 0.05 45);
--color-tfc13-stage2: #2d1200;
--color-tfc13-stage2: oklch(0.24 0.07 50);
--color-tfc13-stage3: #0d0800;
--color-tfc13-stage3: oklch(0.14 0.02 60);
--color-tfc13-back: #0e0800;
--color-tfc13-back: oklch(0.15 0.02 60);
--color-tfc13-back2: #12090a;
--color-tfc13-back2: oklch(0.16 0.02 25);
--color-tfc13-red: #dc2626;
--color-tfc13-red: oklch(0.58 0.21 27);
--color-tfc13-amber: #d97706;
--color-tfc13-amber: oklch(0.68 0.16 60);
--color-tfc13-cream: #fef3c7;
--color-tfc13-cream: oklch(0.96 0.06 92);
--color-tfc13-muted: #c5b48d;
--color-tfc13-muted: oklch(0.79 0.05 90);
--color-tfc13-dim: #8e8265;
--color-tfc13-dim: oklch(0.63 0.03 90);
--font-tfc13-sans: 'Sora', system-ui, sans-serif;
}
.tfc-13 {
width: 100%;
min-height: 100svh;
}
@media (prefers-reduced-motion: reduce) {
.tfc-13 * {
transition-duration: 1ms !important;
}
}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-tfc13-bg: #0c0400;
--color-tfc13-bg: oklch(0.13 0.02 45);
--color-tfc13-panel: #111008;
--color-tfc13-panel: oklch(0.17 0.015 80);
--color-tfc13-stage: #1a0800;
--color-tfc13-stage: oklch(0.18 0.05 45);
--color-tfc13-stage2: #2d1200;
--color-tfc13-stage2: oklch(0.24 0.07 50);
--color-tfc13-stage3: #0d0800;
--color-tfc13-stage3: oklch(0.14 0.02 60);
--color-tfc13-back: #0e0800;
--color-tfc13-back: oklch(0.15 0.02 60);
--color-tfc13-back2: #12090a;
--color-tfc13-back2: oklch(0.16 0.02 25);
--color-tfc13-red: #dc2626;
--color-tfc13-red: oklch(0.58 0.21 27);
--color-tfc13-amber: #d97706;
--color-tfc13-amber: oklch(0.68 0.16 60);
--color-tfc13-cream: #fef3c7;
--color-tfc13-cream: oklch(0.96 0.06 92);
--color-tfc13-muted: #c5b48d;
--color-tfc13-muted: oklch(0.79 0.05 90);
--color-tfc13-dim: #8e8265;
--color-tfc13-dim: oklch(0.63 0.03 90);
--font-tfc13-sans: 'Sora', system-ui, sans-serif;
}
.tfc-13 {
width: 100%;
min-height: 100svh;
}
@media (prefers-reduced-motion: reduce) {
.tfc-13 * {
transition-duration: 1ms !important;
}
}@import "tailwindcss";
@theme {
--color-tfc13-bg: #0c0400;
--color-tfc13-bg: oklch(0.13 0.02 45);
--color-tfc13-panel: #111008;
--color-tfc13-panel: oklch(0.17 0.015 80);
--color-tfc13-stage: #1a0800;
--color-tfc13-stage: oklch(0.18 0.05 45);
--color-tfc13-stage2: #2d1200;
--color-tfc13-stage2: oklch(0.24 0.07 50);
--color-tfc13-stage3: #0d0800;
--color-tfc13-stage3: oklch(0.14 0.02 60);
--color-tfc13-back: #0e0800;
--color-tfc13-back: oklch(0.15 0.02 60);
--color-tfc13-back2: #12090a;
--color-tfc13-back2: oklch(0.16 0.02 25);
--color-tfc13-red: #dc2626;
--color-tfc13-red: oklch(0.58 0.21 27);
--color-tfc13-amber: #d97706;
--color-tfc13-amber: oklch(0.68 0.16 60);
--color-tfc13-cream: #fef3c7;
--color-tfc13-cream: oklch(0.96 0.06 92);
--color-tfc13-muted: #c5b48d;
--color-tfc13-muted: oklch(0.79 0.05 90);
--color-tfc13-dim: #8e8265;
--color-tfc13-dim: oklch(0.63 0.03 90);
--font-tfc13-sans: 'Sora', system-ui, sans-serif;
}
.tfc-13 {
width: 100%;
min-height: 100svh;
}
@media (prefers-reduced-motion: reduce) {
.tfc-13 * {
transition-duration: 1ms !important;
}
}<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=Sora:wght@400;600;700;800&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=Sora:wght@400;600;700;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Two sibling rules (
:hover .front,:hover .back) became two utility pairs on the faces themselves. The symmetry of the slide is now visible in the markup, which matters because a mismatched duration is the failure mode. - This is the demo that documents what
preserve-3dcosts you: with no 3D context,backdrop-blur-mdjust works. - UI change from the CSS original: allergens carry icon + text + border (not colour alone), ingredients and nutrition became
<ul>/<dl>, the dish SVG has a realaria-label, and the emoji chilli was replaced with the words "Medium spice".
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 Restaurant Menu Card with Sliding Ingredient & Nutrition Reveal
Source: https://codefronts.com/components/tailwind-css-flip-cards/tailwind-restaurant-menu-card-sliding-ingredient-nutrition/
The one card in the set with no 3D at all: the front slides out left while the back slides in from the right, like pulling a card from a file. It proves the pattern is about the reveal, not the rotation — and because there is no preserve-3d, the frosted price tag's backdrop-blur actually works, which it would not inside a 3D context in Firefox.
## HTML
```html
<section class="tfc-13 w-full min-h-svh grid place-items-center bg-tfc13-bg font-tfc13-sans px-5 py-10 text-tfc13-cream">
<div class="group relative w-[340px] max-w-full h-[470px] overflow-hidden rounded-2xl shadow-[0_1px_2px_oklch(0_0_0/0.5),0_22px_48px_-18px_oklch(0.3_0.08_50/0.7)] has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-tfc13-amber has-[:focus-visible]:outline-offset-4">
<input id="tfc-13-flip" type="checkbox" class="peer sr-only">
<label for="tfc-13-flip" class="absolute inset-0 z-20 cursor-pointer rounded-2xl"><span class="sr-only">Show ingredients, allergens and nutrition for Spaghetti al Ragu</span></label>
<div class="absolute inset-0 flex flex-col rounded-2xl overflow-hidden bg-tfc13-panel border border-tfc13-amber/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:-translate-x-full group-has-checked:-translate-x-full group-has-[:focus-visible]:-translate-x-full motion-reduce:transition-none">
<div class="relative grid h-55 shrink-0 place-items-center overflow-hidden bg-linear-160 from-tfc13-stage via-tfc13-stage2 to-tfc13-stage3 before:absolute before:inset-0 before:bg-[radial-gradient(circle_at_50%_60%,oklch(0.6_0.13_60/0.3),transparent_65%)]">
<svg class="relative z-1" width="180" height="160" viewBox="0 0 180 160" fill="none" role="img" aria-label="Illustration of a plate of spaghetti with meatballs, sauce and basil">
<ellipse cx="90" cy="110" rx="78" ry="30" fill="oklch(0.25 0.03 60 / 0.6)"/>
<ellipse cx="90" cy="105" rx="76" ry="28" fill="#2a1a08"/>
<ellipse cx="90" cy="103" rx="68" ry="24" fill="#1a0e04"/>
<path d="M55 95 Q70 80 85 95 Q100 110 115 95 Q130 80 125 95" stroke="oklch(0.65 0.14 65 / 0.8)" stroke-width="5" fill="none" stroke-linecap="round"/>
<path d="M60 100 Q75 85 90 100 Q105 115 120 100" stroke="oklch(0.58 0.12 55 / 0.7)" stroke-width="4" fill="none" stroke-linecap="round"/>
<path d="M65 90 Q80 75 95 90 Q110 105 125 90" stroke="oklch(0.75 0.15 70 / 0.6)" stroke-width="3" fill="none" stroke-linecap="round"/>
<circle cx="72" cy="88" r="14" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="72" cy="88" r="10" fill="oklch(0.52 0.1 50 / 0.8)"/>
<circle cx="108" cy="93" r="13" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="108" cy="93" r="9" fill="oklch(0.52 0.1 50 / 0.8)"/>
<ellipse cx="90" cy="95" rx="35" ry="12" fill="oklch(0.45 0.18 30 / 0.35)"/>
<circle cx="78" cy="76" r="3" fill="oklch(0.73 0.18 150 / 0.7)"/>
<circle cx="85" cy="74" r="2" fill="oklch(0.73 0.18 150 / 0.6)"/>
<circle cx="95" cy="78" r="2.5" fill="oklch(0.73 0.18 150 / 0.7)"/>
<ellipse cx="90" cy="85" rx="20" ry="6" fill="oklch(0.95 0.06 85 / 0.3)"/>
</svg>
<p class="absolute top-3.5 right-3.5 z-2 rounded-full border border-tfc13-amber/40 bg-black/70 px-3 py-1.5 text-base font-extrabold text-tfc13-amber backdrop-blur-md">$24</p>
</div>
<div class="flex flex-1 flex-col gap-2 p-5">
<p class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Italian · Pasta</p>
<h3 class="text-[22px] font-extrabold tracking-[-0.02em] text-tfc13-cream">Spaghetti al Ragu</h3>
<p class="text-[13px] leading-[1.6] text-tfc13-muted text-pretty">House-made spaghetti with slow-cooked Bolognese, fresh parmesan, and wild basil.</p>
<ul class="mt-1 flex flex-wrap gap-1.5">
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Medium spice</li>
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Chef's pick</li>
</ul>
<p class="mt-auto text-[10px] tracking-[0.08em] text-tfc13-dim">Hover, tap or press Space for ingredients & nutrition →</p>
</div>
</div>
<div class="absolute inset-0 flex translate-x-full flex-col gap-3 rounded-2xl overflow-hidden p-6 bg-linear-160 from-tfc13-back to-tfc13-back2 border border-tfc13-red/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-x-0 group-has-checked:translate-x-0 group-has-[:focus-visible]:translate-x-0 motion-reduce:transition-none">
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Key ingredients</h3>
<ul class="grid grid-cols-2 gap-1.5 text-xs text-tfc13-cream/75">
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Spaghetti pasta</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Beef mince (15%)</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">San Marzano tomato</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Parmigiano 24mo</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Soffritto base</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Fresh basil</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Dry white wine</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Extra virgin olive oil</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Allergens</h3>
<ul class="flex flex-wrap gap-1.5">
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Gluten</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Dairy</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Sulphites</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Nutrition per serving</h3>
<dl class="grid grid-cols-4 gap-1.5">
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">620</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">kcal</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">42g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Carbs</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">38g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Protein</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">22g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Fat</dt></div>
</dl>
<button type="button" class="relative z-30 mt-auto min-h-11 w-full rounded-xl bg-linear-135 from-tfc13-red to-tfc13-amber text-[13px] font-extrabold tracking-[0.04em] text-white transition-opacity duration-150 hover:opacity-90 focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2">Add to order — $24</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfc13-bg: #0c0400;
--color-tfc13-bg: oklch(0.13 0.02 45);
--color-tfc13-panel: #111008;
--color-tfc13-panel: oklch(0.17 0.015 80);
--color-tfc13-stage: #1a0800;
--color-tfc13-stage: oklch(0.18 0.05 45);
--color-tfc13-stage2: #2d1200;
--color-tfc13-stage2: oklch(0.24 0.07 50);
--color-tfc13-stage3: #0d0800;
--color-tfc13-stage3: oklch(0.14 0.02 60);
--color-tfc13-back: #0e0800;
--color-tfc13-back: oklch(0.15 0.02 60);
--color-tfc13-back2: #12090a;
--color-tfc13-back2: oklch(0.16 0.02 25);
--color-tfc13-red: #dc2626;
--color-tfc13-red: oklch(0.58 0.21 27);
--color-tfc13-amber: #d97706;
--color-tfc13-amber: oklch(0.68 0.16 60);
--color-tfc13-cream: #fef3c7;
--color-tfc13-cream: oklch(0.96 0.06 92);
--color-tfc13-muted: #c5b48d;
--color-tfc13-muted: oklch(0.79 0.05 90);
--color-tfc13-dim: #8e8265;
--color-tfc13-dim: oklch(0.63 0.03 90);
--font-tfc13-sans: 'Sora', system-ui, sans-serif;
}
.tfc-13 {
width: 100%;
min-height: 100svh;
}
@media (prefers-reduced-motion: reduce) {
.tfc-13 * {
transition-duration: 1ms !important;
}
}
```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 Restaurant Menu Card with Sliding Ingredient & Nutrition Reveal
Source: https://codefronts.com/components/tailwind-css-flip-cards/tailwind-restaurant-menu-card-sliding-ingredient-nutrition/
The one card in the set with no 3D at all: the front slides out left while the back slides in from the right, like pulling a card from a file. It proves the pattern is about the reveal, not the rotation — and because there is no preserve-3d, the frosted price tag's backdrop-blur actually works, which it would not inside a 3D context in Firefox.
## HTML
```html
<section class="tfc-13 w-full min-h-svh grid place-items-center bg-tfc13-bg font-tfc13-sans px-5 py-10 text-tfc13-cream">
<div class="group relative w-[340px] max-w-full h-[470px] overflow-hidden rounded-2xl shadow-[0_1px_2px_oklch(0_0_0/0.5),0_22px_48px_-18px_oklch(0.3_0.08_50/0.7)] has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-tfc13-amber has-[:focus-visible]:outline-offset-4">
<input id="tfc-13-flip" type="checkbox" class="peer sr-only">
<label for="tfc-13-flip" class="absolute inset-0 z-20 cursor-pointer rounded-2xl"><span class="sr-only">Show ingredients, allergens and nutrition for Spaghetti al Ragu</span></label>
<div class="absolute inset-0 flex flex-col rounded-2xl overflow-hidden bg-tfc13-panel border border-tfc13-amber/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:-translate-x-full group-has-checked:-translate-x-full group-has-[:focus-visible]:-translate-x-full motion-reduce:transition-none">
<div class="relative grid h-55 shrink-0 place-items-center overflow-hidden bg-linear-160 from-tfc13-stage via-tfc13-stage2 to-tfc13-stage3 before:absolute before:inset-0 before:bg-[radial-gradient(circle_at_50%_60%,oklch(0.6_0.13_60/0.3),transparent_65%)]">
<svg class="relative z-1" width="180" height="160" viewBox="0 0 180 160" fill="none" role="img" aria-label="Illustration of a plate of spaghetti with meatballs, sauce and basil">
<ellipse cx="90" cy="110" rx="78" ry="30" fill="oklch(0.25 0.03 60 / 0.6)"/>
<ellipse cx="90" cy="105" rx="76" ry="28" fill="#2a1a08"/>
<ellipse cx="90" cy="103" rx="68" ry="24" fill="#1a0e04"/>
<path d="M55 95 Q70 80 85 95 Q100 110 115 95 Q130 80 125 95" stroke="oklch(0.65 0.14 65 / 0.8)" stroke-width="5" fill="none" stroke-linecap="round"/>
<path d="M60 100 Q75 85 90 100 Q105 115 120 100" stroke="oklch(0.58 0.12 55 / 0.7)" stroke-width="4" fill="none" stroke-linecap="round"/>
<path d="M65 90 Q80 75 95 90 Q110 105 125 90" stroke="oklch(0.75 0.15 70 / 0.6)" stroke-width="3" fill="none" stroke-linecap="round"/>
<circle cx="72" cy="88" r="14" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="72" cy="88" r="10" fill="oklch(0.52 0.1 50 / 0.8)"/>
<circle cx="108" cy="93" r="13" fill="oklch(0.45 0.1 50 / 0.85)"/>
<circle cx="108" cy="93" r="9" fill="oklch(0.52 0.1 50 / 0.8)"/>
<ellipse cx="90" cy="95" rx="35" ry="12" fill="oklch(0.45 0.18 30 / 0.35)"/>
<circle cx="78" cy="76" r="3" fill="oklch(0.73 0.18 150 / 0.7)"/>
<circle cx="85" cy="74" r="2" fill="oklch(0.73 0.18 150 / 0.6)"/>
<circle cx="95" cy="78" r="2.5" fill="oklch(0.73 0.18 150 / 0.7)"/>
<ellipse cx="90" cy="85" rx="20" ry="6" fill="oklch(0.95 0.06 85 / 0.3)"/>
</svg>
<p class="absolute top-3.5 right-3.5 z-2 rounded-full border border-tfc13-amber/40 bg-black/70 px-3 py-1.5 text-base font-extrabold text-tfc13-amber backdrop-blur-md">$24</p>
</div>
<div class="flex flex-1 flex-col gap-2 p-5">
<p class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Italian · Pasta</p>
<h3 class="text-[22px] font-extrabold tracking-[-0.02em] text-tfc13-cream">Spaghetti al Ragu</h3>
<p class="text-[13px] leading-[1.6] text-tfc13-muted text-pretty">House-made spaghetti with slow-cooked Bolognese, fresh parmesan, and wild basil.</p>
<ul class="mt-1 flex flex-wrap gap-1.5">
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Medium spice</li>
<li class="rounded-full border border-tfc13-red/20 bg-tfc13-red/10 px-2.5 py-0.5 text-[10px] text-tfc13-cream/75">Chef's pick</li>
</ul>
<p class="mt-auto text-[10px] tracking-[0.08em] text-tfc13-dim">Hover, tap or press Space for ingredients & nutrition →</p>
</div>
</div>
<div class="absolute inset-0 flex translate-x-full flex-col gap-3 rounded-2xl overflow-hidden p-6 bg-linear-160 from-tfc13-back to-tfc13-back2 border border-tfc13-red/20 transition-transform duration-[550ms] ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-x-0 group-has-checked:translate-x-0 group-has-[:focus-visible]:translate-x-0 motion-reduce:transition-none">
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Key ingredients</h3>
<ul class="grid grid-cols-2 gap-1.5 text-xs text-tfc13-cream/75">
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Spaghetti pasta</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Beef mince (15%)</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">San Marzano tomato</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Parmigiano 24mo</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Soffritto base</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Fresh basil</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Dry white wine</li>
<li class="flex items-center gap-2 before:size-1.5 before:shrink-0 before:rounded-full before:bg-tfc13-amber">Extra virgin olive oil</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Allergens</h3>
<ul class="flex flex-wrap gap-1.5">
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Gluten</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Dairy</li>
<li class="flex items-center gap-1 rounded-md border border-tfc13-red/35 bg-tfc13-red/10 px-2 py-1 text-[10px] font-semibold text-tfc13-cream/80"><span aria-hidden="true">⚠</span>Sulphites</li>
</ul>
<h3 class="text-[10px] font-bold uppercase tracking-[0.15em] text-tfc13-amber">Nutrition per serving</h3>
<dl class="grid grid-cols-4 gap-1.5">
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">620</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">kcal</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">42g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Carbs</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">38g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Protein</dt></div>
<div class="rounded-lg border border-white/7 bg-white/4 px-1 py-2 text-center"><dd class="text-[15px] font-extrabold text-tfc13-cream">22g</dd><dt class="mt-0.5 text-[9px] uppercase tracking-[0.08em] text-tfc13-dim">Fat</dt></div>
</dl>
<button type="button" class="relative z-30 mt-auto min-h-11 w-full rounded-xl bg-linear-135 from-tfc13-red to-tfc13-amber text-[13px] font-extrabold tracking-[0.04em] text-white transition-opacity duration-150 hover:opacity-90 focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2">Add to order — $24</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tfc13-bg: #0c0400;
--color-tfc13-bg: oklch(0.13 0.02 45);
--color-tfc13-panel: #111008;
--color-tfc13-panel: oklch(0.17 0.015 80);
--color-tfc13-stage: #1a0800;
--color-tfc13-stage: oklch(0.18 0.05 45);
--color-tfc13-stage2: #2d1200;
--color-tfc13-stage2: oklch(0.24 0.07 50);
--color-tfc13-stage3: #0d0800;
--color-tfc13-stage3: oklch(0.14 0.02 60);
--color-tfc13-back: #0e0800;
--color-tfc13-back: oklch(0.15 0.02 60);
--color-tfc13-back2: #12090a;
--color-tfc13-back2: oklch(0.16 0.02 25);
--color-tfc13-red: #dc2626;
--color-tfc13-red: oklch(0.58 0.21 27);
--color-tfc13-amber: #d97706;
--color-tfc13-amber: oklch(0.68 0.16 60);
--color-tfc13-cream: #fef3c7;
--color-tfc13-cream: oklch(0.96 0.06 92);
--color-tfc13-muted: #c5b48d;
--color-tfc13-muted: oklch(0.79 0.05 90);
--color-tfc13-dim: #8e8265;
--color-tfc13-dim: oklch(0.63 0.03 90);
--font-tfc13-sans: 'Sora', system-ui, sans-serif;
}
.tfc-13 {
width: 100%;
min-height: 100svh;
}
@media (prefers-reduced-motion: reduce) {
.tfc-13 * {
transition-duration: 1ms !important;
}
}
```How this works
No rotation, no 3D context, no constraints. The two faces are absolutely positioned siblings translated on X. Everything that is illegal inside preserve-3d — filters, backdrop filters, heavy shadows — is fine here, which is exactly why this variant exists in the collection.
Allergens use three channels. A warning glyph, the word itself, and a red-tinted border. Colour alone fails for 8% of men; in a food-service context that is not an academic concern.
The slide is symmetric. Both faces share one duration and one curve, so the outgoing and incoming edges stay locked together — a 50ms mismatch reads as a glitch rather than a transition.
Make it yours
- Direction: swap
-translate-x-full/translate-x-fullfor the Y pair and the card becomes a vertical drawer. - Cuisine palette lives in
--color-tfc13-amberand--color-tfc13-red; an indigo/white pair reads as sushi. - Portion toggle: add a second checkbox and drive price and nutrition values with
has-checked:variants. - Dietary badges sit in the same flex row as the spice level; add V or GF pills there.
Gotchas — read before shipping
backdrop-blurinside apreserve-3dsubtree is dropped by Firefox. It works here only because this demo has no 3D — do not copy the price tag into a rotating card without a solid fallback.- Both faces need
overflow-hiddenon the SCENE, not on themselves, or the outgoing face is visible beside the card mid-slide. - Allergen data is a legal matter in food service. This is a UI pattern, not a compliance solution.
- Stroke-based SVG food art prints as hairlines. Bump
stroke-widthin a print block if the menu goes to paper.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
backdrop-filter needs Firefox 103+. Translation transitions are universal.