- Add IBrandingService field and DI constructor parameter to all 5 ViewModels
- Add optional IBrandingService? parameter to test constructors (PermissionsViewModel, StorageViewModel, UserAccessAuditViewModel)
- Assemble ReportBranding from GetMspLogoAsync + _currentProfile.ClientLogo before each WriteAsync call
- Pass branding as last parameter to WriteAsync in all ExportHtmlAsync methods
- Guard clause: branding assembly skipped (branding = null) when _brandingService is null (test constructors)
- Build: 0 warnings, 0 errors; tests: 254 passed / 0 failed / 26 skipped
- StorageViewModel: add OnGlobalSitesChanged, OnSiteUrlChanged, _hasLocalSiteOverride
- SearchViewModel: add OnGlobalSitesChanged, OnSiteUrlChanged, _hasLocalSiteOverride
- DuplicatesViewModel: add OnGlobalSitesChanged, OnSiteUrlChanged, _hasLocalSiteOverride
- FolderStructureViewModel: add OnGlobalSitesChanged, OnSiteUrlChanged, _hasLocalSiteOverride
- All four VMs pre-fill SiteUrl from first global site; local typing sets override flag
- Tenant switch resets _hasLocalSiteOverride in all four VMs
- DuplicatesViewModel: ModeFiles/Folders, criteria checkboxes, group flattening to DuplicateRow
- Uses TenantProfile site URL override pattern (ctx.Url is read-only)
- ExportHtmlCommand exports DuplicateGroup list via DuplicatesHtmlExportService
- DuplicatesView.xaml: type selector, criteria panel + flattened DataGrid
- DuplicatesView.xaml.cs: DI constructor with DataContext wiring