15 / 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 Stacked Cards Lift on Hover Sibling Push
The parting-of-the-waters stack: hover a card and every card below it slides down. This is the demo where Tailwind runs out of variants — there is no hover ~ sibling family — so the whole effect rides one arbitrary variant, [&:hover~*]:translate-y-[30px], typed on each card. Worth knowing precisely because it is the exception rather than the rule.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="stk-15 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk15-sans bg-stk15-bg" aria-label="Cascade-lift card stack">
<div class="w-[min(320px,100%)]">
<a class="flex flex-col gap-1.25 -mt-4 first:mt-0 rounded-2xl bg-stk15-c1 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Espresso</b>
<span class="font-stk15-mono text-[13px] opacity-90">Single origin · 30 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c2 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cortado</b>
<span class="font-stk15-mono text-[13px] opacity-90">Equal parts · 90 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c3 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Flat white</b>
<span class="font-stk15-mono text-[13px] opacity-90">Micro-foam · 160 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c4 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cold brew</b>
<span class="font-stk15-mono text-[13px] opacity-90">18 h steep · 240 ml</span>
</a>
</div>
</section><section class="stk-15 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk15-sans bg-stk15-bg" aria-label="Cascade-lift card stack">
<div class="w-[min(320px,100%)]">
<a class="flex flex-col gap-1.25 -mt-4 first:mt-0 rounded-2xl bg-stk15-c1 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Espresso</b>
<span class="font-stk15-mono text-[13px] opacity-90">Single origin · 30 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c2 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cortado</b>
<span class="font-stk15-mono text-[13px] opacity-90">Equal parts · 90 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c3 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Flat white</b>
<span class="font-stk15-mono text-[13px] opacity-90">Micro-foam · 160 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c4 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cold brew</b>
<span class="font-stk15-mono text-[13px] opacity-90">18 h steep · 240 ml</span>
</a>
</div>
</section>@import "tailwindcss";
@theme {
--color-stk15-bg: #161310;
--color-stk15-bg: oklch(0.20 0.012 60);
--color-stk15-c1: #cf5f4b;
--color-stk15-c1: oklch(0.62 0.16 20);
--color-stk15-c2: #bd7440;
--color-stk15-c2: oklch(0.60 0.14 50);
--color-stk15-c3: #a38434;
--color-stk15-c3: oklch(0.58 0.12 80);
--color-stk15-c4: #859030;
--color-stk15-c4: oklch(0.58 0.10 110);
--font-stk15-sans: 'Archivo', system-ui, sans-serif;
--font-stk15-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk15: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk15-bg: #161310;
--color-stk15-bg: oklch(0.20 0.012 60);
--color-stk15-c1: #cf5f4b;
--color-stk15-c1: oklch(0.62 0.16 20);
--color-stk15-c2: #bd7440;
--color-stk15-c2: oklch(0.60 0.14 50);
--color-stk15-c3: #a38434;
--color-stk15-c3: oklch(0.58 0.12 80);
--color-stk15-c4: #859030;
--color-stk15-c4: oklch(0.58 0.10 110);
--font-stk15-sans: 'Archivo', system-ui, sans-serif;
--font-stk15-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk15: 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-stk15-bg: #161310;
--color-stk15-bg: oklch(0.20 0.012 60);
--color-stk15-c1: #cf5f4b;
--color-stk15-c1: oklch(0.62 0.16 20);
--color-stk15-c2: #bd7440;
--color-stk15-c2: oklch(0.60 0.14 50);
--color-stk15-c3: #a38434;
--color-stk15-c3: oklch(0.58 0.12 80);
--color-stk15-c4: #859030;
--color-stk15-c4: oklch(0.58 0.10 110);
--font-stk15-sans: 'Archivo', system-ui, sans-serif;
--font-stk15-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk15: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk15-bg: #161310;
--color-stk15-bg: oklch(0.20 0.012 60);
--color-stk15-c1: #cf5f4b;
--color-stk15-c1: oklch(0.62 0.16 20);
--color-stk15-c2: #bd7440;
--color-stk15-c2: oklch(0.60 0.14 50);
--color-stk15-c3: #a38434;
--color-stk15-c3: oklch(0.58 0.12 80);
--color-stk15-c4: #859030;
--color-stk15-c4: oklch(0.58 0.10 110);
--font-stk15-sans: 'Archivo', system-ui, sans-serif;
--font-stk15-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk15: 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,800&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,800&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 collection's one arbitrary variant:
[&:hover~*]:translate-y-[30px]. Tailwind covers self, ancestor and earlier-sibling state, but not ‘me hovered, later siblings styled’. - A
groupcannot substitute. The parent would know that something is hovered but not which card, and the whole effect depends on which. - The keyboard twin needs its own arbitrary variant too —
[&:focus-visible~*]:— and forgetting it is invisible to anyone testing with a mouse. - The stack stays in normal document flow, so unlike the absolute stacks here it needs no fixed height and reflows freely at narrow widths.
- The lift is a transform and the overlap is a margin: the margin is static, the transform is animated, and the column never relayouts mid-hover.
motion-reduce:transition-[box-shadow]keeps the depth response and removes the movement, rather than slowing it down.
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 Stacked Cards Lift on Hover Sibling Push
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-stacked-cards-lift-on-hover-sibling-push/
The parting-of-the-waters stack: hover a card and every card below it slides down. This is the demo where Tailwind runs out of variants — there is no hover ~ sibling family — so the whole effect rides one arbitrary variant, [&:hover~*]:translate-y-[30px], typed on each card. Worth knowing precisely because it is the exception rather than the rule.
## HTML
```html
<section class="stk-15 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk15-sans bg-stk15-bg" aria-label="Cascade-lift card stack">
<div class="w-[min(320px,100%)]">
<a class="flex flex-col gap-1.25 -mt-4 first:mt-0 rounded-2xl bg-stk15-c1 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Espresso</b>
<span class="font-stk15-mono text-[13px] opacity-90">Single origin · 30 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c2 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cortado</b>
<span class="font-stk15-mono text-[13px] opacity-90">Equal parts · 90 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c3 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Flat white</b>
<span class="font-stk15-mono text-[13px] opacity-90">Micro-foam · 160 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c4 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cold brew</b>
<span class="font-stk15-mono text-[13px] opacity-90">18 h steep · 240 ml</span>
</a>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk15-bg: #161310;
--color-stk15-bg: oklch(0.20 0.012 60);
--color-stk15-c1: #cf5f4b;
--color-stk15-c1: oklch(0.62 0.16 20);
--color-stk15-c2: #bd7440;
--color-stk15-c2: oklch(0.60 0.14 50);
--color-stk15-c3: #a38434;
--color-stk15-c3: oklch(0.58 0.12 80);
--color-stk15-c4: #859030;
--color-stk15-c4: oklch(0.58 0.10 110);
--font-stk15-sans: 'Archivo', system-ui, sans-serif;
--font-stk15-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk15: 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 Stacked Cards Lift on Hover Sibling Push
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-stacked-cards-lift-on-hover-sibling-push/
The parting-of-the-waters stack: hover a card and every card below it slides down. This is the demo where Tailwind runs out of variants — there is no hover ~ sibling family — so the whole effect rides one arbitrary variant, [&:hover~*]:translate-y-[30px], typed on each card. Worth knowing precisely because it is the exception rather than the rule.
## HTML
```html
<section class="stk-15 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk15-sans bg-stk15-bg" aria-label="Cascade-lift card stack">
<div class="w-[min(320px,100%)]">
<a class="flex flex-col gap-1.25 -mt-4 first:mt-0 rounded-2xl bg-stk15-c1 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Espresso</b>
<span class="font-stk15-mono text-[13px] opacity-90">Single origin · 30 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c2 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cortado</b>
<span class="font-stk15-mono text-[13px] opacity-90">Equal parts · 90 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c3 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Flat white</b>
<span class="font-stk15-mono text-[13px] opacity-90">Micro-foam · 160 ml</span>
</a>
<a class="flex flex-col gap-1.25 -mt-4 rounded-2xl bg-stk15-c4 px-6 py-5 text-white no-underline shadow-[0_14px_30px_-18px_rgba(0,0,0,0.8)] transition-[transform,box-shadow] duration-350 ease-stk15 hover:z-5 hover:-translate-y-[18px] hover:scale-[1.03] hover:shadow-[0_26px_44px_-20px_rgba(0,0,0,0.9)] focus-visible:z-5 focus-visible:outline-none focus-visible:-translate-y-[18px] focus-visible:scale-[1.03] focus-visible:shadow-[0_0_0_3px_#fff,0_26px_44px_-20px_rgba(0,0,0,0.9)] [&:hover~*]:translate-y-[30px] [&:focus-visible~*]:translate-y-[30px] motion-reduce:transition-[box-shadow]" href="#">
<b class="text-lg font-extrabold tracking-[-0.02em]">Cold brew</b>
<span class="font-stk15-mono text-[13px] opacity-90">18 h steep · 240 ml</span>
</a>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk15-bg: #161310;
--color-stk15-bg: oklch(0.20 0.012 60);
--color-stk15-c1: #cf5f4b;
--color-stk15-c1: oklch(0.62 0.16 20);
--color-stk15-c2: #bd7440;
--color-stk15-c2: oklch(0.60 0.14 50);
--color-stk15-c3: #a38434;
--color-stk15-c3: oklch(0.58 0.12 80);
--color-stk15-c4: #859030;
--color-stk15-c4: oklch(0.58 0.10 110);
--font-stk15-sans: 'Archivo', system-ui, sans-serif;
--font-stk15-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk15: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```How this works
Where utilities stop. Tailwind's variants describe an element's own state (hover:), an ancestor's (group-hover:) or an earlier sibling's (peer-*). What this pattern needs is the opposite direction: this element hovered, styling later siblings. That is &:hover ~ *, and the arbitrary-variant syntax is the honest way to say it:
class="… [&:hover~*]:translate-y-[30px]
[&:focus-visible~*]:translate-y-[30px]"Every card carries it, so any card hovered pushes everything after it. One class does what a .card:hover ~ .card rule does, and it is the only construct in the collection that reaches for a raw selector.
Why not a group? Wrapping in a group would let the parent know something is hovered, but not which card — and the whole effect depends on which. This is a case where the sibling combinator is not a stylistic preference; it is the mechanism.
Flow, not absolute. The cards overlap with a negative top margin and stay in normal flow, which is why this stack needs no fixed height, wraps happily at narrow widths, and never clips.
Make it yours
- Change the overlap with
-mt-4; keep the resting peek taller than the card's padding or the top edges stop being hoverable. - Set how far the lower cards move with the
30pxin the arbitrary variant. - Adjust the lift with
hover:-translate-y-[18px] hover:scale-[1.03]. - Recolour per item — each card carries its own
bg-stk15-*token, walking one hue ramp. - Add items freely; the sibling variant has no index and does not care how many there are.
Gotchas — read before shipping
- It must be
~, not+. The adjacent-sibling combinator moves only the next card and the parting collapses. - Include the
:focus-visibletwin. Hover-only means a keyboard user gets the lift with none of the space it needs. - Arbitrary variants are an escape hatch, not a habit. If a built-in variant covers your case, use it — raw selectors do not get the compiler's checking.
- Keep enough peek that every card is hoverable, including the ones under the lifted card.
hover:z-5is needed because the lifted card overlaps the one above it as well as the one below.- Do not animate
marginhere. The lift is a transform so it stays on the compositor; margin would relayout the column on every hover.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
The general-sibling combinator and transforms are universal (Chrome 49+, Safari 10+, Firefox 52+). The floor is Tailwind v4's own generated sheet.