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
| Property | Token |
|---|---|
| Background | bg-brand-charcoal (#1A1A1A) |
| Border | border-brand-gray (#2D2D2D) |
| Border radius | rounded-sm (2px) |
| Accent border | border-brand-red (#CC0000) |
| Body text | text-white/80 |
| Secondary text | text-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.