Build DuplicateComparisonPanel base two-column layout widget
epic-duplicate-activity-detection-core-logic-task-008 — Implement the DuplicateComparisonPanel Flutter widget with a responsive two-column layout rendering two ActivityRecord objects side by side. Each column displays the activity's contact name, date, type, duration, notes excerpt, and registration source. Apply design token typography and spacing. The panel must be self-contained and accept two ActivityRecord parameters with no service dependencies so it can be embedded in both the warning bottom sheet and the coordinator queue detail view.
Acceptance Criteria
Technical Requirements
Implementation Notes
Structure the widget as `DuplicateComparisonPanel` containing a `Row` of two `Expanded` `ActivityColumnCard` widgets with a thin `VerticalDivider` between them. `ActivityColumnCard` is a private `StatelessWidget` taking a single `ActivityRecord` and rendering `FieldRow` entries. `FieldRow` is a `Row` with a `Text` label (AppTypography.labelSmall, muted color) and a `Text` value (AppTypography.bodyMedium). Use `LayoutBuilder` to detect narrow viewports and switch to a `Column` layout.
Format dates with `intl` package's `DateFormat.yMMMd()` — use the device locale. Duration: display as 'X min' string. Notes excerpt: use `Text(..., maxLines: 3, overflow: TextOverflow.ellipsis)`. Pass `semanticsLabel` to `FieldRow` values — this is required for task-010's accessibility work.
Keep the widget free of BLoC/Riverpod `ref` usage — all data comes from the two `ActivityRecord` parameters.
Testing Requirements
Widget tests (flutter_test): render the panel with two ActivityRecord fixtures and verify all 6 fields appear in each column. Test vertical stacking below 360dp width using `tester.binding.window.physicalSizeTestValue`. Test overflow safety — notes longer than 3 lines must not cause RenderFlex overflow. Test with null/empty notes field (graceful empty state).
Golden test: generate and commit a golden image for the canonical two-column layout. Accessibility test: verify all text nodes are reachable by Semantics finder. Test const-constructibility.
If the duplicate check RPC fails due to a network error or Supabase outage, the service must decide whether to block submission entirely (safe but disruptive) or allow submission to proceed silently (functional but risks data duplication). An incorrect choice leads to either user frustration or data quality issues.
Mitigation & Contingency
Mitigation: Define an explicit error policy in the service: RPC failures result in a DuplicateCheckResult with status: 'check_failed' and no candidates. The caller treats this as 'allow submission, flag for async review'. Document this as the intended graceful degradation behaviour in the service interface contract.
Contingency: If stakeholders require blocking on RPC failure, expose a configurable `failMode` parameter in the service that can be toggled per organisation via the feature flag system without a code deployment.
The DuplicateComparisonPanel must handle varying activity schemas across organisations (NHF, HLF, Blindeforbundet each have different activity fields). A rigid layout may not accommodate all field variations, causing truncation or missing data in the comparison view.
Mitigation & Contingency
Mitigation: Design the panel to render a dynamic list of key-value pairs rather than a fixed-column layout. Define a `ComparisonField` model that each service populates with only the fields relevant to the activity type and organisation, allowing the panel to adapt without schema knowledge.
Contingency: If dynamic rendering proves too complex within the timeline, ship a simplified panel showing only the five most critical fields (peer mentor, activity type, date, chapter, submitter) and log a follow-up ticket for full field rendering in a later sprint.