---
phase: 20.1.1.1.1
plan: 01
subsystem: ui
tags: [slint, card-face, hover, layout, visual-polish]
dependency_graph:
  requires: []
  provides: [D-08-flicker-fix, D-09-button-alignment, D-11-square-scaling]
  affects: [crates/app/ui/card.slint, code_tips/SLINT_TIPS.md]
tech_stack:
  added: []
  patterns: [passive-hover-zone, slint-last-child-wins]
key_files:
  created: []
  modified:
    - crates/app/ui/card.slint
    - code_tips/SLINT_TIPS.md
decisions:
  - "D-08: persistent passive btn-zone TouchArea declared before conditional button content — eliminates has-hover feedback loop"
  - "D-09: button inner circle y=14px aligns with scaled item squares (not 18px vertical center of 80px row)"
  - "D-11: inner square 52x52 at y=14px (centered), stride 58px, sq-touch width 52px to match inner square"
metrics:
  duration: 8
  completed: "2026-04-15"
  tasks: 2
  files: 2
---

# Phase 20.1.1.1.1 Plan 01: Card Face Visual Defect Fixes (D-08/D-09/D-11) Summary

**One-liner:** Flicker-free product-add button via passive btn-zone TouchArea, scaled 52x52 item squares with 58px stride centered at y=14px, and button circle aligned at y=14px.

## Tasks Completed

| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Fix card.slint — hover flicker, button alignment, square scaling | 28c097d | crates/app/ui/card.slint |
| 2 | Document hover-flicker fix in SLINT_TIPS.md | 4f37c9c | code_tips/SLINT_TIPS.md |

## What Was Built

**D-08 (Hover flicker fix):** Added a persistent passive `btn-zone := TouchArea` at the `+` button position in Row 4. The TouchArea has no `clicked` handler — it only provides `has-hover`. The button visibility condition changed from `if card-hover-zone.has-hover` to `if card-hover-zone.has-hover || btn-zone.has-hover`. The passive zone is declared before the conditional button content so the inner `add-btn-touch` (last-declared) still wins click events per Slint's last-child-wins rule.

**D-11 (Scale product image squares and SN labels):** Inner image/initials Rectangle scaled from 44x44 to 52x52, centered in the 80px row at y=14px (computed as `(80-52)/2=14`). Outer per-square wrapper changed from 46px to 58px wide. Stride updated from `sq-index * 52px` to `sq-index * 58px`. SN/product-name labels repositioned to `y: 68px` (14+52+2) with `width: 58px` and `font-size: 10px`. `sq-touch` width updated to 52px to match the inner square. Hover label x offset updated to use 58px stride.

**D-09 (Button vertical alignment):** Inner `+` button circle `y` changed from `18px` to `14px` to top-align with item squares. Circle dimensions updated from 44x44 (border-radius 22) to 52x52 (border-radius 26) to match scaled squares. Outer button wrapper updated to `width: 52px`.

**Documentation:** Appended "Hover-conditional element flicker (TouchArea feedback loop)" tip to `code_tips/SLINT_TIPS.md` with problem description, root cause (Slint hit-testing routes cursor to deepest TouchArea), solution, code example, and child order rule.

## Verification

- `cargo check -p app` exits 0 (1 pre-existing unused variable warning, unrelated)
- `grep "btn-zone" crates/app/ui/card.slint` returns 2 matches (declaration + condition)
- `grep "58px" crates/app/ui/card.slint` returns 9 matches (stride, widths, x offsets)
- `grep "Hover-conditional" code_tips/SLINT_TIPS.md` returns 1 match

## Deviations from Plan

None — plan executed exactly as written.

## Known Stubs

None.

## Threat Flags

None — this plan modifies only Slint UI layout code and a documentation file. No network, auth, or data changes.

## Self-Check: PASSED

- crates/app/ui/card.slint: modified (verified via grep and cargo check)
- code_tips/SLINT_TIPS.md: modified (verified via grep)
- Commits 28c097d and 4f37c9c both exist in git log
