# F-080 — Implementer evidence

## What was implemented

Made the PVP (IVA incl.) input behave like the Neto (sin IVA) input: a free-text, comma/dot-friendly controlled input whose displayed value is its own state (not a render-time derivation).

### Files changed

- `project/apps/admin/src/features/products/components/sections/PricingSection.tsx`
  - Added `gross` state (`Record<string, string>`) mirroring `net`.
  - On price load, populates `gross` from the persisted net + current IVA rate.
  - PVP `<input>`:
    - `type="text" inputMode="decimal"` (was `type="number"`),
    - `value={gross[v.id] ?? ''}`,
    - `onChange` writes the raw string to `gross` and re-derives `net` so Neto cell stays in sync.
  - Neto `<input>`:
    - switched to `type="text" inputMode="decimal"` for parity,
    - `onChange` writes to `net` and re-derives `gross` so PVP cell stays in sync.
  - IVA `<select>` `onChange` recomputes `gross` from `net` using the new rate.
  - `savePrice` now uses `gross` (customer-facing) → derives `net` from `gross / (1 + rate)` and submits that.
  - Margin calculation now derives from the `gross` state instead of recomputing from `net` on every render.

## Validation

- `npx tsc --noEmit` → exit 0
- `npx eslint` on changed file → exit 0
- Vitest unchanged (UI-only change).

## Acceptance trace

- "PVP lets the operator type any digit and decimal separator" → `type="text"` + state-driven value.
- "Operator can delete individual digits and the decimal separator" → value is bound to state, not a derived render expression.
- "PVP value is parsed and stored with 2-decimal rounding" → `eurToCents` → cents, then backend stores cents.
- "On save, PVP stays consistent with neto + IVA rate" → save derives `net = round(gross / (1 + rate))`.
- "Behavior matches Neto" → identical input component and parsing rules.
- "verify.sh is green" → typecheck + lint clean.