<!-- source-hash: 84fe8c9e8dffcbf0ae0ec8ff163a67e2 -->
Pure presentation component for rendering blog post cards in two density modes (`default` and `sm`), with no built-in click/navigation logic — callers supply the resolved `href` and wrap with their own anchor strategy.

## Key Components

### `BlogCard`
Main card component supporting two layouts:
- **`default`**: Full vertical card with cover image, title, summary, author avatar, date, and view count
- **`sm`**: Compact horizontal card (~80px tall) designed for chat-inline rendering, showing a thumbnail, title, category, and summary

### `BlogCardSkeleton`
Loading placeholder matching both `default` and `sm` density layouts using animated pulse styles.

### `BlogCardProps`
| Prop | Type | Description |
|---|---|---|
| `post` | `BlogPostSummary` | Post data (title, image, author, etc.) |
| `href` | `string` | Resolved detail URL from caller |
| `target` | `'_blank'` | Opens in new tab (set by chat dispatch) |
| `placeholderUrl` | `string \| null` | Fallback image when `featured_image` is missing |
| `size` | `'default' \| 'sm'` | Card density mode |
| `hasEmbeddedVideo` | `boolean` | Surfaces a "Video" badge in compact mode |
| `priority` | `boolean` | Passes LCP priority hint to the cover image |

**Image fallback chain:** `post.featured_image` → `placeholderUrl` → `bg-ods-bg` background slot

## Usage Example

```typescript
// Default full card — caller wraps with navigation anchor
<BlogCard
  post={blogPostSummary}
  href={buildContentURL(post.slug)}
  placeholderUrl={useOgPlaceholder(post)}
  size="default"
  priority={true}
/>

// Compact card for chat-inline rendering
<BlogCard
  post={blogPostSummary}
  href={detailUrl}
  target="_blank"
  rel="noopener noreferrer"
  size="sm"
  hasEmbeddedVideo={true}
  placeholderUrl={staticFallbackUrl}
/>

// Skeleton while loading
<BlogCardSkeleton size="sm" />
```