---
phase: 29
plan: 02
subsystem: frontend
tags: [components, image-rendering, ui]
key-files:
  created:
    - src/client/components/GearImage.tsx
  modified:
    - src/client/components/ItemCard.tsx
    - src/client/components/GlobalItemCard.tsx
    - src/client/components/CandidateCard.tsx
    - src/client/components/CandidateListItem.tsx
    - src/client/components/ImageUpload.tsx
    - src/client/components/ComparisonTable.tsx
    - src/client/components/CatalogSearchOverlay.tsx
    - src/client/components/LinkToGlobalItem.tsx
    - src/client/routes/items/$itemId.tsx
    - src/client/routes/global-items/$globalItemId.tsx
    - src/client/routes/global-items/index.tsx
    - src/client/routes/threads/$threadId/candidates/$candidateId.tsx
metrics:
  tasks: 13
  commits: 4
  files-changed: 13
---

# Plan 29-02 Summary: GearImage Component + Surface Updates

## What was built
- Created `GearImage` shared component with three modes: contain (default), cover (tiny thumbnails), and crop (CSS transform)
- Created `imageContainerBg()` helper for consistent dominant color backgrounds
- Updated all 12 gear image surfaces to use GearImage
- Default rendering now uses `object-contain` instead of `object-cover`
- Parent containers use dominant color background for letterbox/pillarbox fill
- LinkToGlobalItem uses `cover` mode for 32px thumbnails (intentional exception)

## Commits

| Task | Commit | Description |
|------|--------|-------------|
| 1 | 06d3984 | Create GearImage component |
| 2-3 | 2865e65 | Update ItemCard and GlobalItemCard |
| 4-5 | 05c0918 | Update CandidateCard and CandidateListItem |
| 6-8 | 91846b5 | Update ComparisonTable, CatalogSearchOverlay, ImageUpload |
| 9-13 | 66d9c41 | Update detail pages and LinkToGlobalItem |
| lint | 9636033 | Lint fixes for formatting and unused parameter |

## Deviations
None.

## Self-Check: PASSED
- GearImage component exists: YES
- object-cover removed from all gear surfaces: YES (only remains in GearImage internal, ProfileSection avatar, users avatar)
- Build passes: YES
- Lint passes: YES
