Skip to content

Card

Source: packages/ui/src/components/card.tsx (pending promotion from app-level)

Anatomy

┌─────────────────────────────────────┐
│ [Icon / Badge] │ ← optional header
│ Title │ ← required
│ ───────────────────────────────── │
│ Body copy or description text │ ← required
│ │
│ [ CTA / link ] │ ← optional footer
└─────────────────────────────────────┘

Variants

Service Card

Used in the 2×3 services grid on the homepage. Features a diamond icon (), a title, descriptive bullet points, and an “INQUIRE” CTA.

// Expected structure (app-level, pre-promotion)
<div className="rounded-sm border border-brand-gray bg-brand-charcoal p-6 flex flex-col gap-4">
<div className="text-brand-red text-xl"></div>
<h3 className="text-xl font-semibold text-white">Keynote Speaking</h3>
<ul className="text-sm text-white/70 space-y-1 flex-1">
<li>RSA · DEF CON · Black Hat</li>
<li>Fortune 500</li>
</ul>
<Button variant="ghost" size="sm">Inquire</Button>
</div>

Press / Media Card

Used in the filterable press grid. Shows publication logo, headline, date, and an external link.

<div className="rounded-sm border border-brand-gray bg-brand-charcoal p-4 flex gap-4 items-start">
<img src={logo} alt={publication} className="h-6 w-auto opacity-70" />
<div>
<p className="text-sm font-semibold text-white">{headline}</p>
<p className="text-xs text-white/50 mt-1">{publication} · {year}</p>
</div>
</div>

Podcast Episode Card

Used in the episode archive. Shows episode number, title, duration, and a play/link action.

<div className="rounded-sm border border-brand-gray bg-brand-charcoal p-4 flex justify-between items-center gap-4">
<div>
<span className="text-xs font-mono text-brand-red uppercase">EP {number}</span>
<h4 className="text-sm font-semibold text-white mt-1">{title}</h4>
</div>
<span className="text-xs text-white/50 font-mono shrink-0">{duration}</span>
</div>

Testimonial Card

Used in the social proof section. Contains a blockquote and attribution.

<figure className="rounded-sm border-l-2 border-brand-red pl-6 py-2">
<blockquote className="text-base text-white/80 italic leading-relaxed">
{quote}
</blockquote>
<figcaption className="mt-4 text-xs text-white/50 uppercase tracking-wider">
{attribution}
</figcaption>
</figure>

Design Tokens Used

PropertyToken
Backgroundbg-brand-charcoal (#1A1A1A)
Borderborder-brand-gray (#2D2D2D)
Border radiusrounded-sm (2px)
Accent borderborder-brand-red (#CC0000)
Body texttext-white/80
Secondary texttext-white/50

Accessibility

  • Cards that are entirely clickable must use a single <a> wrapping the card or the “stretched link” pattern — not multiple nested interactive elements.
  • Non-interactive cards do not need a role.
  • All icons used as visual decorations must have aria-hidden="true".

Promotion to Shared Library

When a card variant is used in 2+ apps, it should be promoted to packages/ui/src/components/card.tsx with typed props. Follow the same pattern as button.tsx.