Project milestones
Track progress across sprints. Update statuses on a weekly cadence, push blockers to the top, and let the team see where velocity pools.
A card is a container that groups heading, body content, images, and text into one unit.
Track progress across sprints. Update statuses on a weekly cadence, push blockers to the top, and let the team see where velocity pools.
<div class="demo-card-solo">
<article class="card">
<h3>Project milestones</h3>
<p>
Track progress across sprints. Update statuses on a weekly cadence, push
blockers to the top, and let the team see where velocity pools.
</p>
</article>
</div>
Background, border, radius, and a subtle shadow.
Tighter padding, gap, and font size.
No bg, border, or shadow. Sits on a parent surface.
Primary 2px border. Pulls out of a grid.
<div class="card-grid">
<article class="card">
<h4>Default</h4>
<p>Background, border, radius, and a subtle shadow.</p>
</article>
<article class="card is-compact">
<h4>Compact</h4>
<p>Tighter padding, gap, and font size.</p>
</article>
<article class="card is-flat">
<h4>Flat</h4>
<p>No bg, border, or shadow. Sits on a parent surface.</p>
</article>
<article class="card is-featured">
<h4>Featured</h4>
<p>Primary 2px border. Pulls out of a grid.</p>
</article>
</div>
Handoff complete; staging deploy scheduled for Thursday.
<div class="demo-card-solo">
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/card-figure/400/200"
alt=""
width="400"
height="200"
/>
</figure>
<h3>Launch plan</h3>
<p>Handoff complete; staging deploy scheduled for Thursday.</p>
</article>
</div>
Your draft is ready to go live. Review once more, then publish to the staging site for final checks before release.
<div class="demo-card-solo">
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/card-footer/400/200"
alt=""
width="400"
height="200"
/>
</figure>
<h3>Publish draft</h3>
<p>
Your draft is ready to go live. Review once more, then publish to the staging
site for final checks before release.
</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Save for later</button>
<button class="button" type="button">Publish</button>
</footer>
</article>
</div>
Highlights, misses, and commitments from the quarterly review. Four action items assigned; owner dates in the linked doc.
Outstanding items before the 1.0 cut. Click the card anywhere to open the checklist; the action buttons keep their own click targets.
<div class="card-grid" style="--card-grid-min: 20rem">
<article class="card is-interactive">
<figure>
<img
src="https://picsum.photos/seed/card-interactive/400/200"
alt=""
width="400"
height="200"
/>
</figure>
<h3><a href="#">Q4 retro summary</a></h3>
<p>
Highlights, misses, and commitments from the quarterly review. Four action
items assigned; owner dates in the linked doc.
</p>
</article>
<article class="card is-interactive">
<figure>
<img
src="https://picsum.photos/seed/card-interactive-footer/400/200"
alt=""
width="400"
height="200"
/>
</figure>
<h3><a href="#">Release checklist</a></h3>
<p>
Outstanding items before the 1.0 cut. Click the card anywhere to open the
checklist; the action buttons keep their own click targets.
</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Snooze</button>
<button class="button" type="button">Mark complete</button>
</footer>
</article>
</div>
Review role assignments and stale invitations before the security review on Friday.
Staged ship plan with go/no-go criteria for each phase. No figure on this card; the heading starts at the top and the footer still pins to the bottom edge.
No figure, no footer. The card still stretches to match the row's height.
<div class="card-grid">
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/plain-1/400/180"
alt=""
width="400"
height="180"
/>
</figure>
<h4>Access control audit</h4>
<p>
Review role assignments and stale invitations before the security review on
Friday.
</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
<article class="card">
<h4>Rollout checklist</h4>
<p>
Staged ship plan with go/no-go criteria for each phase. No figure on this
card; the heading starts at the top and the footer still pins to the bottom
edge.
</p>
<footer class="cluster is-snug">
<button class="button" type="button">Continue</button>
</footer>
</article>
<article class="card">
<h4>Docs migration</h4>
<p>No figure, no footer. The card still stretches to match the row's height.</p>
</article>
</div>
Plain .card-grid — the wrapped title pushes its own body down
Review role assignments before Friday.
Staged ship plan with go/no-go criteria for each phase.
Move remaining pages from the old CMS.
With .is-aligned — every body starts below the tallest title
Review role assignments before Friday.
Staged ship plan with go/no-go criteria for each phase.
Move remaining pages from the old CMS.
<div class="flow">
<p class="text-muted text--1">
Plain <code>.card-grid</code> — the wrapped title pushes its own body down
</p>
<div class="card-grid">
<article class="card">
<h4>Access control and stale invitation audit in a project</h4>
<p>Review role assignments before Friday.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
<article class="card">
<h4>Rollout checklist</h4>
<p>Staged ship plan with go/no-go criteria for each phase.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
<article class="card">
<h4>Docs migration</h4>
<p>Move remaining pages from the old CMS.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
</div>
<p class="text-muted text--1">
With <code>.is-aligned</code> — every body starts below the tallest title
</p>
<div class="card-grid is-aligned" style="--card-grid-rows: 3">
<article class="card">
<h4>Access control and stale invitation audit in a project</h4>
<p>Review role assignments before Friday.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
<article class="card">
<h4>Rollout checklist</h4>
<p>Staged ship plan with go/no-go criteria for each phase.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
<article class="card">
<h4>Docs migration</h4>
<p>Move remaining pages from the old CMS.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
</div>
</div>
</docs-resize>
<docs-resize>
<div class="flow">
<p class="text-muted text--1">Plain <code>.card-grid</code></p>
<div class="card-grid">
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/grid-1/400/180"
alt=""
width="400"
height="180"
/>
</figure>
<h4>Access control and stale invitation audit in a project</h4>
<p>Review role assignments before the security review on Friday.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/grid-2/400/180"
alt=""
width="400"
height="180"
/>
</figure>
<h4>Rollout checklist</h4>
<p>
Staged ship plan with go/no-go criteria for each phase. Sign-off
required before each window.
</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
<button class="button" type="button">Continue</button>
</footer>
</article>
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/grid-3/400/180"
alt=""
width="400"
height="180"
/>
</figure>
<h4>Docs migration</h4>
<p>Move remaining pages from the old CMS; redirect map drafted.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
</div>
<p class="text-muted text--1">With <code>.is-aligned</code></p>
<div class="card-grid is-aligned">
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/grid-1/400/180"
alt=""
width="400"
height="180"
/>
</figure>
<h4>Access control and stale invitation audit in a project</h4>
<p>Review role assignments before the security review on Friday.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/grid-2/400/180"
alt=""
width="400"
height="180"
/>
</figure>
<h4>Rollout checklist</h4>
<p>
Staged ship plan with go/no-go criteria for each phase. Sign-off
required before each window.
</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
<button class="button" type="button">Continue</button>
</footer>
</article>
<article class="card">
<figure>
<img
src="https://picsum.photos/seed/grid-3/400/180"
alt=""
width="400"
height="180"
/>
</figure>
<h4>Docs migration</h4>
<p>Move remaining pages from the old CMS; redirect map drafted.</p>
<footer class="cluster is-snug">
<button class="button is-outlined" type="button">Open</button>
</footer>
</article>
</div>
</div>
Plain .card-grid
Review role assignments before the security review on Friday.
Staged ship plan with go/no-go criteria for each phase. Sign-off required before each window.
Move remaining pages from the old CMS; redirect map drafted.
With .is-aligned
Review role assignments before the security review on Friday.
Staged ship plan with go/no-go criteria for each phase. Sign-off required before each window.
Move remaining pages from the old CMS; redirect map drafted.
Card
Structure -- semantic HTML carries the regions, no slot classes:
<article class="card">
<figure> <-- optional first-child media slot;
<img src="…" alt="…"> <picture>/<video> work too;
</figure> <figcaption> if you need one
<h3>Card title</h3> <-- or h2/h4/etc. per hierarchy
<p>Body paragraph.</p> <-- or any body content
<footer> <-- pushed to the card's bottom edge;
... compose .cluster + buttons or
</footer> byline text inside
</article>
Heading level (h2-h6) is the author's choice -- pick what fits
your document hierarchy. Card normalizes visual size via
--card-heading-font-size so the component looks consistent regardless
of the level used. Heading links render as text (color: inherit,
no underline) and tint primary on hover.
Media slot (figure as first child)
A <figure> placed as the first child of the card receives a
full-bleed treatment: negative margins equal to the card's padding
pull it flush with the card's border on the top and sides,
regardless of padding tokens (P2 test 2). <figure> at any other
position stays at normal proportions (margin: 0 reset, no bleed)
so a mid-card figure doesn't visually break the layout.
Inside the figure, <img> / <picture> / <video> all work; the inner
<img> (whether direct or wrapped in <picture>) and <video> get
sized to fill. Add a <figcaption> when the image needs a caption;
its styling is the consumer's call.
Footer slot
<footer> is pushed to the card's bottom edge via
margin-block-start: auto in the card's flex column (P2 test 3). It
carries
no other styling defaults -- compose what's inside: a .cluster of
buttons for actions, .text-muted utility for byline text, or
anything else. Footer can serve either "actions" or "byline" use
cases; the consumer picks the styling.
Interactive cards: .is-interactive adds hover shadow + cursor and
stretches the heading anchor's click area over the whole card via
::after. For a whole-card click target, put the <a> on the heading
(the link's accessible name stays just the heading text). Don't
wrap the entire card in an anchor -- that names the link with the
full card text and forbids nested interactives.
Source: src/css/card.css
.card
| Class | Kind | Description |
|---|---|---|
.is-compact | variant | Tighter padding, gap, and smaller heading |
.is-flat | variant | No shadow, border, or background |
.is-interactive | variant | Hover shadow and stretched heading link for whole-card click |
.is-featured | variant | Primary-colored thick border for emphasis |
| Slot | Description |
|---|---|
> figure:first-child | Full-bleed slot when figure is the first child |
> footer | The footer slot is pushed to the bottom edge |
| Token | Default | Description |
|---|---|---|
--card-bg | var(--color-surface-raised) | Background color for the card |
--card-border-color | var(--color-border) | Border color for the card |
--card-border-width | var(--border-width-default) | Border width for the card |
--card-border-style | solid | Border style for the card |
--card-radius | var(--radius-md) | Border radius for the card corners |
--card-padding-block | var(--ui-pad-block-relaxed) | Block-axis padding inside the card |
--card-padding-inline | var(--ui-pad-inline-relaxed) | Inline-axis padding inside the card |
--card-box-shadow | var(--shadow-sm) | Box shadow for the card |
--card-gap | var(--ui-gutter-relaxed) | Vertical spacing between card regions |
--card-heading-font-size | var(--font-size-md) | Font size for the card heading |
--card-content-font-size | inherit | Font size for the card body content |
--card-media-radius | var(--radius-md) | Border radius for the first-child media figure |
--card-media-height | auto | Fixed height for the media image or video |
A responsive grid of cards in auto-fill columns. Each card keeps its natural height by default; .is-aligned spans subgrid rows so a row of matching cards lines up its title, body, and footer across siblings.
Source: src/css/card.css
.card-grid
| Class | Kind | Description |
|---|---|---|
.card-grid.is-aligned | variant | Subgrid row alignment across uniform cards |
| Token | Default | Description |
|---|---|---|
--card-grid-min | 18rem | Minimum column width for auto-fill columns |
--card-grid-rows | 4 | Number of subgrid rows each card spans |