A menu that sold out in a week
A new menu shot in one day and posted across a month.
Case studies as a deck: on a wide screen each card holds at the top of the screen while the next slides up over it, and the one underneath shrinks and darkens a little on a scroll-driven timeline; on a phone they follow one another. Each card paints a colour block: its number and field, its name (the card's link), a line, the work it took as chips and a "View case" cue, beside a picture or a drawing in a second block (Motif). Zero JavaScript.
scroll inside
Sample work
A new menu shot in one day and posted across a month.
Six rooms and a pool, filmed at the two best hours of the day.
A month of stories and one reel a week for a beach club.
Slow pictures, short captions, and bookings by message.
Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.
Variants · each row writes the attribute the prop writes; the section's own CSS answers
JavaScript of its own
0 B
CSS 18.0 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Chrome 115 · not Firefox · Safari 26; needs scroll-timeline, has. Elsewhere: the cards still stack (sticky) without shrinking or darkening.
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
npx shadcn@latest add @moonarc-pro/case-stack---
import CaseStack from '@/components/moonarc/pro/CaseStack.astro';
---
<CaseStack
eyebrow="Work"
more={{ href: '/work/', label: 'All work' }}
cases={[
{ href: '/work/one/', title: 'A menu that sold out', text: 'A new menu shot in a day and posted for a month.', meta: 'Restaurant', tags: ['Photo', 'Social'], motif: 'plate' },
{ href: '/work/two/', title: 'Rooms booked by June', text: 'A villa\'s rooms, filmed for the season.', meta: 'Villa', tags: ['Video', 'Ads'], motif: 'gate' },
]}
>
<span slot="headline">Selected <em>work</em></span>
</CaseStack>Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: motif.
| Prop | Type | Default | Description |
|---|---|---|---|
cases | { href, title, text?, meta?, tags?, block?, art?, motif?, caption?, image? }[] | none | The cases, in order. block is the card's colour (the five in turn when unset), art the drawing's (the next block when unset); image ({ src, alt, srcset?, sizes? }) replaces the drawing. |
eyebrow | string | none | A short line above the heading. |
headline | string | none | The heading. Slot "headline" wins and may hold an <em>. |
more | { href: string; label: string } | none | A link beside the heading, e.g. to all the work. |
cue | string | 'View case' | The cue at the foot of each card, beside the round arrow (hidden from a screen reader: the name is the link). |
tagsLabel | string | 'Services' | Accessible name of each card's chips. |
level | 2 | 3 | 2 | Heading level of the section's heading; the cases' names are one below. |
density | 'compact' | 'cozy' | 'roomy' | 'cozy' | Block padding ×0.8 / ×1 / ×1.25 through --ma-density. |
The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.
.ma-casestack.ma-casestack__arrow.ma-casestack__body.ma-casestack__card.ma-casestack__cue.ma-casestack__eyebrow.ma-casestack__head.ma-casestack__headline.ma-casestack__item.ma-casestack__link.ma-casestack__list.ma-casestack__media.ma-casestack__meta.ma-casestack__more.ma-casestack__summary.ma-casestack__tags.ma-casestack__text.ma-casestack__title
slot="eyebrow"slot="headline"
The cards still hold and stack; none shrinks or darkens, the arrow and the picture stay put.
ClientRouterCSS only (a view timeline); nothing to rebind.
Replaces: Sticky card stacks (GSAP ScrollTrigger) · Stacking cards (Framer templates). See the migration table.
Cards stick to the top as you scroll and each one shrinks and dims as the next slides over it, as on Apple product pages.
What is on offer, as colour blocks: each card paints one of the palette's blocks and carries a drawing in its corner (Motif), an index, a name, a line, chips for what it includes and a foot with a price and a round arrow.
Sample projects
The work as a numbered index: one line per project with the title at display size and the client, the discipline and the year in mono, the whole line a link.
The whole body of work as a grid of covers with filters by discipline.
Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown