# Chunk 02 — Option Thumbnails

> Add a **thumbnail image to each parameter option** so merchants visually understand what each
> choice means (e.g. what "Georgette" vs "Velvet" looks like, what "Golden Hour" lighting is,
> what a "Boat Neck" is). Style: **image card with the label below** (Fotor tool-card style),
> matching `docs/mockup-editor-shell.html`.
>
> This is an additive, low-risk chunk: we change how `.opt` elements *look* and add an `<img>`
> inside them, without changing the selection logic, values, or any endpoint.

---

## Goal
Every visual option (garment, fabric, pattern, fit, sleeve, neckline, embellishment, model,
hair, makeup, expression, footwear, pose, lighting, camera, frame, background, occasion, season,
aesthetic, vibe, image style, etc.) becomes a small **image card**: a thumbnail on top, the
existing translated label beneath. Where no image exists yet, fall back to a clean icon/illustration
so the UI never looks broken while images are filled in incrementally.

---

## Part A — Preservation Contract  ⚠️ (must not break)

The selection engine in `public/js/rongberong.js` binds to specific structure. Keep it.

- **Option element stays the same node with the same hooks.** Today each option is:
  ```html
  <span class="opt" data-v="Georgette" role="checkbox" aria-checked="false" tabindex="0">{{ __('fabric.Georgette') }}</span>
  ```
  The JS relies on: the **`.opt`** class, the **`data-v="<value>"`** attribute (exact value string —
  it maps to `state` and is sent to the API), the parent **`.opts`** with **`data-group="<key>"`**,
  the **`.opt.sel`** selected class, and `role="checkbox"` / `aria-checked` / `tabindex` for a11y +
  keyboard handling.
- **Do NOT change any `data-v` value** — they are the API payload values (see chunk 01 §A.2). Adding
  an image must not rename or remove them.
- **Do NOT change `data-group` keys** — they map to `state` keys.
- The JS does `e.target.closest('.opt')` for clicks and toggles `.sel`; an `<img>` inside the `.opt`
  is fine because `closest('.opt')` still resolves. Keep the image non-interactive (`pointer-events`
  inherited; don't add separate click handlers).
- **i18n unchanged:** labels still render via `{{ __('group.Value') }}`. No hardcoded text.
- **No new endpoints, no controller changes** for this chunk (images are static assets).
- `.fg-sel-count` counters, `.field-group` toggles, and required-category logic must still work.

### Acceptance gate for this contract
After the change, selecting/deselecting any option must still: toggle `.sel`, update `state`,
update `.fg-sel-count`, build the prompt preview, and produce the same `data-v` value in the
`/generate` payload as before.

---

## Part B — The change (visual + data)

### B.1 New option markup (image card)
Extend the existing `.opt` to an image-card layout. Keep all existing attributes; add an image and
wrap the label in a span:

```html
<span class="opt opt--thumb" data-v="Georgette" data-thumb="fabric/georgette"
      role="checkbox" aria-checked="false" tabindex="0">
  <span class="opt-thumb" aria-hidden="true">
    <img loading="lazy" alt="" src="{{ asset('img/options/fabric/georgette.jpg') }}"
         onerror="this.closest('.opt-thumb').classList.add('opt-thumb--fallback')">
  </span>
  <span class="opt-label">{{ __('fabric.Georgette') }}</span>
</span>
```

- `opt--thumb` = new modifier so non-visual groups (e.g. free-text) are unaffected.
- `data-thumb` = relative key for the image (optional helper; the `src` can also be built from
  `data-group` + `data-v`).
- `onerror` adds a fallback class so a missing image shows an icon/placeholder instead of a broken
  image — this is what lets you ship images **incrementally**.
- `alt=""` because the visible label already names it (avoids double announcement for screen readers);
  the thumb is decorative.

### B.2 Image card CSS (Tailwind v4 `@theme` + component CSS)
Match the mockup's tool card:
- Card: column flex, `gap:6px`, `width` ~ 84–96px, cursor pointer.
- Thumb: aspect ratio **3:4** (slightly portrait), `border-radius: var(--radius)`, `object-fit: cover`,
  1px `--color-border`. Hover → `transform: scale(1.03)` + `--shadow-md`.
- Selected (`.opt.sel`): 2px `--color-accent` ring on the thumb + label color `--color-accent`.
- Label: `--font-sans`, 12px/500, centered, 2-line clamp.
- Fallback (`.opt-thumb--fallback`): hide `<img>`, show a centered Lucide-style icon on
  `--color-bg-subtle`. Use a per-group default icon (shirt for garment, etc.).
- Groups render as a responsive grid: `display:grid; grid-template-columns: repeat(auto-fill, minmax(84px,1fr)); gap:10px;`
  on `.opts` (only where `.opt--thumb` is used).

### B.3 Image sourcing (free / open source)
Use only license-clean sources. Recommended, in order:
1. **Unsplash** (Unsplash License — free, commercial OK, no attribution required) — best for
   fabrics, lighting moods, backgrounds, model/pose context.
2. **Pexels** / **Pixabay** (free, commercial OK) — good fallback breadth.
3. **Openverse** (aggregates CC-licensed media; filter to CC0 / commercial-use) — for niche items.
4. **Wikimedia Commons** (check each file's license; prefer CC0/public domain) — for traditional
   garments (saree, panjabi, jamdani) and cultural specifics.
5. For abstract concepts (aspect ratio, branding space, text overlay) use **generated diagrams /
   simple icons**, not photos.

Rules:
- Prefer **CC0 / Unsplash / Pexels** to avoid attribution burden. If a CC-BY image is used, record
  attribution in `docs/credits/option-images.md`.
- Optimize before committing: resize to ~**320×420px**, convert to **`.webp`** (with `.jpg` fallback
  only if needed), target < 40 KB each.
- Keep culturally accurate, modest-friendly imagery (this is a Bangladeshi f-commerce audience).
- Do NOT hotlink — download, optimize, and serve from `public/img/options/...`.

### B.4 Asset folder convention
```
public/img/options/
  garment/   kurti.webp saree.webp polo.webp panjabi.webp ...
  fabric/    silk.webp georgette.webp velvet.webp denim.webp ...
  pattern/   solid.webp floral.webp jamdani.webp ...
  pose/  lighting/  camera/  frame/  bg/  occasion/  season/
  model/  hair/  makeup/  expression/  footwear/
  aesthetic/  vibe/  image_style/
```
File name = lowercased `data-v` with spaces→hyphens (e.g. `T-Shirt`→`t-shirt.webp`,
`Golden Hour`→`golden-hour.webp`). Document the exact slug rule in code so `src` can be derived.

---

## Part C — Build plan for Claude Code

1. **Read** chunk 01 (`docs/01-design-spec.md`) Part A, this doc Part A, and the existing partials
   in `resources/views/rongberong/partials/config/`. Confirm the `.opt` pattern.
2. **CSS:** add `.opt--thumb`, `.opt-thumb`, `.opt-thumb--fallback`, `.opt-label`, selected/hover
   states, and the `.opts` grid, in `resources/css/app.css` (or the existing component CSS). Use brand
   tokens from chunk 01 §B.2.
3. **Markup:** update the option partials to the image-card markup (§B.1). Where options are built via
   `@foreach`, update the loop template once. **Keep every `data-v` and `data-group` exactly.**
   Add a small Blade helper or inline expression to derive the image path from `data-group` + slug(`data-v`).
4. **Fallback first:** ship with the `onerror` icon fallback so it works before all images exist.
5. **Images:** add real images under `public/img/options/...` per §B.3–B.4, starting with the
   **garment** group, then fabric, pattern, pose, lighting, bg (highest visual value first).
6. **Per-group default icons** for fallback (garment→shirt, model→user, lighting→sun, etc.).
7. **i18n:** no new strings expected; if any added, update both `lang/*.json` and `$jsKeys`.
8. **Run the Acceptance Checklist** below.

> Scope control: it's fine to land the markup+CSS+fallback first (works immediately), then fill
> images group-by-group in follow-up commits. Note progress in `docs/README.md` status.

---

## Acceptance Checklist
1. No console errors; `rongberong.js` still initializes.
2. Options render as image cards (thumb on top, label below) in all `.opt--thumb` groups.
3. Missing image → clean icon fallback, never a broken-image glyph.
4. Click an option → `.sel` toggles, thumb shows accent ring, `state` updates, `.fg-sel-count` updates.
5. Keyboard: focus an option, press Enter/Space → selects (a11y preserved).
6. Generate (photo) payload still sends the exact same `data-v` values as before this chunk.
7. Voice selection still highlights the right option card (it targets `[data-group][data-v]`).
8. EN and বাংলা labels both render under thumbnails; layout doesn't overflow in Bangla.
9. Mobile: cards wrap in a grid, tappable, ≥44px targets.
10. Page weight reasonable (images lazy-loaded, optimized).

---

## Reference summary
- **Pattern preserved:** `<span class="opt" data-v="…">` inside `<div class="opts" data-group="…">`,
  `.sel` for selected — extended with `.opt--thumb` + `<img>` + `.opt-label`.
- **Images:** free/CC0 sources (Unsplash/Pexels/Pixabay/Openverse/Wikimedia), optimized webp in
  `public/img/options/<group>/<slug>.webp`, with `onerror` icon fallback for incremental rollout.
- **Untouched:** selection engine, `data-v` values, `data-group` keys, endpoints, i18n keys, state shape.
