Live preview

Rendered from the tier-2 component tokens + foundation tokens per this spec — a spec-faithful rendering, not the production component (those live in each product repo). Variants and states come from the spec below.

Fairhope Soccer Camp
U10–U14 · Fairhope, AL · Jun 24–28
$249
flat
Fairhope Soccer Camp
U10–U14 · Fairhope, AL · Jun 24–28
$249
raised
Fairhope Soccer Camp
U10–U14 · Fairhope, AL · Jun 24–28
$249
interactive

Anatomy

root
The container: surface background, card radius, hairline border, section padding, optional shadow.
media
Optional image/media header (e.g. the camp photo), clipped to the card radius.
body
The content region — title, meta, and an actions row.

Token bindings

Each binding's value is resolved live from the built @beestera/tokens output — tier-2 component tokens (--card-*) collapse through the foundation tier.

Part Property Token Resolved Applies to
root border-radius --card-radius 0.75rem --card-radius → --radius-card
root background --card-bg #ffffff --card-bg → --color-surface
root border-color --card-border #e4e4e7 --card-border → --color-border
root padding --card-padding 1.5rem --card-padding → --spacing-section
root box-shadow --card-shadow 0 1px 2px rgba(24, 24, 27, 0.06), 0 1px 3px rgba(24, 24, 27, 0.1) --card-shadow → --shadow-card-default elevation:raised
root box-shadow --card-shadow 0 1px 2px rgba(24, 24, 27, 0.06), 0 1px 3px rgba(24, 24, 27, 0.1) --card-shadow → --shadow-card-default elevation:interactive
root box-shadow --card-shadow-hover 0 4px 6px rgba(24, 24, 27, 0.08), 0 2px 4px rgba(24, 24, 27, 0.12) --card-shadow-hover → --shadow-card-hover elevation:interactive,state:hover

Variants

elevation flatraisedinteractive
flat = border only, no shadow; raised = a resting card shadow; interactive = raised that lifts to the hover shadow on hover (for cards that are themselves links/buttons).

State matrix

default
Resting appearance for the active elevation.
hover
Only the interactive elevation reacts — shadow lifts from card-default to card-hover.

Accessibility

Role
group / article for content cards; the interactive elevation MUST wrap a real link/button, not attach a click to a div.
Contrast
Card content inherits foundation text-on-surface pairs (all AA). The card itself adds no text.
Focus order
flat/raised are non-interactive. interactive cards expose one focusable control; the whole-card affordance MUST be keyboard reachable.
Target size
For interactive cards, the primary affordance target >= 44px (--spacing-touch-min).

Usage

Do

  • Use flat for dense grids, raised to separate a card from a busy background, interactive when the whole card is a link.
  • Keep the section padding token (--card-padding) rather than ad-hoc padding.
  • Clip media to the card radius.

Don't

  • Don't hardcode box-shadow or radius literals — bind to --card-*.
  • Don't make a non-interactive card look clickable (raised is not interactive).
  • Don't nest cards more than one level deep.

Implementations

swarm-os
packages/ui/src/Card.tsbuildCardView Ships elevation: flat|raised|interactive with the exact radius/border/padding/shadow tokens this spec binds.

Figma source: Card