---
task: Fix "Similar products already exist" modal layout — match-row cards unreadable on mobile (flex row squishes info text to single characters, Import button overlaps content)
cycles: 5
context: true
private: false
started: 2026-05-28T16:30:42Z
finished: 2026-05-28T16:31:11Z
---

## files
- resources/js/Pages/CreateProductUltimate.vue [lines 534-560] — fuzzy match modal template: `.match-row` items with thumb, info, button
- resources/js/Pages/CreateProductUltimate.vue [lines 875-914] — scoped CSS: `.match-row`, `.match-thumb`, `.match-info` and dark mode overrides

## steps
1. In `CreateProductUltimate.vue` template (lines 534-560), wrap the `FileImage` + `.match-info` div in a new `<div class="match-row-top">` inner wrapper, leaving the `<button>` outside it so the layout becomes: outer `.match-row` (column) → `.match-row-top` (thumb + info, row) + button (full-width, below)
2. Add `w-100` class to the Import button so it spans the full card width on mobile
3. In the scoped CSS, change `.match-row` from `align-items: center` flex-row to a `flex-direction: column; gap: 10px` column layout. Add `.match-row-top { display: flex; align-items: center; gap: 12px; }` rule.
4. Remove `align-items: center` from `.match-row` (it now stacks vertically, not horizontally)
5. Verify `.match-info { flex: 1; min-width: 0; }` stays on `.match-info` (unchanged — still needed inside `.match-row-top`)
6. Build: `npm run build` then `docker restart bukidbountyapp`

## context

Current template structure (lines 534-560):
```html
<div v-for="m in fuzzyMatches" :key="m.hashkey" class="match-row">
  <FileImage :src="..." class="match-thumb" fallback="..." />
  <div class="match-info">
    <div class="fw_6">{{ m.name }}</div>
    <div class="text-muted small">
      <span v-if="m.category">{{ m.category }}<span v-if="m.subcategory"> · {{ m.subcategory }}</span> · </span>
      <span>₱{{ m.price }} / {{ m.unitname }}</span>
    </div>
    <div v-if="m.already_in_store" class="text-success smallest mt-1">...</div>
  </div>
  <button class="btn btn-sm btn-primary rounded-pill" :disabled="m.already_in_store || isImporting" @click="importExistingProduct(m)">
    <span v-if="isImporting"><LoadingSpinner size="small" /></span>
    <span v-else-if="m.already_in_store">In Store</span>
    <span v-else>Import to Store</span>
  </button>
</div>
```

Target template structure:
```html
<div v-for="m in fuzzyMatches" :key="m.hashkey" class="match-row">
  <div class="match-row-top">
    <FileImage :src="..." class="match-thumb" fallback="..." />
    <div class="match-info">
      <div class="fw_6">{{ m.name }}</div>
      <div class="text-muted small">
        <span v-if="m.category">{{ m.category }}<span v-if="m.subcategory"> · {{ m.subcategory }}</span> · </span>
        <span>₱{{ m.price }} / {{ m.unitname }}</span>
      </div>
      <div v-if="m.already_in_store" class="text-success smallest mt-1">...</div>
    </div>
  </div>
  <button class="btn btn-sm btn-primary rounded-pill w-100" :disabled="m.already_in_store || isImporting" @click="importExistingProduct(m)">
    ...
  </button>
</div>
```

Current CSS (lines 875-890):
```css
.match-row {
  display: flex;
  align-items: center;   /* ← causes single-column squish when button competes for width */
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid #f1f5f9;
}
.match-thumb { width: 56px; height: 56px; border-radius: 10px; object-fit: cover; flex-shrink: 0; }
.match-info { flex: 1; min-width: 0; }
```

Target CSS additions/changes:
```css
.match-row {
  display: flex;
  flex-direction: column;   /* vertical stack: top-row then button */
  gap: 10px;
  padding: 12px 0;
  border-bottom: 1px solid #f1f5f9;
}
.match-row-top {
  display: flex;
  align-items: center;
  gap: 12px;
}
/* .match-thumb and .match-info stay unchanged */
```

## notes
- dictionary: ai-docs/dictionary.md
- linters: none
- constraints: `.bb-modal*` styles are scoped to `CreateProductUltimate.vue` — do NOT touch global CSS. Dark mode override `:global(.dark-mode) .match-row` at line 914 only sets `border-bottom-color` — no changes needed there.
- build: `npm run build` then `docker restart bukidbountyapp` (see dictionary Build & Deployment Standards)
