13 / 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 Staircase Offset Stacked Cards Cascade
A strict stair-step cascade where one uniform corner of every card stays visible. The whole staircase is a single expression — [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] with [z-index:calc(var(--i)+1)] — and hovering adds a lateral offset to the same expression, so the step slides out along its own diagonal rather than jumping off it.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="stk-13 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk13-sans bg-stk13-bg" aria-label="Staircase cascade of cards">
<div class="relative w-65 h-70">
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c1 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:0">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Plan</b>
<span class="font-stk13-mono text-[13px] opacity-90">Scope & milestones</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c2 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:1">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Design</b>
<span class="font-stk13-mono text-[13px] opacity-90">Flows & system</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c3 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:2">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Build</b>
<span class="font-stk13-mono text-[13px] opacity-90">Ship in slices</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c4 p-5 text-stk13-dark no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:3">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Launch</b>
<span class="font-stk13-mono text-[13px] opacity-80">Measure & iterate</span>
</a>
</div>
</section><section class="stk-13 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk13-sans bg-stk13-bg" aria-label="Staircase cascade of cards">
<div class="relative w-65 h-70">
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c1 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:0">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Plan</b>
<span class="font-stk13-mono text-[13px] opacity-90">Scope & milestones</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c2 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:1">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Design</b>
<span class="font-stk13-mono text-[13px] opacity-90">Flows & system</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c3 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:2">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Build</b>
<span class="font-stk13-mono text-[13px] opacity-90">Ship in slices</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c4 p-5 text-stk13-dark no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:3">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Launch</b>
<span class="font-stk13-mono text-[13px] opacity-80">Measure & iterate</span>
</a>
</div>
</section>@import "tailwindcss";
@theme {
--color-stk13-bg: #12141c;
--color-stk13-bg: oklch(0.21 0.014 275);
--color-stk13-dark: #1a1508;
--color-stk13-dark: oklch(0.24 0.030 85);
--color-stk13-c1: #5f7ae0;
--color-stk13-c1: oklch(0.60 0.16 265);
--color-stk13-c2: #4a94cc;
--color-stk13-c2: oklch(0.62 0.15 210);
--color-stk13-c3: #3fae8c;
--color-stk13-c3: oklch(0.64 0.15 160);
--color-stk13-c4: #d0b23a;
--color-stk13-c4: oklch(0.78 0.16 90);
--font-stk13-sans: 'Archivo', system-ui, sans-serif;
--font-stk13-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk13: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk13-bg: #12141c;
--color-stk13-bg: oklch(0.21 0.014 275);
--color-stk13-dark: #1a1508;
--color-stk13-dark: oklch(0.24 0.030 85);
--color-stk13-c1: #5f7ae0;
--color-stk13-c1: oklch(0.60 0.16 265);
--color-stk13-c2: #4a94cc;
--color-stk13-c2: oklch(0.62 0.15 210);
--color-stk13-c3: #3fae8c;
--color-stk13-c3: oklch(0.64 0.15 160);
--color-stk13-c4: #d0b23a;
--color-stk13-c4: oklch(0.78 0.16 90);
--font-stk13-sans: 'Archivo', system-ui, sans-serif;
--font-stk13-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk13: 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-stk13-bg: #12141c;
--color-stk13-bg: oklch(0.21 0.014 275);
--color-stk13-dark: #1a1508;
--color-stk13-dark: oklch(0.24 0.030 85);
--color-stk13-c1: #5f7ae0;
--color-stk13-c1: oklch(0.60 0.16 265);
--color-stk13-c2: #4a94cc;
--color-stk13-c2: oklch(0.62 0.15 210);
--color-stk13-c3: #3fae8c;
--color-stk13-c3: oklch(0.64 0.15 160);
--color-stk13-c4: #d0b23a;
--color-stk13-c4: oklch(0.78 0.16 90);
--font-stk13-sans: 'Archivo', system-ui, sans-serif;
--font-stk13-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk13: cubic-bezier(0.3, 0.9, 0.3, 1);
}@import "tailwindcss";
@theme {
--color-stk13-bg: #12141c;
--color-stk13-bg: oklch(0.21 0.014 275);
--color-stk13-dark: #1a1508;
--color-stk13-dark: oklch(0.24 0.030 85);
--color-stk13-c1: #5f7ae0;
--color-stk13-c1: oklch(0.60 0.16 265);
--color-stk13-c2: #4a94cc;
--color-stk13-c2: oklch(0.62 0.15 210);
--color-stk13-c3: #3fae8c;
--color-stk13-c3: oklch(0.64 0.15 160);
--color-stk13-c4: #d0b23a;
--color-stk13-c4: oklch(0.78 0.16 90);
--font-stk13-sans: 'Archivo', system-ui, sans-serif;
--font-stk13-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk13: 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. - Offset and stacking order come from the same
--i, so a step cannot be positioned as one rank and layered as another. - The hover transform extends the resting
calc()rather than replacing it with fixed numbers, which is what lets one class serve every step. [z-index:calc(var(--i)+1)]is another case with no utility equivalent — the scale is integers, not expressions.- The final step's fill is light enough that its text switches to
text-stk13-dark; contrast is per-card here, not a global choice. motion-reduce:transition-[box-shadow]narrows the transition rather than killing it — the depth cue survives, the sliding does not.- Cards are
<a>elements because the cascade is a real four-destination list, and links need notabindex, noroleand no key handling.
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 Staircase Offset Stacked Cards Cascade
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-staircase-offset-stacked-cards-cascade/
A strict stair-step cascade where one uniform corner of every card stays visible. The whole staircase is a single expression — [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] with [z-index:calc(var(--i)+1)] — and hovering adds a lateral offset to the same expression, so the step slides out along its own diagonal rather than jumping off it.
## HTML
```html
<section class="stk-13 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk13-sans bg-stk13-bg" aria-label="Staircase cascade of cards">
<div class="relative w-65 h-70">
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c1 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:0">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Plan</b>
<span class="font-stk13-mono text-[13px] opacity-90">Scope & milestones</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c2 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:1">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Design</b>
<span class="font-stk13-mono text-[13px] opacity-90">Flows & system</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c3 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:2">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Build</b>
<span class="font-stk13-mono text-[13px] opacity-90">Ship in slices</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c4 p-5 text-stk13-dark no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:3">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Launch</b>
<span class="font-stk13-mono text-[13px] opacity-80">Measure & iterate</span>
</a>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk13-bg: #12141c;
--color-stk13-bg: oklch(0.21 0.014 275);
--color-stk13-dark: #1a1508;
--color-stk13-dark: oklch(0.24 0.030 85);
--color-stk13-c1: #5f7ae0;
--color-stk13-c1: oklch(0.60 0.16 265);
--color-stk13-c2: #4a94cc;
--color-stk13-c2: oklch(0.62 0.15 210);
--color-stk13-c3: #3fae8c;
--color-stk13-c3: oklch(0.64 0.15 160);
--color-stk13-c4: #d0b23a;
--color-stk13-c4: oklch(0.78 0.16 90);
--font-stk13-sans: 'Archivo', system-ui, sans-serif;
--font-stk13-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk13: 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 Staircase Offset Stacked Cards Cascade
Source: https://codefronts.com/components/tailwind-stacked-cards/tailwind-staircase-offset-stacked-cards-cascade/
A strict stair-step cascade where one uniform corner of every card stays visible. The whole staircase is a single expression — [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] with [z-index:calc(var(--i)+1)] — and hovering adds a lateral offset to the same expression, so the step slides out along its own diagonal rather than jumping off it.
## HTML
```html
<section class="stk-13 w-full min-h-svh flex items-center justify-center px-5 py-15 font-stk13-sans bg-stk13-bg" aria-label="Staircase cascade of cards">
<div class="relative w-65 h-70">
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c1 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:0">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Plan</b>
<span class="font-stk13-mono text-[13px] opacity-90">Scope & milestones</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c2 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:1">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Design</b>
<span class="font-stk13-mono text-[13px] opacity-90">Flows & system</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c3 p-5 text-white no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:2">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Build</b>
<span class="font-stk13-mono text-[13px] opacity-90">Ship in slices</span>
</a>
<a class="absolute left-0 top-0 flex h-30 w-47.5 flex-col gap-1.5 rounded-2xl bg-stk13-c4 p-5 text-stk13-dark no-underline shadow-[0_18px_34px_-20px_rgba(0,0,0,0.8)] [transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))] [z-index:calc(var(--i)+1)] transition-[transform,box-shadow] duration-350 ease-stk13 hover:z-20 hover:shadow-[0_28px_48px_-20px_rgba(0,0,0,0.9)] hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] focus-visible:z-20 focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#fff,0_28px_48px_-20px_rgba(0,0,0,0.9)] focus-visible:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))] motion-reduce:transition-[box-shadow]" href="#" style="--i:3">
<b class="text-[19px] font-extrabold tracking-[-0.02em]">Launch</b>
<span class="font-stk13-mono text-[13px] opacity-80">Measure & iterate</span>
</a>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-stk13-bg: #12141c;
--color-stk13-bg: oklch(0.21 0.014 275);
--color-stk13-dark: #1a1508;
--color-stk13-dark: oklch(0.24 0.030 85);
--color-stk13-c1: #5f7ae0;
--color-stk13-c1: oklch(0.60 0.16 265);
--color-stk13-c2: #4a94cc;
--color-stk13-c2: oklch(0.62 0.15 210);
--color-stk13-c3: #3fae8c;
--color-stk13-c3: oklch(0.64 0.15 160);
--color-stk13-c4: #d0b23a;
--color-stk13-c4: oklch(0.78 0.16 90);
--font-stk13-sans: 'Archivo', system-ui, sans-serif;
--font-stk13-mono: 'JetBrains Mono', ui-monospace, monospace;
--ease-stk13: cubic-bezier(0.3, 0.9, 0.3, 1);
}
```How this works
The staircase is arithmetic. One rule's worth of value, on every card:
[transform:translate(calc(var(--i)*24px),calc(var(--i)*46px))]
[z-index:calc(var(--i)+1)]Because both the offset and the stacking order come from the same index, a card cannot end up positioned as step three and layered as step one — a class of bug that index-per-rule CSS invites.
Hover extends rather than overrides. The raised state keeps the index terms and adds to them:
hover:[transform:translate(calc(var(--i)*24px+40px),calc(var(--i)*46px-8px))]The card therefore slides out from wherever it sits, and the same class works for step one and step four. Writing fixed pixel destinations instead would need four hover rules and would break the moment the step size changed.
Cards are links. The stair is a process with four destinations, so each step is an <a>: focusable, announceable, and operable with no tabindex.
Make it yours
- Change the step size via the
24pxand46pxmultipliers — both hover states follow automatically. - Reverse the cascade by negating the multipliers;
z-indexstill tracks the index correctly. - Change which corner peeks by adjusting the vertical multiplier relative to the card height.
- Add a step by copying one
<a>with the next--iand a colour token. - Slide the card the other way by flipping the
+40pxto-40pxin the hover transform.
Gotchas — read before shipping
- Derive
z-indexfrom the same index as the offset. Two independent sources of truth for depth eventually disagree. - Leave a consistent peek. If the vertical step is smaller than the card's padding, some steps become unclickable.
- The hover transform must extend the resting calc, not replace it — hard-coded destinations only work for one step.
- Give the stage the full diagonal span (here
w-65 h-70) or the last step clips. calc(var(--i)*24px+40px)must be typed with no spaces; inside an arbitrary value a space ends the class.- Keep step text at full opacity. Four mid-tone fills with dimmed white text is the fastest way to fail contrast on the lightest one.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Index-driven transforms and calc() in z-index are universal (Chrome 49+, Safari 10+, Firefox 52+). The floor is Tailwind v4's own generated sheet.