diff --git a/docs/memory/component-registry.md b/docs/memory/component-registry.md
index b31453d..16d133f 100644
--- a/docs/memory/component-registry.md
+++ b/docs/memory/component-registry.md
@@ -37,7 +37,9 @@ duplicates) and MUST update it after completing one.
| Component | Status | Composed of | Notes |
|-----------|--------|-------------|-------|
| FormField | planned | Input + Typography (label) + Typography (helper) | Standard form field with label and validation |
-| PriceCard | planned | Card + Typography + Badge + Button | Service pricing display |
+| ProviderCard | review | Card + Typography + Badge | Provider listing card. Verified: image + logo + "Trusted Partner" badge. Unverified: text-only. Capability badges (arbitrary label + colour). Footer with "Packages from $X >". 7 component tokens. |
+| VenueCard | planned | Card + Typography + Badge | Venue listing card. Always has photo, location, capacity, price. Simpler than ProviderCard. |
+| MapCard | planned | Card + Typography + Badge | Compact horizontal map popup card. Deferred until map integration. |
| ServiceOption | planned | Card + Typography + Chip + Icon | Selectable service item |
| SearchBar | planned | Input + Icon + Button | Search with submit |
| StepIndicator | planned | Typography + Badge + Divider | Multi-step flow progress |
diff --git a/docs/memory/decisions-log.md b/docs/memory/decisions-log.md
index ac5ade7..22b94cc 100644
--- a/docs/memory/decisions-log.md
+++ b/docs/memory/decisions-log.md
@@ -219,3 +219,43 @@ contradict a previous one.
**Rationale:** Leading icons (email, phone, dollar) are essential for FA's arrangement forms. Success state provides positive feedback after validation. The Figma only had trailing icon, but leading icons are a near-universal production need. The `startIcon`/`endIcon` props are simpler than MUI's `InputAdornment` pattern while remaining compatible with raw adornments via `startAdornment`/`endAdornment`.
**Affects:** Input component API, InputAdornment usage, Storybook stories
**Alternatives considered:** Only supporting MUI's raw adornment API — rejected as too verbose for the common case. The convenience props are ergonomic while the raw props remain available for complex cases (e.g., password toggle with IconButton).
+
+### D026 — ProviderCard establishes the molecule pattern
+**Date:** 2026-03-25
+**Category:** architecture
+**Decision:** ProviderCard is the first molecule. Molecules compose existing atoms via `sx` props — no MUI theme overrides. All styling from token CSS variables and theme accessors.
+**Rationale:** Keeps molecules lightweight and composable. Theme overrides are reserved for atoms where global consistency matters. Molecules are higher-level compositions with more context-specific layouts.
+**Affects:** All future molecules (VenueCard, MapCard, ServiceOption, etc.)
+**Alternatives considered:** Adding MuiProviderCard theme overrides — rejected as molecules are page-specific compositions, not reusable primitives.
+
+### D027 — ProviderCard image is a URL string, not a ReactNode
+**Date:** 2026-03-25
+**Category:** component
+**Decision:** `imageUrl` prop accepts a string rendered as CSS `background-image` with `cover`. Logo is also a URL string rendered as `
`.
+**Rationale:** Simpler API for the common case (CDN URLs). CSS background-image handles aspect ratio cropping automatically. `
` for logo supports `alt` text natively for accessibility.
+**Affects:** ProviderCard, VenueCard, MapCard APIs
+**Alternatives considered:** ReactNode for image — rejected as over-flexible. A ReactNode slot would allow video/carousel but adds API complexity for a feature we don't need yet.
+
+### D028 — Logo is 48px (not 75px from Figma)
+**Date:** 2026-03-25
+**Category:** component
+**Decision:** Logo overlay is 48px diameter, not the 75px shown in Figma.
+**Rationale:** On a ~340-400px card in a list panel, a 75px logo dominates the content area. 48px provides clear brand visibility while leaving sufficient space for the provider name and meta row.
+**Affects:** providerCard.logo.size token
+**Alternatives considered:** 75px from Figma — too large for the card width. 64px — still large relative to content.
+
+### D029 — Footer is built into ProviderCard, not a slot
+**Date:** 2026-03-25
+**Category:** component
+**Decision:** The "Packages from $X >" footer is rendered via a `startingPrice` number prop, not a children/slot pattern.
+**Rationale:** The footer is structurally identical across all provider cards — warm background, "Packages from" text, price, chevron. Only the price value changes. A slot would add API complexity for no flexibility gain. If footer is omitted (no startingPrice), the bar is simply absent.
+**Affects:** ProviderCard API, VenueCard may use a similar pattern
+**Alternatives considered:** children/render prop for footer — rejected as over-engineered for a fixed layout.
+
+### D030 — Verified is an explicit boolean, not derived from imageUrl
+**Date:** 2026-03-25
+**Category:** component
+**Decision:** `verified` boolean prop controls the visual treatment independently from `imageUrl`/`logoUrl`.
+**Rationale:** A provider could be verified but have a broken/missing image URL. The boolean is the source of truth from the business layer. Image and logo are only rendered when `verified` is also true, preventing accidental display of unverified providers with images.
+**Affects:** ProviderCard API, data model expectations
+**Alternatives considered:** Deriving verified from imageUrl presence — rejected as it couples business logic (partner status) to content availability (image uploaded).
diff --git a/docs/memory/session-log.md b/docs/memory/session-log.md
index c06371f..806eeb8 100644
--- a/docs/memory/session-log.md
+++ b/docs/memory/session-log.md
@@ -496,6 +496,48 @@ Each entry follows this structure:
- **Planned (5 organisms):** ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer
**Next steps:**
-- User to review Switch and Radio in Storybook
-- Begin PriceCard molecule
+- ~~User to review Switch and Radio in Storybook~~ ✓ Approved
+- ~~Begin PriceCard molecule~~ ✓ Replaced with ProviderCard (see below)
+- Address P2 audit issues in a future cleanup pass
+
+### Session 2026-03-25l — ProviderCard molecule (first molecule)
+
+**Agent(s):** Claude Opus (via conversation)
+
+**Work completed:**
+- Reviewed 3 Figma designs: Provider Cards (5503:44422), Service Venue (2997:83018), Map Pin Card (5369:140263)
+- Captured business context: verified vs unverified providers, Parsons partner strategy, map + list layout
+- Replaced generic "PriceCard" in registry with 3 specific molecules: ProviderCard, VenueCard, MapCard
+- Saved business context to auto-memory (project_listing_cards.md)
+- Created plan via /plan mode — component API, card structure, token plan, story plan
+- Created providerCard component tokens (`tokens/component/providerCard.json`): image.height, logo.size, footer.background/paddingX/paddingY, content.padding/gap — 7 tokens
+- Built ProviderCard molecule (`src/components/molecules/ProviderCard/ProviderCard.tsx`):
+ - Composes Card (interactive, padding="none") + Badge + Typography
+ - Verified variant: hero image (CSS bg-image cover), logo overlay (48px circle, absolute positioned, overlaps content), "Trusted Partner" badge (filled brand), capability badge
+ - Unverified variant: text-only, same content area + footer
+ - Footer bar: warm brand.100 bg, "Packages from $X" + ChevronRight
+ - Accessibility: aria-label on reviews, aria-hidden on decorative icons, alt text on logo
+ - All values from token CSS variables, no hardcoded hex
+- Created 9 Storybook stories: Default, VerifiedProvider, UnverifiedProvider, ListLayout (mixed), CapabilityVariants, EdgeCases, Responsive, OnDifferentBackgrounds, InteractiveDemo
+- Preflight passed all 5 checks
+- Logged D026-D030 in decisions log
+
+**Decisions made:**
+- D026: Molecules compose atoms via sx — no MUI theme overrides
+- D027: Image as URL string (CSS bg-image), logo as URL string (
)
+- D028: Logo 48px (not 75px Figma) for card width proportion
+- D029: Footer built in via startingPrice prop, not a slot
+- D030: verified is explicit boolean, not derived from imageUrl
+
+**Component status at end of session:**
+- **Done (7):** Button, Typography, Input, Card, Badge, Chip, Switch, Radio
+- **Review (1 molecule):** ProviderCard
+- **Planned (7 atoms):** IconButton, Icon, Avatar, Divider, ColourToggle, Slider, Link
+- **Planned (5 molecules):** VenueCard, MapCard, ServiceOption, SearchBar, StepIndicator, FormField
+- **Planned (5 organisms):** ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer
+
+**Next steps:**
+- User to review ProviderCard in Storybook — especially ListLayout story for verified/unverified alignment
+- Build VenueCard molecule (simpler — always has photo, location, capacity, price)
+- Consider MapCard as a deferred item until map integration
- Address P2 audit issues in a future cleanup pass
diff --git a/docs/memory/token-registry.md b/docs/memory/token-registry.md
index b92f121..9765532 100644
--- a/docs/memory/token-registry.md
+++ b/docs/memory/token-registry.md
@@ -264,3 +264,17 @@ the correct token for any design property.
|-----------|-----------|---------|-------------|
| radio.size.default | 20px | Radio | Outer circle size |
| radio.dotSize.default | 10px | Radio | Inner selected dot size |
+
+### ProviderCard
+
+`tokens/component/providerCard.json`
+
+| Token path | Value / Reference | Used by | Description |
+|-----------|-----------|---------|-------------|
+| providerCard.image.height | 180px | ProviderCard | Hero image fixed height |
+| providerCard.logo.size | 48px | ProviderCard | Logo circle diameter |
+| providerCard.footer.background | → color.brand.100 (#F7ECDF) | ProviderCard | Warm beige footer bar |
+| providerCard.footer.paddingX | → spacing.4 (16px) | ProviderCard | Footer horizontal padding |
+| providerCard.footer.paddingY | → spacing.3 (12px) | ProviderCard | Footer vertical padding |
+| providerCard.content.padding | → spacing.4 (16px) | ProviderCard | Content area padding |
+| providerCard.content.gap | → spacing.2 (8px) | ProviderCard | Gap between content rows |
diff --git a/src/components/molecules/ProviderCard/ProviderCard.stories.tsx b/src/components/molecules/ProviderCard/ProviderCard.stories.tsx
new file mode 100644
index 0000000..57745f7
--- /dev/null
+++ b/src/components/molecules/ProviderCard/ProviderCard.stories.tsx
@@ -0,0 +1,420 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { ProviderCard } from './ProviderCard';
+import Box from '@mui/material/Box';
+
+// Placeholder images for stories (grey boxes via data URIs)
+const HERO_PLACEHOLDER =
+ 'https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=600&h=300&fit=crop&auto=format';
+const HERO_PLACEHOLDER_2 =
+ 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=600&h=300&fit=crop&auto=format';
+const HERO_PLACEHOLDER_3 =
+ 'https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=600&h=300&fit=crop&auto=format';
+// Simple grey circle for logo placeholder
+const LOGO_PLACEHOLDER =
+ 'data:image/svg+xml,' +
+ encodeURIComponent(
+ '',
+ );
+
+const meta: Meta = {
+ title: 'Molecules/ProviderCard',
+ component: ProviderCard,
+ tags: ['autodocs'],
+ parameters: {
+ layout: 'centered',
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/design/XUDUrw4yMkEexBCCYHXUvT/Parsons?node-id=5369-140263',
+ },
+ },
+ argTypes: {
+ name: { control: 'text' },
+ location: { control: 'text' },
+ verified: { control: 'boolean' },
+ rating: { control: { type: 'number', min: 0, max: 5, step: 0.1 } },
+ reviewCount: { control: 'number' },
+ capabilityLabel: { control: 'text' },
+ capabilityColor: {
+ control: 'select',
+ options: ['default', 'success', 'warning', 'error', 'info'],
+ },
+ startingPrice: { control: 'number' },
+ onClick: { action: 'clicked' },
+ },
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+};
+
+export default meta;
+type Story = StoryObj;
+
+// ─── Default ────────────────────────────────────────────────────────────────
+
+/** Default — verified provider with all fields */
+export const Default: Story = {
+ args: {
+ name: 'H.Parsons Funeral Directors',
+ location: 'Wollongong',
+ verified: true,
+ imageUrl: HERO_PLACEHOLDER,
+ logoUrl: LOGO_PLACEHOLDER,
+ rating: 4.8,
+ reviewCount: 127,
+ capabilityLabel: 'Online Arrangement',
+ capabilityColor: 'success',
+ startingPrice: 900,
+ },
+};
+
+// ─── Verified Provider ──────────────────────────────────────────────────────
+
+/** Full verified provider card with all elements */
+export const VerifiedProvider: Story = {
+ name: 'Verified Provider',
+ render: () => (
+ {}}
+ />
+ ),
+};
+
+// ─── Unverified Provider ────────────────────────────────────────────────────
+
+/** Unverified provider — text only, no image/logo/trusted badge */
+export const UnverifiedProvider: Story = {
+ name: 'Unverified Provider',
+ render: () => (
+ {}}
+ />
+ ),
+};
+
+// ─── List Layout ────────────────────────────────────────────────────────────
+
+/**
+ * Mixed verified and unverified providers in a scrollable list.
+ * This is the primary use case — text alignment should be consistent
+ * across both card types for scan readability.
+ */
+export const ListLayout: Story = {
+ name: 'List Layout — Mixed',
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ render: () => (
+
+ {}}
+ />
+ {}}
+ />
+ {}}
+ />
+ {}}
+ />
+ {}}
+ />
+
+ ),
+};
+
+// ─── Capability Variants ────────────────────────────────────────────────────
+
+/** Three capability badge colours */
+export const CapabilityVariants: Story = {
+ name: 'Capability Variants',
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ render: () => (
+
+ {}}
+ />
+ {}}
+ />
+ {}}
+ />
+
+ ),
+};
+
+// ─── Edge Cases ─────────────────────────────────────────────────────────────
+
+/** Edge cases: long name, missing fields, extremes */
+export const EdgeCases: Story = {
+ name: 'Edge Cases',
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ render: () => (
+
+ {/* Long name — tests maxLines truncation */}
+ {}}
+ />
+ {/* No reviews */}
+ {}}
+ />
+ {/* No capability badge */}
+ {}}
+ />
+ {/* No price (footer hidden) */}
+ {}}
+ />
+ {/* Minimal — just name and location */}
+ {}}
+ />
+
+ ),
+};
+
+// ─── Responsive ─────────────────────────────────────────────────────────────
+
+/** Cards at different viewport widths */
+export const Responsive: Story = {
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ render: () => (
+
+ {[280, 340, 420].map((width) => (
+
+ {width}px
+ {}}
+ />
+
+ ))}
+
+ ),
+};
+
+// ─── On Different Backgrounds ───────────────────────────────────────────────
+
+/** Cards on white vs grey surfaces */
+export const OnDifferentBackgrounds: Story = {
+ name: 'On Different Backgrounds',
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ render: () => (
+
+
+ White surface
+ {}}
+ />
+
+
+ Grey surface (neutral.50)
+ {}}
+ />
+
+
+ ),
+};
+
+// ─── Interactive Demo ───────────────────────────────────────────────────────
+
+/** Click any card — fires onClick in Storybook actions panel */
+export const InteractiveDemo: Story = {
+ name: 'Interactive — Click to Navigate',
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ render: () => (
+
+ alert('Navigate to Parsons Ladies packages')}
+ />
+ alert('Navigate to Rankins packages')}
+ />
+
+ ),
+};
diff --git a/src/components/molecules/ProviderCard/ProviderCard.tsx b/src/components/molecules/ProviderCard/ProviderCard.tsx
new file mode 100644
index 0000000..2ed1c35
--- /dev/null
+++ b/src/components/molecules/ProviderCard/ProviderCard.tsx
@@ -0,0 +1,260 @@
+import React from 'react';
+import Box from '@mui/material/Box';
+import type { SxProps, Theme } from '@mui/material/styles';
+import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined';
+import StarRoundedIcon from '@mui/icons-material/StarRounded';
+import ChevronRightIcon from '@mui/icons-material/ChevronRight';
+import VerifiedOutlinedIcon from '@mui/icons-material/VerifiedOutlined';
+import { Card } from '../../atoms/Card';
+import { Badge } from '../../atoms/Badge';
+import type { BadgeColor } from '../../atoms/Badge/Badge';
+import { Typography } from '../../atoms/Typography';
+
+// ─── Types ───────────────────────────────────────────────────────────────────
+
+/** Props for the FA ProviderCard molecule */
+export interface ProviderCardProps {
+ /** Provider display name */
+ name: string;
+ /** Location text (suburb, city) */
+ location: string;
+ /** Whether this provider is a verified/trusted partner */
+ verified?: boolean;
+ /** Hero image URL — only rendered when verified */
+ imageUrl?: string;
+ /** Provider logo URL — circular overlay on image, only rendered when verified */
+ logoUrl?: string;
+ /** Average rating (e.g. 4.8). Omit to hide reviews. */
+ rating?: number;
+ /** Number of reviews (e.g. 127). Omit to hide review count. */
+ reviewCount?: number;
+ /** Capability badge label (e.g. "Online Arrangement") */
+ capabilityLabel?: string;
+ /** Capability badge colour intent — maps to Badge colour */
+ capabilityColor?: BadgeColor;
+ /** Starting price in dollars (shown in footer as "Packages from $X") */
+ startingPrice?: number;
+ /** Click handler — entire card is clickable */
+ onClick?: () => void;
+ /** MUI sx prop for style overrides */
+ sx?: SxProps;
+}
+
+// ─── Constants ───────────────────────────────────────────────────────────────
+
+const LOGO_SIZE = 'var(--fa-provider-card-logo-size)';
+const LOGO_OVERLAP = 24; // half of 48px logo, in px
+const IMAGE_HEIGHT = 'var(--fa-provider-card-image-height)';
+const CONTENT_PADDING = 'var(--fa-provider-card-content-padding)';
+const CONTENT_GAP = 'var(--fa-provider-card-content-gap)';
+const FOOTER_BG = 'var(--fa-provider-card-footer-background)';
+const FOOTER_PX = 'var(--fa-provider-card-footer-padding-x)';
+const FOOTER_PY = 'var(--fa-provider-card-footer-padding-y)';
+
+// ─── Component ───────────────────────────────────────────────────────────────
+
+/**
+ * Provider listing card for the FA design system.
+ *
+ * Displays a funeral provider in the provider select screen's scrollable
+ * list. Supports verified (paid partner) and unverified (scraped listing)
+ * providers with consistent text alignment for scan readability.
+ *
+ * **Verified providers** get a hero image, logo overlay, and "Trusted Partner"
+ * badge. **Unverified providers** show text content only — no image, logo,
+ * or verification badge.
+ *
+ * Composes: Card (interactive, padding="none"), Badge, Typography.
+ *
+ * Usage:
+ * ```tsx
+ * navigate(`/providers/parsons`)}
+ * />
+ * ```
+ */
+export const ProviderCard = React.forwardRef(
+ (
+ {
+ name,
+ location,
+ verified = false,
+ imageUrl,
+ logoUrl,
+ rating,
+ reviewCount,
+ capabilityLabel,
+ capabilityColor = 'default',
+ startingPrice,
+ onClick,
+ sx,
+ },
+ ref,
+ ) => {
+ const showImage = verified && imageUrl;
+ const showLogo = verified && logoUrl;
+
+ return (
+
+ {/* ── Image area (verified only) ── */}
+ {showImage && (
+
+ {/* Trusted Partner badge */}
+
+ }
+ >
+ Trusted Partner
+
+
+
+ {/* Logo overlay */}
+ {showLogo && (
+
+ )}
+
+ )}
+
+ {/* ── Content area ── */}
+
+ {/* Provider name */}
+
+ {name}
+
+
+ {/* Meta row: location + reviews */}
+
+ {/* Location */}
+
+
+
+ {location}
+
+
+
+ {/* Reviews */}
+ {rating != null && (
+
+
+
+ {rating}
+ {reviewCount != null && ` (${reviewCount.toLocaleString('en-AU')})`}
+
+
+ )}
+
+
+ {/* Capability badge */}
+ {capabilityLabel && (
+
+
+ {capabilityLabel}
+
+
+ )}
+
+
+ {/* ── Footer bar ── */}
+ {startingPrice != null && (
+
+
+ Packages from
+
+
+ ${startingPrice.toLocaleString('en-AU')}
+
+
+
+ )}
+
+ );
+ },
+);
+
+ProviderCard.displayName = 'ProviderCard';
+export default ProviderCard;
diff --git a/src/components/molecules/ProviderCard/index.ts b/src/components/molecules/ProviderCard/index.ts
new file mode 100644
index 0000000..dcea37d
--- /dev/null
+++ b/src/components/molecules/ProviderCard/index.ts
@@ -0,0 +1,2 @@
+export { ProviderCard, default } from './ProviderCard';
+export type { ProviderCardProps } from './ProviderCard';
diff --git a/src/theme/generated/tokens.css b/src/theme/generated/tokens.css
index 45fedc4..b3bdb1b 100644
--- a/src/theme/generated/tokens.css
+++ b/src/theme/generated/tokens.css
@@ -26,6 +26,8 @@
--fa-input-height-sm: 40px; /** Small — compact forms, admin layouts, matches Button medium height */
--fa-input-height-md: 48px; /** Medium (default) — standard forms, matches Button large for alignment */
--fa-input-icon-size-default: 20px; /** 20px — icon size inside input field, matches Figma trailing icon */
+ --fa-provider-card-image-height: 180px; /** Fixed image height for consistent card sizing in list layouts */
+ --fa-provider-card-logo-size: 48px; /** Logo circle diameter — positioned bottom-left of image, overlapping content area */
--fa-radio-size-default: 20px; /** Default radio size — matches Figma 16px + padding for 44px touch target area */
--fa-radio-dot-size-default: 10px; /** Selected indicator dot — 50% of outer size */
--fa-switch-track-width: 44px; /** Track width — slightly narrower than Figma 52px for better proportion with 44px touch target */
@@ -265,6 +267,11 @@
--fa-input-font-size-default: var(--fa-font-size-base); /** 16px — prevents iOS auto-zoom on focus, matches Figma */
--fa-input-border-radius-default: var(--fa-border-radius-sm); /** 4px — subtle rounding, consistent with Figma design */
--fa-input-gap-default: var(--fa-spacing-2); /** 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability */
+ --fa-provider-card-footer-background: var(--fa-color-brand-100); /** Warm beige footer — brand.100 provides subtle brand warmth */
+ --fa-provider-card-footer-padding-x: var(--fa-spacing-4); /** 16px horizontal padding — matches compact card padding */
+ --fa-provider-card-footer-padding-y: var(--fa-spacing-3); /** 12px vertical padding — slightly tighter than content area */
+ --fa-provider-card-content-padding: var(--fa-spacing-4); /** 16px content padding — compact to maximise text area on listing cards */
+ --fa-provider-card-content-gap: var(--fa-spacing-2); /** 8px vertical gap between content rows (name, meta, capability) */
--fa-switch-track-border-radius: var(--fa-border-radius-full); /** Pill shape */
--fa-color-text-primary: var(--fa-color-neutral-800); /** Primary text — body content, headings. Cool charcoal (#2C2E35) for comfortable extended reading */
--fa-color-text-secondary: var(--fa-color-neutral-600); /** Secondary text — helper text, descriptions, metadata, less prominent content */
diff --git a/src/theme/generated/tokens.js b/src/theme/generated/tokens.js
index 32523cb..dad18f9 100644
--- a/src/theme/generated/tokens.js
+++ b/src/theme/generated/tokens.js
@@ -72,6 +72,13 @@ export const InputFontSizeDefault = "1rem"; // 16px — prevents iOS auto-zoom o
export const InputBorderRadiusDefault = "4px"; // 4px — subtle rounding, consistent with Figma design
export const InputGapDefault = "8px"; // 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability
export const InputIconSizeDefault = "20px"; // 20px — icon size inside input field, matches Figma trailing icon
+export const ProviderCardImageHeight = "180px"; // Fixed image height for consistent card sizing in list layouts
+export const ProviderCardLogoSize = "48px"; // Logo circle diameter — positioned bottom-left of image, overlapping content area
+export const ProviderCardFooterBackground = "#f7ecdf"; // Warm beige footer — brand.100 provides subtle brand warmth
+export const ProviderCardFooterPaddingX = "16px"; // 16px horizontal padding — matches compact card padding
+export const ProviderCardFooterPaddingY = "12px"; // 12px vertical padding — slightly tighter than content area
+export const ProviderCardContentPadding = "16px"; // 16px content padding — compact to maximise text area on listing cards
+export const ProviderCardContentGap = "8px"; // 8px vertical gap between content rows (name, meta, capability)
export const RadioSizeDefault = "20px"; // Default radio size — matches Figma 16px + padding for 44px touch target area
export const RadioDotSizeDefault = "10px"; // Selected indicator dot — 50% of outer size
export const SwitchTrackWidth = "44px"; // Track width — slightly narrower than Figma 52px for better proportion with 44px touch target
diff --git a/tokens/component/providerCard.json b/tokens/component/providerCard.json
new file mode 100644
index 0000000..fb348a7
--- /dev/null
+++ b/tokens/component/providerCard.json
@@ -0,0 +1,46 @@
+{
+ "providerCard": {
+ "$description": "ProviderCard molecule tokens — listing card for funeral providers on the select screen. Supports verified (image + logo + badge) and unverified (text-only) variants.",
+ "image": {
+ "$type": "dimension",
+ "$description": "Hero image area dimensions.",
+ "height": { "$value": "180px", "$description": "Fixed image height for consistent card sizing in list layouts" }
+ },
+ "logo": {
+ "$type": "dimension",
+ "$description": "Provider logo overlay dimensions.",
+ "size": { "$value": "48px", "$description": "Logo circle diameter — positioned bottom-left of image, overlapping content area" }
+ },
+ "footer": {
+ "$description": "Footer bar styling — warm beige bar with package pricing.",
+ "background": {
+ "$type": "color",
+ "$value": "{color.brand.100}",
+ "$description": "Warm beige footer — brand.100 provides subtle brand warmth"
+ },
+ "paddingX": {
+ "$type": "dimension",
+ "$value": "{spacing.4}",
+ "$description": "16px horizontal padding — matches compact card padding"
+ },
+ "paddingY": {
+ "$type": "dimension",
+ "$value": "{spacing.3}",
+ "$description": "12px vertical padding — slightly tighter than content area"
+ }
+ },
+ "content": {
+ "$description": "Content area spacing.",
+ "padding": {
+ "$type": "dimension",
+ "$value": "{spacing.4}",
+ "$description": "16px content padding — compact to maximise text area on listing cards"
+ },
+ "gap": {
+ "$type": "dimension",
+ "$value": "{spacing.2}",
+ "$description": "8px vertical gap between content rows (name, meta, capability)"
+ }
+ }
+ }
+}