# Handoff: bidbrain Auction Card (redesign)

## Overview
A redesigned auction listing card for **bidbrain** — a tool that helps a car dealer triage Motorway (and other source) auctions in a second or two. The card leads with the **retail price**, visualises the deal as a **price gauge** (reserve → max bid → retail), and folds secondary data (insights, valuations) into compact, glanceable rows.

One card layout is used everywhere: a vertical card in a single-column feed on mobile, and the **same vertical card** in a multi-column grid on desktop. There is no separate horizontal layout.

## About the Design Files
The files in this bundle are **design references created in HTML/JSX** — prototypes showing intended look and behaviour, **not production code to copy directly**. Your task is to recreate this design in the bidbrain codebase's existing environment and patterns (or, if the card component doesn't exist yet, in whatever framework the app already uses). `design-canvas.jsx`, `tweaks-panel.jsx`, and `image-slot.js` are presentation scaffolding for the prototype only — ignore them entirely.

The design logic lives in:
- `hifi-card.jsx` — the card component tree (all sub-components, including the gauge's tight-mode rule)
- `hifi-data.js` — the data contract (two real-world examples)
- `Card Hi-Fi.html` — the full stylesheet (the `.hf-*` rules) and locked default values

## Fidelity
**High-fidelity.** Colours, typography, spacing, radii, and copy are final and were reviewed/locked by the product owner. Recreate pixel-perfectly, mapping tokens onto your existing system where equivalents exist.

## Locked defaults
- Accent: `#1F8A5B` (green) with soft fill `#E3F3EA`
- Card corner radius: `16px` (CTA radius = card radius − 6px)
- Hero photo height: `240px`
- Valuation detail: collapsed by default

## The Card — top to bottom

### 1. Photo header (`.hf-photo`)
- Full-bleed listing photo, `object-fit: cover`, height 240px, background `#E8EAE4` while loading / when absent (empty state shows the source's placeholder text, e.g. "No photo yet").
- Overlaid chrome (all `z-index` above photo):
  - **Source badge** top-left: dark translucent pill `rgba(24,36,32,0.78)` + `backdrop-filter: blur(6px)`, white text 11.5px/700, padding 4px 10px 5px, fully rounded. Text = source name ("Motorway"). Multiple sources exist, so this is data-driven.
  - **Watch star** top-right: 34px circular button, `rgba(255,255,255,0.92)` bg, subtle shadow `0 1px 4px rgba(24,36,32,0.18)`, star outline icon in `--ink-2`; hover → amber `#B97D18`.
  - **Reg plate** bottom-left: white pill `rgba(255,255,255,0.94)`, 11.5px/800, letter-spacing 0.06em, radius 7px, e.g. "CN18 YLP".
  - **Photo count** bottom-right: dark translucent pill like the source badge but `rgba(24,36,32,0.65)`, camera icon + count.

### 2. Title row (`.hf-titlerow`)
- Flex, space-between, gap 12px.
- **Title** h3: 16.5px/700, letter-spacing −0.01em, line-height 1.25, `text-wrap: pretty`. May wrap to 2 lines.
- **Badges** (`.hf-badges`): right-aligned, wrap, gap 6px, max-width 46%:
  - "Fills a gap" — green pill (`--accent-soft` bg, `--accent` text, 11.5px/700, padding 4px 10px 5px, fully rounded)
  - "Seen before" — same pill in amber (`--warn-soft` bg, `--warn` text). Only when the vehicle was seen in a previous auction.

### 3. Spec chips (`.hf-chips`)
- Flex-wrap row, gap 7px, margin-top 13px.
- Standard chip: `#F3F5F1` bg, `--ink-2` text, 12px/600, padding 3px 9px 4px, fully rounded, `tabular-nums`. Contents: year, mileage, owners, location.
- **CAP chip** (`.hf-chip-cap`) is deliberately distinct: white bg, 1px `--line` border, `--ink` text 700, with a tiny uppercase "CAP" kicker (9.5px/800, letter-spacing 0.09em, `--ink-3`) before the value.

### 4. Price gauge (`.hf-gauge`) — the centrepiece
Margins 28px 2px 10px. A horizontal track mapping money to position: 0% = reserve, 100% = retail. `midPct = (maxBid − reserve) / (retail − reserve) × 100`.

- **Track**: 8px tall, fully rounded, `#ECEEE9`.
- **Band** (reserve → max bid): gradient `linear-gradient(90deg, color-mix(in oklch, var(--accent) 38%, white), var(--accent))`, rounded.
- **Dots**: hollow 12px dot at 0% (border `#CFD5CC`); filled-ring 14px dot at midPct (accent border + `0 0 0 3px` accent-at-18% halo); solid accent dot at 100%.
- **Labels above the track** (46px tall label zone):
  - Reserve (left, at 0%): kicker "RESERVE" + value 14.5px/600 in `--ink-2`
  - Max bid (at midPct, `translateX(-32%)`): kicker "MAX BID" + value 14.5px/800 in `--ink`
  - Retail (right-aligned): kicker "RETAILS FOR · CAZANA" + **the hero number**: 25px/800, letter-spacing −0.02em, in `--accent`. This is the #1 glanceable figure on the card.
  - Kicker style everywhere: 10px/700, letter-spacing 0.09em, uppercase, `--ink-3`, nowrap.
- **Room pill** below the track (margin-top 16px, margin-bottom 10px): accent-soft pill, accent text 12px/700, padding 7px 18px 8px, centred under the band (`justify-content: safe center` so it never spills past the card edge). Copy: "+£1,416 room".
- **TIGHT MODE** — when `midPct < 26` the reserve and max-bid labels can't coexist above the track (e.g. max bid £6,999 vs reserve £6,827 vs retail £9,999 → midPct ≈ 5%):
  - Reserve label moves **below** the track (left), the room pill sits beside it (right) in one flex row (space-between, margin 14px 0 10px).
  - The max-bid label stays above at midPct with **no** translateX (left-anchored).
  - The hollow 0% dot is hidden (it would collide with the mid dot).
  - Room copy flips to the delta form: "£172 over reserve".

### 5. Insight flags (`.hf-flags`)
- Column, gap 9px, margin-top 20px. Variable count (the model emits 1–5).
- Each row: 20px circular icon + 13px/500 `--ink-2` text, single line.
- Three kinds:
  - `warn` — amber: `--warn-soft` bg, `--warn` "!" — cautions (partial service history, seen recently)
  - `good` — green: `--accent-soft` bg, `--accent` "✓" — positives (sold before with margin, reserve dropped)
  - `info` — neutral: `#EDF0F3` bg, `#64748B` italic serif "i" — explanations (e.g. why the value was capped)
- Keep copy short enough for one line at ~324px text width; push detail to the listing view.

### 6. Valuation detail (`.hf-vals`) — collapsible
- Separated by a 1px `--line` top border, margin-top 16px.
- Toggle row: full-width ghost button, "Valuation detail" 12.5px/700 `--ink-2` left + chevron right (rotates 180° when open, 0.15s). Hover → `--ink`.
- Expanded: flex-wrap grid of valuation chips (gap 8px), one per source: GLASS'S, GLASS'S +15, CAZANA, CAZANA +15. Chip style identical to the CAP chip (white, bordered, kicker + value, radius 10px).
- **Collapsed by default.** Persist the user's preference if the app has per-user settings.

### 7. CTA row (`.hf-ctarow`)
- Flex, gap 14px, margin-top 14px.
- **Primary CTA**: "Open listing to bid" — fills remaining width, `--ink` bg, white 14.5px/700, padding 12px 18px, radius = card radius − 6px, hover `#2A3A34`. Opens the source listing (external).
- **Verdict**: quiet text right of the CTA, 12.5px/600, nowrap. "✗ Would not buy this" in `--ink-3`; "✓ Would buy this" in `--accent`. Deliberately subtle — it's a footnote, not a banner.

## Layout contexts
- **Mobile feed**: card full-width (designed at 364px content width), cards stacked vertically.
- **Desktop dashboard**: CSS grid of the same cards, `gap: 20px`, `align-items: start` (cards have different heights — top-align them). 2 columns shown in the mock; let the column count respond to viewport (e.g. `repeat(auto-fill, minmax(360px, 1fr))`).

## Interactions & Behavior
- Card itself is not a link; the CTA opens the listing; the star toggles watch state.
- Valuation toggle expands/collapses with no animation needed beyond the chevron rotation (height change can be instant or ~150ms ease).
- Hover states: CTA darkens; star tints amber; valuation toggle text darkens. No card-level hover lift was specified.
- All money strings are pre-formatted (`£6,999`) — render with `font-variant-numeric: tabular-nums` wherever numbers appear.
- Verdict, badges, insights, and valuations are all data-driven and optional — the card must degrade gracefully when any are absent (see the Peugeot example: 1 badge, 2 insights).

## State Management
Card props (see `hifi-data.js` for the exact two examples):
```
{
  source, title, reg, photos, photoUrl?,
  badges: [{ t, k? ('seen') }],
  chips: [year, mileage, owners, location],
  cap, reserve, max, retail (numbers + display strings),
  room (string),
  insights: [{ k: 'warn'|'good'|'info', t }],
  vals: [[label, value] × 4],
  verdict: 'Would buy' | 'Would not buy'
}
```
Local state: `valsOpen` (bool), `watched` (bool, star).
Derived: `midPct`, `tight = midPct < 26`.

## Design Tokens
| Token | Value |
|---|---|
| `--ink` | `#182420` (text, CTA bg) |
| `--ink-2` | `#5B6B64` (secondary text) |
| `--ink-3` | `#93A09A` (kickers, quiet text) |
| `--line` | `#E7EBE6` (borders) |
| `--card` | `#FFFFFF` |
| `--accent` | `#1F8A5B` |
| `--accent-soft` | `#E3F3EA` |
| `--warn` | `#B97D18` |
| `--warn-soft` | `#FDF3DF` |
| page/feed bg | `#F3F4F0` |
| card radius | `16px` (CTA = radius − 6px; chips fully rounded; CAP/val chips 10px) |
| card border | `1px solid var(--line)` |
| card shadow | `0 1px 2px rgba(24,36,32,0.04), 0 10px 30px -12px rgba(24,36,32,0.12)` |
| body padding | `20px` |
| grid gap (desktop) | `20px` |

Typography: **Figtree** (Google Fonts), weights 400–800. Scale used: 25px/800 (retail), 16.5px/700 (title), 14.5px (CTA, gauge numbers), 13px (insights), 12–12.5px (chips, verdict, toggle), 10px & 9.5px uppercase kickers. If the codebase already has a brand font, map sizes/weights onto it 1:1.

## Assets
- No raster assets. Icons (star, camera, chevron) are tiny inline SVGs — recreate with your icon library equivalents.
- Listing photos come from the auction source; the prototype uses a drag-and-drop placeholder (`image-slot.js`) which should be replaced by the real photo, with the `#E8EAE4` empty state behind it.

## Files
- `PROMPT.md` — ready-made prompt to give Claude Code.
- `screenshots/cards.png` — expected result: typical card · everything-on card (tight-mode gauge) · valuation detail expanded.
- `Card Hi-Fi.html` — full stylesheet (`.hf-*` rules) + locked defaults; open it in a browser to see the live design (artboards: Mobile · typical, Mobile · everything on, Desktop grid 2-up). The `.hf-row` rules near the end of the stylesheet are a **discarded** horizontal layout — ignore them.
- `hifi-card.jsx` — component structure and gauge tight-mode logic (`HfRow` is the discarded layout — ignore).
- `hifi-data.js` — the two reference datasets (typical + everything-on).
- `design-canvas.jsx`, `tweaks-panel.jsx`, `image-slot.js` — prototype scaffolding, not part of the design.
