{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "compliance-sanctions-screener",
  "title": "Compliance Sanctions Screener",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/compliance-sanctions-screener/compliance-sanctions-screener.component.ts",
      "content": "// AML/KYC OFAC, Politically Exposed Persons (PEP), and global sanctions list screening\n// workbench with fuzzy match threshold tuning, real-time entity inspection modal, and\n// prohibited match enforcement. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  AlertTriangle,\n  Ban,\n  Building2,\n  Check,\n  CheckCircle2,\n  Eye,\n  FileSearch,\n  Globe,\n  Info,\n  LucideAngularModule,\n  RefreshCw,\n  RotateCcw,\n  Search,\n  ShieldAlert,\n  ShieldCheck,\n  ShieldX,\n  Sliders,\n  User,\n  Users,\n  X,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport {\n  UiSelectComponent,\n  UiSelectContentComponent,\n  UiSelectItemComponent,\n  UiSelectTriggerComponent,\n  UiSelectValueComponent,\n} from '@/ui/select/select.component'\nimport { UiSliderComponent } from '@/ui/slider/slider.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\nimport type { EntityType, SanctionRecord } from './compliance-sanctions-types'\nimport { defaultSanctionRecords } from './compliance-sanctions-data'\nimport { UiSanctionsInvestigationDialogComponent } from './sanctions-investigation-dialog.component'\n\nexport type { EntityType, SanctionRecord }\n\nfunction cloneRecords(records: SanctionRecord[]): SanctionRecord[] {\n  return JSON.parse(JSON.stringify(records)) as SanctionRecord[]\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-compliance-sanctions-screener, [ui-compliance-sanctions-screener]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiInputComponent,\n    UiSanctionsInvestigationDialogComponent,\n    UiSelectComponent,\n    UiSelectContentComponent,\n    UiSelectItemComponent,\n    UiSelectTriggerComponent,\n    UiSelectValueComponent,\n    UiSliderComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <div data-slot=\"compliance-sanctions-screener\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <div class=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\">\n        <div>\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <h1 class=\"text-xl font-bold tracking-tight sm:text-2xl\">AML / OFAC Sanctions &amp; PEP Screening</h1>\n            <span ui-badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success gap-1.5 py-0.5\">\n              <span class=\"bg-success size-1.5 animate-pulse rounded-full\"></span>\n              <span class=\"font-medium\">OFAC SDN, EU Consolidated, UK HMT, UN Sanctions · Synced 10m ago</span>\n            </span>\n          </div>\n          <p class=\"text-muted-foreground mt-1 text-xs sm:text-sm\">\n            Automated identity verification, Politically Exposed Persons (PEP), and multilateral sanctions screening\n            workbench.\n          </p>\n        </div>\n\n        <div class=\"flex shrink-0 items-center gap-2\">\n          <button\n            ui-button\n            variant=\"default\"\n            size=\"sm\"\n            [disabled]=\"isBatchScreening()\"\n            class=\"cursor-pointer gap-2 shadow-xs\"\n            (click)=\"handleRunBatchScreening()\"\n          >\n            <lucide-icon [img]=\"RefreshCw\" [class]=\"batchIconClass\" />\n            <span>{{ isBatchScreening() ? 'Screening 1,420 Records...' : 'Run Batch Screening' }}</span>\n          </button>\n        </div>\n      </div>\n\n      <!-- Notification Toast / Banner -->\n      @if (notificationBanner(); as banner) {\n        <div [class]=\"bannerClass(banner.type)\">\n          <div class=\"flex min-w-0 items-center gap-2\">\n            @switch (banner.type) {\n              @case ('success') {\n                <lucide-icon [img]=\"CheckCircle2\" class=\"size-4 shrink-0\" />\n              }\n              @case ('warning') {\n                <lucide-icon [img]=\"AlertTriangle\" class=\"size-4 shrink-0\" />\n              }\n              @case ('destructive') {\n                <lucide-icon [img]=\"Ban\" class=\"size-4 shrink-0\" />\n              }\n              @default {\n                <lucide-icon [img]=\"Info\" class=\"size-4 shrink-0\" />\n              }\n            }\n            <span>{{ banner.message }}</span>\n          </div>\n          <button\n            aria-label=\"Dismiss notification\"\n            type=\"button\"\n            class=\"rounded-md p-1 transition-colors hover:bg-black/5 dark:hover:bg-white/10\"\n            (click)=\"notificationBanner.set(null)\"\n          >\n            <lucide-icon [img]=\"X\" class=\"size-3.5\" />\n          </button>\n        </div>\n      }\n\n      <!-- 4 Screening Telemetry Cards -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        <!-- Card 1: Total Screened -->\n        <div ui-card class=\"border-border/80 border shadow-xs\">\n          <div ui-card-content class=\"p-4 sm:p-5\">\n            <div class=\"flex items-center justify-between\">\n              <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\"\n                >Total Screened Today</span\n              >\n              <div class=\"bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"Users\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-3 flex items-baseline gap-2\">\n              <span class=\"text-2xl font-bold tracking-tight tabular-nums\">{{\n                totalScreenedCount.toLocaleString()\n              }}</span>\n              <span class=\"text-muted-foreground text-xs font-medium\">Entities</span>\n            </div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">\n              <span class=\"text-success font-medium\">+14.2%</span> vs yesterday · 38 automated batches\n            </p>\n          </div>\n        </div>\n\n        <!-- Card 2: Clear / No Matches -->\n        <div ui-card class=\"border-border/80 border shadow-xs\">\n          <div ui-card-content class=\"p-4 sm:p-5\">\n            <div class=\"flex items-center justify-between\">\n              <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Clear / No Matches</span>\n              <div class=\"bg-success/10 text-success flex size-8 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"ShieldCheck\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-3 flex items-baseline gap-2\">\n              <span class=\"text-success text-2xl font-bold tracking-tight tabular-nums\">\n                {{ clearedCount().toLocaleString() }}\n              </span>\n              <span class=\"text-success text-xs font-semibold tabular-nums\">Cleared · 99.2%</span>\n            </div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">Low Risk · 0 PEP matches · 0 adverse media</p>\n          </div>\n        </div>\n\n        <!-- Card 3: Potential Matches Flagged -->\n        <div ui-card class=\"border-border/80 border shadow-xs\">\n          <div ui-card-content class=\"p-4 sm:p-5\">\n            <div class=\"flex items-center justify-between\">\n              <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\"\n                >Potential Matches Flagged</span\n              >\n              <div class=\"bg-warning/10 text-warning flex size-8 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"AlertTriangle\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-3 flex items-baseline gap-2\">\n              <span class=\"text-warning text-2xl font-bold tracking-tight tabular-nums\">\n                {{ flaggedCount() }}\n              </span>\n              <span class=\"text-warning text-xs font-semibold\">Pending Review</span>\n            </div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">Action required · SLA &lt;2h · 1 high confidence</p>\n          </div>\n        </div>\n\n        <!-- Card 4: Confirmed Prohibited Matches -->\n        <div ui-card class=\"border-border/80 border shadow-xs\">\n          <div ui-card-content class=\"p-4 sm:p-5\">\n            <div class=\"flex items-center justify-between\">\n              <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\"\n                >Confirmed Prohibited Matches</span\n              >\n              <div class=\"bg-destructive/10 text-destructive flex size-8 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"Ban\" class=\"size-4\" />\n              </div>\n            </div>\n            <div class=\"mt-3 flex items-baseline gap-2\">\n              <span\n                class=\"text-2xl font-bold tracking-tight tabular-nums\"\n                [class]=\"blockedCount() > 0 ? 'text-destructive' : 'text-foreground'\"\n              >\n                {{ blockedCount() }}\n              </span>\n              <span class=\"text-muted-foreground text-xs font-semibold\">Blocked</span>\n            </div>\n            <p class=\"text-muted-foreground mt-1 text-xs\">Asset freeze locked · FinCEN SAR ready</p>\n          </div>\n        </div>\n      </div>\n\n      <!-- Real-Time Entity Search Bar & Fuzzy Threshold Workbench -->\n      <div ui-card class=\"border-border/80 bg-card border shadow-xs\">\n        <div ui-card-content class=\"space-y-4 p-4 sm:p-5\">\n          <div class=\"grid grid-cols-1 items-end gap-4 md:grid-cols-12\">\n            <!-- Search Input -->\n            <div class=\"space-y-1.5 md:col-span-4\">\n              <label for=\"entity-search-input\" class=\"text-foreground flex items-center gap-1.5 text-xs font-medium\">\n                <lucide-icon [img]=\"Search\" class=\"text-muted-foreground size-3.5\" />\n                <span>Search Individual / Entity Name</span>\n              </label>\n              <div class=\"relative\">\n                <ui-input\n                  id=\"entity-search-input\"\n                  [value]=\"searchQuery()\"\n                  (valueChange)=\"searchQuery.set($event)\"\n                  type=\"text\"\n                  placeholder=\"Search name, alias, ID or passport...\"\n                  class=\"bg-background pl-8 text-xs sm:text-sm\"\n                />\n                <lucide-icon\n                  [img]=\"Search\"\n                  class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\"\n                />\n                @if (searchQuery()) {\n                  <button\n                    aria-label=\"Clear search\"\n                    type=\"button\"\n                    class=\"text-muted-foreground hover:text-foreground absolute top-1/2 right-2.5 -translate-y-1/2\"\n                    (click)=\"searchQuery.set('')\"\n                  >\n                    <lucide-icon [img]=\"X\" class=\"size-3.5\" />\n                  </button>\n                }\n              </div>\n            </div>\n\n            <!-- Country Filter Dropdown -->\n            <div class=\"space-y-1.5 md:col-span-3\">\n              <span class=\"text-foreground flex items-center gap-1.5 text-xs font-medium\">\n                <lucide-icon [img]=\"Globe\" class=\"text-muted-foreground size-3.5\" />\n                <span>Country / Domicile Filter</span>\n              </span>\n              <ui-select [value]=\"selectedCountry()\" (valueChange)=\"selectedCountry.set($event)\">\n                <button ui-select-trigger class=\"bg-background w-full text-xs sm:text-sm\">\n                  <ui-select-value placeholder=\"All Countries\" />\n                </button>\n                <ui-select-content>\n                  <ui-select-item value=\"all\">All Countries</ui-select-item>\n                  <ui-select-item value=\"Russia\">Russia (Russian Federation)</ui-select-item>\n                  <ui-select-item value=\"United States\">United States (USA)</ui-select-item>\n                  <ui-select-item value=\"Cyprus\">Cyprus (EU)</ui-select-item>\n                  <ui-select-item value=\"United Kingdom\">United Kingdom (UK)</ui-select-item>\n                  <ui-select-item value=\"Switzerland\">Switzerland (CH)</ui-select-item>\n                  <ui-select-item value=\"United Arab Emirates\">United Arab Emirates (UAE)</ui-select-item>\n                </ui-select-content>\n              </ui-select>\n            </div>\n\n            <!-- Entity Type Pills -->\n            <div class=\"space-y-1.5 md:col-span-2\">\n              <span class=\"text-foreground flex items-center gap-1.5 text-xs font-medium\">\n                <lucide-icon [img]=\"Building2\" class=\"text-muted-foreground size-3.5\" />\n                <span>Entity Type</span>\n              </span>\n              <div class=\"bg-muted border-input flex h-9 items-center gap-1 rounded-md border p-1\">\n                <button type=\"button\" [class]=\"entityPillClass('all')\" (click)=\"selectedEntityType.set('all')\">\n                  All\n                </button>\n                <button\n                  type=\"button\"\n                  [class]=\"entityPillClass('individual')\"\n                  (click)=\"selectedEntityType.set('individual')\"\n                >\n                  Indiv.\n                </button>\n                <button\n                  type=\"button\"\n                  [class]=\"entityPillClass('corporate')\"\n                  (click)=\"selectedEntityType.set('corporate')\"\n                >\n                  Corp.\n                </button>\n              </div>\n            </div>\n\n            <!-- Match Threshold Slider -->\n            <div class=\"space-y-1.5 md:col-span-3\">\n              <div class=\"flex flex-wrap items-center justify-between gap-x-2 gap-y-1\">\n                <span class=\"text-foreground flex items-center gap-1.5 text-xs font-medium\">\n                  <lucide-icon [img]=\"Sliders\" class=\"text-muted-foreground size-3.5\" />\n                  <span>Match Threshold</span>\n                </span>\n                <span ui-badge variant=\"secondary\" class=\"text-xs font-semibold tabular-nums\">\n                  {{ currentThreshold() }}% Fuzzy Match\n                </span>\n              </div>\n              <div class=\"pt-1.5\">\n                <ui-slider\n                  [value]=\"thresholdValue()\"\n                  (valueChange)=\"onThresholdChange($event)\"\n                  [min]=\"50\"\n                  [max]=\"100\"\n                  [step]=\"1\"\n                  class=\"w-full\"\n                />\n              </div>\n            </div>\n          </div>\n\n          <!-- Filter helper status bar -->\n          <div\n            class=\"border-border/60 text-muted-foreground flex flex-wrap items-center justify-between gap-2 border-t pt-2 text-xs\"\n          >\n            <div class=\"flex min-w-0 items-center gap-2\">\n              <span\n                >Showing <strong class=\"text-foreground tabular-nums\">{{ filteredRecords().length }}</strong> of\n                <strong class=\"text-foreground tabular-nums\">{{ records().length }}</strong> screening audit\n                records</span\n              >\n              @if (searchQuery() || selectedCountry() !== 'all' || selectedEntityType() !== 'all') {\n                <span class=\"text-muted-foreground/60\">· Filters applied</span>\n              }\n            </div>\n            <div class=\"flex min-w-0 items-center gap-2\">\n              @if (\n                searchQuery() ||\n                selectedCountry() !== 'all' ||\n                selectedEntityType() !== 'all' ||\n                currentThreshold() !== 85\n              ) {\n                <button\n                  ui-button\n                  variant=\"ghost\"\n                  size=\"sm\"\n                  class=\"text-muted-foreground hover:text-foreground h-7 gap-1 text-xs\"\n                  (click)=\"handleResetFilters()\"\n                >\n                  <lucide-icon [img]=\"RotateCcw\" class=\"size-3\" />\n                  <span>Reset Filters</span>\n                </button>\n              }\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Screening Match Results Table -->\n      <div ui-card class=\"border-border/80 overflow-hidden border shadow-xs\">\n        <div class=\"border-border/60 border-b p-4 pb-3 sm:p-5\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div>\n              <h3 class=\"text-base font-semibold\">Active Screening Queue &amp; Target List Matches</h3>\n              <p class=\"text-muted-foreground mt-0.5 text-xs\">\n                Real-time fuzzy scoring across OFAC SDN, Sectoral SSI, EU Restrictive Measures, and UN Security Council\n                lists.\n              </p>\n            </div>\n            <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n              <span class=\"bg-warning inline-block size-2 rounded-full\"></span>\n              <span>Amber: Requires Review</span>\n              <span class=\"bg-destructive ml-2 inline-block size-2 rounded-full\"></span>\n              <span>Red: Prohibited Asset Freeze</span>\n            </div>\n          </div>\n        </div>\n\n        <div class=\"overflow-x-auto\">\n          <table ui-table>\n            <thead ui-table-header class=\"bg-muted/40\">\n              <tr ui-table-row>\n                <th ui-table-head class=\"min-w-[220px]\">Entity Name &amp; Classification</th>\n                <th ui-table-head class=\"min-w-[140px]\">Match Score &amp; Status</th>\n                <th ui-table-head class=\"min-w-[200px]\">Designated Watchlist / Program</th>\n                <th ui-table-head class=\"min-w-[220px]\">Matched Attributes</th>\n                <th ui-table-head class=\"min-w-[130px]\">Jurisdiction</th>\n                <th ui-table-head class=\"min-w-[220px] text-right\">Actions</th>\n              </tr>\n            </thead>\n            <tbody ui-table-body>\n              @for (record of filteredRecords(); track record.id) {\n                <tr ui-table-row [class]=\"rowClass(record.matchStatus)\">\n                  <!-- 1. Entity Name & Classification -->\n                  <td ui-table-cell class=\"py-3.5 align-top font-medium\">\n                    <div class=\"flex items-start gap-2.5\">\n                      <div [class]=\"avatarClass(record.entityType)\">\n                        @if (record.entityType === 'individual') {\n                          <lucide-icon [img]=\"User\" class=\"size-4\" />\n                        } @else {\n                          <lucide-icon [img]=\"Building2\" class=\"size-4\" />\n                        }\n                      </div>\n                      <div>\n                        <div class=\"flex items-center gap-1.5\">\n                          <span class=\"text-foreground font-semibold\">{{ record.entityName }}</span>\n                          <span ui-badge variant=\"outline\" class=\"px-1.5 py-0 text-xs uppercase\">\n                            {{ record.entityType }}\n                          </span>\n                        </div>\n                        @if (record.originalScript) {\n                          <p class=\"text-muted-foreground mt-0.5 text-xs\">\n                            {{ record.originalScript }}\n                          </p>\n                        }\n                        @if (record.aliases && record.aliases.length > 0) {\n                          <div class=\"text-muted-foreground/80 mt-1 flex flex-wrap gap-1 text-xs\">\n                            <span class=\"font-medium\">AKAs:</span>\n                            <span>{{ aliasPreview(record) }}</span>\n                          </div>\n                        }\n                      </div>\n                    </div>\n                  </td>\n\n                  <!-- 2. Match Score & Status -->\n                  <td ui-table-cell class=\"py-3.5 align-top\">\n                    <div class=\"space-y-1\">\n                      @if (record.matchStatus === 'blocked') {\n                        <div>\n                          <span ui-badge variant=\"destructive\" class=\"gap-1 text-xs font-semibold\">\n                            <lucide-icon [img]=\"Ban\" class=\"size-3\" />\n                            <span>Blocked &amp; Frozen</span>\n                          </span>\n                        </div>\n                      } @else if (record.matchStatus === 'cleared_false_positive') {\n                        <div>\n                          <span\n                            ui-badge\n                            variant=\"outline\"\n                            class=\"border-success/30 bg-success/10 text-success gap-1 text-xs font-semibold\"\n                          >\n                            <lucide-icon [img]=\"CheckCircle2\" class=\"size-3\" />\n                            <span>Cleared (False Positive)</span>\n                          </span>\n                        </div>\n                      } @else if (record.matchScore >= 95) {\n                        <div>\n                          <span ui-badge variant=\"destructive\" class=\"gap-1 text-xs font-semibold tabular-nums\">\n                            <lucide-icon [img]=\"ShieldX\" class=\"size-3\" />\n                            <span>{{ record.matchScore }}% Critical Match</span>\n                          </span>\n                        </div>\n                      } @else if (record.matchScore >= currentThreshold()) {\n                        <div>\n                          <span\n                            ui-badge\n                            variant=\"outline\"\n                            class=\"border-warning/40 bg-warning/15 text-warning gap-1 text-xs font-semibold tabular-nums\"\n                          >\n                            <lucide-icon [img]=\"AlertTriangle\" class=\"size-3\" />\n                            <span>{{ record.matchScore }}% Match</span>\n                          </span>\n                        </div>\n                      } @else {\n                        <div>\n                          <span\n                            ui-badge\n                            variant=\"outline\"\n                            class=\"border-success/30 bg-success/10 text-success gap-1 text-xs font-semibold tabular-nums\"\n                          >\n                            <lucide-icon [img]=\"Check\" class=\"size-3\" />\n                            <span>{{ record.matchScore }}% Match · Clear</span>\n                          </span>\n                        </div>\n                      }\n\n                      <div class=\"text-muted-foreground text-xs tabular-nums\">Screened {{ record.lastScreened }}</div>\n                    </div>\n                  </td>\n\n                  <!-- 3. Target Sanctions List & Programs -->\n                  <td ui-table-cell class=\"py-3.5 align-top\">\n                    <div class=\"space-y-1\">\n                      <div class=\"text-foreground text-xs font-medium\">\n                        {{ record.sanctionList }}\n                      </div>\n                      <div class=\"text-muted-foreground line-clamp-2 text-xs\">\n                        {{ record.program }}\n                      </div>\n                      @if (record.pepLevel) {\n                        <div class=\"text-warning text-xs font-medium\">\n                          {{ record.pepLevel }}\n                        </div>\n                      }\n                    </div>\n                  </td>\n\n                  <!-- 4. Matched Attributes -->\n                  <td ui-table-cell class=\"py-3.5 align-top\">\n                    <div class=\"space-y-1 text-xs\">\n                      <div class=\"text-foreground font-medium\">\n                        {{ record.matchedAttributesSummary }}\n                      </div>\n                      <div class=\"text-muted-foreground tabular-nums\">ID: {{ record.nationalIdOrLei }}</div>\n                      <div class=\"text-muted-foreground max-w-[240px] truncate\">\n                        {{ record.address }}\n                      </div>\n                    </div>\n                  </td>\n\n                  <!-- 5. Jurisdiction -->\n                  <td ui-table-cell class=\"py-3.5 align-top\">\n                    <div class=\"space-y-1 text-xs\">\n                      <div class=\"text-foreground flex items-center gap-1 font-medium\">\n                        <lucide-icon [img]=\"Globe\" class=\"text-muted-foreground size-3 shrink-0\" />\n                        <span>{{ record.country }}</span>\n                      </div>\n                      <div class=\"text-muted-foreground\">\n                        {{ record.jurisdiction }}\n                      </div>\n                    </div>\n                  </td>\n\n                  <!-- 6. Actions -->\n                  <td ui-table-cell class=\"py-3.5 text-right align-top\">\n                    <div class=\"flex flex-col items-end justify-end gap-1.5 sm:flex-row sm:items-center\">\n                      <button\n                        ui-button\n                        variant=\"outline\"\n                        size=\"sm\"\n                        class=\"h-8 cursor-pointer gap-1.5 text-xs\"\n                        (click)=\"openInvestigation(record)\"\n                      >\n                        <lucide-icon [img]=\"Eye\" class=\"size-3.5\" />\n                        <span>Review Match</span>\n                      </button>\n\n                      @if (\n                        record.id === 'SANCT-2026-001' &&\n                        record.matchStatus !== 'cleared_false_positive' &&\n                        record.matchStatus !== 'blocked'\n                      ) {\n                        <button\n                          ui-button\n                          variant=\"ghost\"\n                          size=\"sm\"\n                          class=\"text-success hover:bg-success/10 hover:text-success h-8 cursor-pointer gap-1 text-xs\"\n                          (click)=\"handleClearFalsePositive(record)\"\n                        >\n                          <lucide-icon [img]=\"Check\" class=\"size-3.5\" />\n                          <span>Clear False Positive</span>\n                        </button>\n                        <button\n                          ui-button\n                          variant=\"destructive\"\n                          size=\"sm\"\n                          class=\"h-8 cursor-pointer gap-1 text-xs\"\n                          (click)=\"handleBlockEntity(record)\"\n                        >\n                          <lucide-icon [img]=\"Ban\" class=\"size-3.5\" />\n                          <span>Block &amp; Freeze</span>\n                        </button>\n                      }\n\n                      @if (record.id === 'SANCT-2026-004' && record.matchStatus !== 'blocked') {\n                        <button\n                          ui-button\n                          variant=\"destructive\"\n                          size=\"sm\"\n                          class=\"h-8 cursor-pointer gap-1 text-xs\"\n                          (click)=\"handleBlockEntity(record)\"\n                        >\n                          <lucide-icon [img]=\"Ban\" class=\"size-3.5\" />\n                          <span>Block Entity</span>\n                        </button>\n                      }\n                    </div>\n                  </td>\n                </tr>\n              }\n\n              @if (filteredRecords().length === 0) {\n                <tr ui-table-row>\n                  <td ui-table-cell colspan=\"6\" class=\"text-muted-foreground py-10 text-center\">\n                    <div class=\"flex flex-col items-center justify-center gap-2\">\n                      <lucide-icon [img]=\"FileSearch\" class=\"text-muted-foreground/50 size-8\" />\n                      <p class=\"text-sm font-medium\">No matching screening records found</p>\n                      <p class=\"text-xs\">Adjust your search keyword, country filter, or match threshold.</p>\n                      <button ui-button variant=\"outline\" size=\"sm\" class=\"mt-2 text-xs\" (click)=\"handleResetFilters()\">\n                        Reset Filters\n                      </button>\n                    </div>\n                  </td>\n                </tr>\n              }\n            </tbody>\n          </table>\n        </div>\n      </div>\n\n      <!-- Sanction Match Investigation Modal / Dialog -->\n      <ui-sanctions-investigation-dialog\n        [open]=\"isInvestigationOpen()\"\n        (openChange)=\"isInvestigationOpen.set($event)\"\n        [selectedRecord]=\"selectedRecord()\"\n        [thresholdValue]=\"currentThreshold()\"\n        (clear)=\"handleClearFalsePositive($event)\"\n        (escalate)=\"handleEscalate($event)\"\n        (block)=\"handleBlockEntity($event)\"\n      />\n    </div>\n  `,\n})\nexport class UiComplianceSanctionsScreenerComponent {\n  protected readonly AlertTriangle = AlertTriangle\n  protected readonly Ban = Ban\n  protected readonly Building2 = Building2\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Eye = Eye\n  protected readonly FileSearch = FileSearch\n  protected readonly Globe = Globe\n  protected readonly Info = Info\n  protected readonly RefreshCw = RefreshCw\n  protected readonly RotateCcw = RotateCcw\n  protected readonly Search = Search\n  protected readonly ShieldAlert = ShieldAlert\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly ShieldX = ShieldX\n  protected readonly Sliders = Sliders\n  protected readonly User = User\n  protected readonly Users = Users\n  protected readonly X = X\n\n  @Input() set initialSearch(v: string | undefined) {\n    if (v !== undefined) this.searchQuery.set(v)\n  }\n  @Input() set initialCountry(v: string | undefined) {\n    if (v !== undefined) this.selectedCountry.set(v)\n  }\n  @Input() set initialThreshold(v: number | undefined) {\n    if (v !== undefined) this.thresholdValue.set([v])\n  }\n  @Input() set initialRecords(v: SanctionRecord[] | undefined) {\n    if (v) this.records.set(cloneRecords(v))\n  }\n  @Input('class') className?: string\n\n  readonly searchQuery = signal('Viktor Ivanov')\n  readonly selectedCountry = signal('all')\n  readonly selectedEntityType = signal<'all' | EntityType>('all')\n  readonly thresholdValue = signal<number[]>([85])\n  readonly records = signal<SanctionRecord[]>(cloneRecords(defaultSanctionRecords))\n\n  readonly isBatchScreening = signal(false)\n  readonly notificationBanner = signal<{\n    message: string\n    type: 'success' | 'warning' | 'info' | 'destructive'\n  } | null>(null)\n  readonly selectedRecord = signal<SanctionRecord | null>(null)\n  readonly isInvestigationOpen = signal(false)\n  private bannerTimer: ReturnType<typeof setTimeout> | undefined\n  private batchTimer: ReturnType<typeof setTimeout> | undefined\n\n  readonly totalScreenedCount = 1420\n\n  readonly currentThreshold = computed(() => this.thresholdValue()[0] ?? 85)\n\n  readonly filteredRecords = computed(() => {\n    const q = this.searchQuery().toLowerCase().trim()\n    const country = this.selectedCountry()\n    const entityType = this.selectedEntityType()\n    return this.records().filter((record) => {\n      if (q) {\n        const matchesName = record.entityName.toLowerCase().includes(q)\n        const matchesAlias = record.aliases.some((a) => a.toLowerCase().includes(q))\n        const matchesList = record.sanctionList.toLowerCase().includes(q)\n        const matchesId = record.nationalIdOrLei.toLowerCase().includes(q)\n        const matchesSummary = record.matchedAttributesSummary.toLowerCase().includes(q)\n        if (!matchesName && !matchesAlias && !matchesList && !matchesId && !matchesSummary) return false\n      }\n      if (country !== 'all' && record.country !== country) return false\n      if (entityType !== 'all' && record.entityType !== entityType) return false\n      return true\n    })\n  })\n\n  readonly clearedCount = computed(() => {\n    const baseCleared = 1408\n    const additionalCleared = this.records().filter((r) => r.matchStatus === 'cleared_false_positive').length\n    const newlyBlocked = this.records().filter((r) => r.matchStatus === 'blocked').length\n    return baseCleared + additionalCleared - newlyBlocked\n  })\n\n  readonly flaggedCount = computed(() => {\n    const basePending = 12\n    const cleared = this.records().filter((r) => r.matchStatus === 'cleared_false_positive').length\n    const blocked = this.records().filter((r) => r.matchStatus === 'blocked').length\n    return Math.max(0, basePending - cleared - blocked)\n  })\n\n  readonly blockedCount = computed(() => this.records().filter((r) => r.matchStatus === 'blocked').length)\n\n  get rootClass(): string {\n    return cn('text-foreground w-full space-y-6', this.className)\n  }\n\n  get batchIconClass(): string {\n    return cn('size-4', this.isBatchScreening() && 'animate-spin')\n  }\n\n  bannerClass(type: string): string {\n    return cn(\n      'flex items-center justify-between gap-3 rounded-lg border px-4 py-3 text-xs transition-colors duration-200 sm:text-sm',\n      type === 'success' && 'border-success/30 bg-success/10 text-success',\n      type === 'warning' && 'border-warning/30 bg-warning/10 text-warning',\n      type === 'destructive' && 'bg-destructive/10 border-destructive/30 text-destructive',\n      type === 'info' && 'bg-primary/10 border-primary/20 text-primary',\n    )\n  }\n\n  entityPillClass(value: 'all' | EntityType): string {\n    return cn(\n      'flex-1 rounded px-2 py-1 text-xs font-medium transition-colors',\n      this.selectedEntityType() === value\n        ? 'bg-background text-foreground shadow-xs'\n        : 'text-muted-foreground hover:text-foreground',\n    )\n  }\n\n  rowClass(status: string): string {\n    return cn(\n      'hover:bg-muted/30 transition-colors',\n      status === 'potential_match' && 'bg-warning/[0.02]',\n      status === 'prohibited_match' && 'bg-destructive/[0.03]',\n      status === 'blocked' && 'bg-destructive/[0.06] opacity-90',\n    )\n  }\n\n  avatarClass(entityType: EntityType): string {\n    return cn(\n      'mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg text-xs font-bold',\n      entityType === 'individual' ? 'bg-primary/10 text-primary' : 'bg-secondary text-secondary-foreground',\n    )\n  }\n\n  aliasPreview(record: SanctionRecord): string {\n    const shown = record.aliases.slice(0, 2).join(', ')\n    return record.aliases.length > 2 ? `${shown} (+${record.aliases.length - 2} more)` : shown\n  }\n\n  onThresholdChange(value: number[] | number): void {\n    this.thresholdValue.set(Array.isArray(value) ? value : [value])\n  }\n\n  openInvestigation(record: SanctionRecord): void {\n    this.selectedRecord.set(record)\n    this.isInvestigationOpen.set(true)\n  }\n\n  showNotification(message: string, type: 'success' | 'warning' | 'info' | 'destructive' = 'info'): void {\n    this.notificationBanner.set({ message, type })\n    clearTimeout(this.bannerTimer)\n    this.bannerTimer = setTimeout(() => {\n      if (this.notificationBanner()?.message === message) this.notificationBanner.set(null)\n    }, 4500)\n  }\n\n  handleRunBatchScreening(): void {\n    this.isBatchScreening.set(true)\n    clearTimeout(this.batchTimer)\n    this.batchTimer = setTimeout(() => {\n      this.isBatchScreening.set(false)\n      this.showNotification(\n        'Batch screening completed. 1,420 entities cross-referenced against 4 global registries. 12 matches flagged.',\n        'success',\n      )\n    }, 1200)\n  }\n\n  private patchRecord(record: SanctionRecord, patch: Partial<SanctionRecord>): void {\n    this.records.update((prev) => prev.map((r) => (r.id === record.id ? { ...r, ...patch } : r)))\n    const selected = this.selectedRecord()\n    if (selected && selected.id === record.id) this.selectedRecord.set({ ...selected, ...patch })\n  }\n\n  handleClearFalsePositive(record: SanctionRecord): void {\n    this.patchRecord(record, { matchStatus: 'cleared_false_positive' })\n    this.showNotification(\n      `False positive cleared for \"${record.entityName}\". Compliance audit log logged with officer signature.`,\n      'success',\n    )\n  }\n\n  handleBlockEntity(record: SanctionRecord): void {\n    this.patchRecord(record, { matchStatus: 'blocked' })\n    this.showNotification(\n      `Entity \"${record.entityName}\" confirmed PROHIBITED. Asset freeze locked and SAR report staged for FinCEN / EU MLRO.`,\n      'destructive',\n    )\n  }\n\n  handleEscalate(record: SanctionRecord): void {\n    this.showNotification(\n      `Case for \"${record.entityName}\" escalated to Senior Compliance Officer & Legal Counsel for review.`,\n      'warning',\n    )\n    this.isInvestigationOpen.set(false)\n  }\n\n  handleResetFilters(): void {\n    this.searchQuery.set('')\n    this.selectedCountry.set('all')\n    this.selectedEntityType.set('all')\n    this.thresholdValue.set([85])\n    this.showNotification('Filters reset to default workbench view.', 'info')\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/compliance-sanctions-screener/compliance-sanctions-screener.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/compliance-sanctions-screener/sanctions-investigation-dialog.component.ts",
      "content": "// Sanction match investigation & attribute comparison dialog: entity overview banner,\n// attribute-by-attribute verification matrix, and the 31 CFR Part 587 compliance notice.\n// Port of the React SanctionsInvestigationDialog 1:1.\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'\nimport { Ban, Check, Layers, LucideAngularModule, ShieldAlert, ShieldCheck } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiDialogCloseComponent,\n  UiDialogComponent,\n  UiDialogContentComponent,\n  UiDialogDescriptionComponent,\n  UiDialogFooterComponent,\n  UiDialogHeaderComponent,\n  UiDialogTitleComponent,\n} from '@/ui/dialog/dialog.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\nimport type { SanctionRecord } from './compliance-sanctions-types'\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-sanctions-investigation-dialog, [ui-sanctions-investigation-dialog]',\n  standalone: true,\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiDialogCloseComponent,\n    UiDialogComponent,\n    UiDialogContentComponent,\n    UiDialogDescriptionComponent,\n    UiDialogFooterComponent,\n    UiDialogHeaderComponent,\n    UiDialogTitleComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <ui-dialog [open]=\"open\" (openChange)=\"openChange.emit($event)\">\n      @if (selectedRecord; as record) {\n        <ui-dialog-content class=\"max-h-[90vh] overflow-y-auto sm:max-w-3xl\">\n          <div ui-dialog-header>\n            <div class=\"flex min-w-0 items-center gap-2.5\">\n              <div [class]=\"iconWrapClass(record.matchScore)\">\n                @if (record.matchScore >= 85) {\n                  <lucide-icon [img]=\"ShieldAlert\" class=\"size-5\" />\n                } @else {\n                  <lucide-icon [img]=\"ShieldCheck\" class=\"size-5\" />\n                }\n              </div>\n              <div>\n                <h2 ui-dialog-title class=\"text-base font-bold sm:text-lg\">\n                  Sanction Match Investigation &amp; Attribute Comparison\n                </h2>\n                <p ui-dialog-description class=\"text-muted-foreground mt-0.5 text-xs\">\n                  Detailed biometric, legal entity registry, and designated watchlist reconciliation audit trail.\n                </p>\n              </div>\n            </div>\n          </div>\n\n          <div class=\"space-y-4 py-2\">\n            <!-- Entity Overview Banner -->\n            <div class=\"border-border bg-muted/40 grid grid-cols-1 gap-3 rounded-lg border p-3 text-xs sm:grid-cols-3\">\n              <div>\n                <span class=\"text-muted-foreground block\">Subject Entity Name</span>\n                <strong class=\"text-foreground text-sm font-semibold\">{{ record.entityName }}</strong>\n                @if (record.originalScript) {\n                  <div class=\"text-muted-foreground mt-0.5 text-xs\">\n                    {{ record.originalScript }}\n                  </div>\n                }\n              </div>\n              <div>\n                <span class=\"text-muted-foreground block\">Fuzzy Algorithm Score</span>\n                <div class=\"mt-0.5 flex items-center gap-1.5\">\n                  <span\n                    class=\"text-sm font-bold tabular-nums\"\n                    [class]=\"record.matchScore >= 85 ? 'text-warning' : 'text-success'\"\n                  >\n                    {{ record.matchScore }}% Match\n                  </span>\n                  <span\n                    ui-badge\n                    [variant]=\"scoreBadgeVariant(record.matchScore)\"\n                    class=\"py-0 text-xs whitespace-normal\"\n                  >\n                    {{ scoreBadgeLabel(record.matchScore) }}\n                  </span>\n                </div>\n                <span class=\"text-muted-foreground text-xs\">Threshold: {{ thresholdValue }}%</span>\n              </div>\n              <div>\n                <span class=\"text-muted-foreground block\">Primary Watchlist Source</span>\n                <strong class=\"text-foreground mt-0.5 line-clamp-1 font-medium\">{{ record.sanctionList }}</strong>\n                <span class=\"text-muted-foreground text-xs\">{{ record.jurisdiction }}</span>\n              </div>\n            </div>\n\n            <!-- Attribute Comparison Matrix -->\n            <div class=\"space-y-2\">\n              <h4\n                class=\"text-muted-foreground flex items-center gap-1.5 text-xs font-semibold tracking-wider uppercase\"\n              >\n                <lucide-icon [img]=\"Layers\" class=\"text-primary size-3.5\" />\n                <span>Attribute-by-Attribute Verification Matrix</span>\n              </h4>\n\n              <div class=\"border-border overflow-hidden rounded-lg border\">\n                <div class=\"overflow-x-auto\">\n                  <table ui-table>\n                    <thead ui-table-header class=\"bg-muted/60\">\n                      <tr ui-table-row>\n                        <th ui-table-head class=\"w-[140px] text-xs\">Attribute</th>\n                        <th ui-table-head class=\"min-w-[160px] text-xs\">Submitted Query Data</th>\n                        <th ui-table-head class=\"min-w-[200px] text-xs\">Designated Watchlist Record</th>\n                        <th ui-table-head class=\"w-[130px] text-right text-xs\">Match Verdict</th>\n                      </tr>\n                    </thead>\n                    <tbody ui-table-body>\n                      @for (attr of record.attributeComparisons; track attr.field) {\n                        <tr ui-table-row class=\"hover:bg-muted/20 text-xs\">\n                          <td ui-table-cell class=\"text-foreground py-2.5 align-top font-medium\">\n                            {{ attr.field }}\n                          </td>\n                          <td ui-table-cell class=\"text-muted-foreground py-2.5 align-top\">\n                            <span class=\"text-foreground font-medium\">{{ attr.submittedValue }}</span>\n                          </td>\n                          <td ui-table-cell class=\"py-2.5 align-top\">\n                            <div class=\"space-y-0.5\">\n                              <span class=\"text-foreground font-medium\">{{ attr.watchlistValue }}</span>\n                              @if (attr.note) {\n                                <p class=\"text-muted-foreground/80 text-xs italic\">\n                                  {{ attr.note }}\n                                </p>\n                              }\n                            </div>\n                          </td>\n                          <td ui-table-cell class=\"py-2.5 text-right align-top\">\n                            @if (attr.matchType === 'exact') {\n                              <span\n                                ui-badge\n                                variant=\"destructive\"\n                                class=\"text-xs font-semibold whitespace-normal tabular-nums\"\n                              >\n                                {{ attr.score }}% Exact Match\n                              </span>\n                            } @else if (attr.matchType === 'fuzzy' || attr.matchType === 'partial') {\n                              <span\n                                ui-badge\n                                variant=\"outline\"\n                                class=\"border-warning/40 bg-warning/15 text-warning text-xs font-semibold whitespace-normal tabular-nums\"\n                              >\n                                {{ attr.score }}% Fuzzy Hit\n                              </span>\n                            } @else {\n                              <span\n                                ui-badge\n                                variant=\"outline\"\n                                class=\"border-success/30 bg-success/10 text-success text-xs font-semibold\"\n                              >\n                                Clear\n                              </span>\n                            }\n                          </td>\n                        </tr>\n                      }\n                    </tbody>\n                  </table>\n                </div>\n              </div>\n            </div>\n\n            <!-- Legal Authority & Compliance Advisory Warning -->\n            @if (record.matchScore >= 85) {\n              <div\n                class=\"border-destructive/30 bg-destructive/5 text-foreground space-y-2 rounded-lg border p-3.5 text-xs\"\n              >\n                <div class=\"text-destructive flex min-w-0 items-center gap-2 font-semibold\">\n                  <lucide-icon [img]=\"ShieldAlert\" class=\"size-4\" />\n                  <span>Mandatory Sanctions Compliance &amp; Asset Freeze Notice (31 CFR Part 587)</span>\n                </div>\n                <p class=\"text-muted-foreground\">\n                  If confirmed prohibited, all property and interests in property of this entity within U.S. or EU\n                  jurisdiction must be immediately blocked and reported to OFAC / designated national sanctions\n                  authorities within 10 business days.\n                </p>\n                <div class=\"text-muted-foreground flex flex-wrap items-center gap-3 font-mono text-xs\">\n                  <span>Program: {{ record.program }}</span>\n                  <span>•</span>\n                  <span>SAR Filing: Required within 30d</span>\n                </div>\n              </div>\n            }\n          </div>\n\n          <div\n            ui-dialog-footer\n            class=\"border-border flex flex-col-reverse gap-2 border-t pt-3 sm:flex-row sm:items-center sm:justify-between\"\n          >\n            <button ui-dialog-close ui-button variant=\"outline\" size=\"sm\" class=\"text-xs\">Dismiss / Close</button>\n\n            <div class=\"flex min-w-0 items-center gap-2\">\n              @if (record.matchStatus !== 'cleared_false_positive') {\n                <button\n                  ui-button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  class=\"text-success hover:bg-success/10 hover:text-success gap-1.5 text-xs\"\n                  (click)=\"handleClear(record)\"\n                >\n                  <lucide-icon [img]=\"Check\" class=\"size-3.5\" />\n                  <span>Clear False Positive</span>\n                </button>\n              }\n\n              <button ui-button variant=\"secondary\" size=\"sm\" class=\"gap-1.5 text-xs\" (click)=\"escalate.emit(record)\">\n                <lucide-icon [img]=\"ShieldAlert\" class=\"size-3.5\" />\n                <span>Escalate to MLRO</span>\n              </button>\n\n              @if (record.matchStatus !== 'blocked') {\n                <button ui-button variant=\"destructive\" size=\"sm\" class=\"gap-1.5 text-xs\" (click)=\"handleBlock(record)\">\n                  <lucide-icon [img]=\"Ban\" class=\"size-3.5\" />\n                  <span>Confirm Prohibited &amp; Block</span>\n                </button>\n              }\n            </div>\n          </div>\n        </ui-dialog-content>\n      }\n    </ui-dialog>\n  `,\n})\nexport class UiSanctionsInvestigationDialogComponent {\n  protected readonly Ban = Ban\n  protected readonly Check = Check\n  protected readonly Layers = Layers\n  protected readonly ShieldAlert = ShieldAlert\n  protected readonly ShieldCheck = ShieldCheck\n\n  @Input() open = false\n  @Output() openChange = new EventEmitter<boolean>()\n  @Input() selectedRecord: SanctionRecord | null = null\n  @Input() thresholdValue = 85\n  @Output() clear = new EventEmitter<SanctionRecord>()\n  @Output() escalate = new EventEmitter<SanctionRecord>()\n  @Output() block = new EventEmitter<SanctionRecord>()\n\n  iconWrapClass(score: number): string {\n    return cn(\n      'flex size-9 shrink-0 items-center justify-center rounded-lg',\n      score >= 85 ? 'bg-warning/15 text-warning' : 'bg-success/15 text-success',\n    )\n  }\n\n  scoreBadgeVariant(score: number): 'destructive' | 'outline' | 'success' {\n    if (score >= 95) return 'destructive'\n    if (score >= 85) return 'outline'\n    return 'success'\n  }\n\n  scoreBadgeLabel(score: number): string {\n    if (score >= 95) return 'Critical Risk'\n    if (score >= 85) return 'High Confidence'\n    return 'Clear / Clean'\n  }\n\n  handleClear(record: SanctionRecord): void {\n    this.clear.emit(record)\n    this.openChange.emit(false)\n  }\n\n  handleBlock(record: SanctionRecord): void {\n    this.block.emit(record)\n    this.openChange.emit(false)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/compliance-sanctions-screener/sanctions-investigation-dialog.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/compliance-sanctions-screener/compliance-sanctions-types.ts",
      "content": "export type MatchStatus = 'potential_match' | 'prohibited_match' | 'clear' | 'cleared_false_positive' | 'blocked'\nexport type EntityType = 'individual' | 'corporate'\n\nexport interface SanctionAttributeComparison {\n  field: string\n  submittedValue: string\n  watchlistValue: string\n  matchType: 'exact' | 'fuzzy' | 'partial' | 'clean' | 'unmatched'\n  score: number\n  note?: string\n}\n\nexport interface SanctionRecord {\n  id: string\n  entityName: string\n  originalScript?: string\n  entityType: EntityType\n  matchScore: number\n  matchStatus: MatchStatus\n  sanctionList: string\n  program: string\n  matchedAttributesSummary: string\n  country: string\n  jurisdiction: string\n  dateOfBirthOrIncorporation: string\n  nationalIdOrLei: string\n  address: string\n  aliases: string[]\n  pepLevel?: string\n  remarks?: string\n  lastScreened: string\n  attributeComparisons: SanctionAttributeComparison[]\n}\n\nexport interface NotificationBanner {\n  message: string\n  type: 'success' | 'warning' | 'destructive' | 'info'\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/compliance-sanctions-screener/compliance-sanctions-types.ts"
    },
    {
      "path": "packages/registry-angular/blocks/compliance-sanctions-screener/compliance-sanctions-data.ts",
      "content": "import type { SanctionRecord } from './compliance-sanctions-types'\n\nexport const defaultSanctionRecords: SanctionRecord[] = [\n  {\n    id: 'SANCT-2026-001',\n    entityName: 'Viktor Ivanov',\n    originalScript: 'Иванов Виктор Петрович',\n    entityType: 'individual',\n    matchScore: 94,\n    matchStatus: 'potential_match',\n    sanctionList: 'OFAC SDN List · Sectoral Sanctions',\n    program: 'UKRAINE-EO13662 · Executive Order 14024',\n    matchedAttributesSummary: 'DOB 1974, Russia, Passport 77-04-889102',\n    country: 'Russia',\n    jurisdiction: 'US (OFAC) / EU / UK',\n    dateOfBirthOrIncorporation: '1974-05-12',\n    nationalIdOrLei: '77-04-889102 (RUS)',\n    address: 'Presnenskaya Naberezhnaya 12, Moscow, Russia',\n    aliases: ['Victor Ivanov', 'V. P. Ivanov', 'Viktor Petrovich Ivanov'],\n    pepLevel: 'PEP Tier 2 · Former Deputy Minister of Industry',\n    remarks: 'Designated under Executive Order 14024 for operating in the financial and defense sector.',\n    lastScreened: '10m ago',\n    attributeComparisons: [\n      {\n        field: 'Full Legal Name',\n        submittedValue: 'Viktor Ivanov',\n        watchlistValue: 'IVANOV, Viktor Petrovich (Иванов Виктор Петрович)',\n        matchType: 'fuzzy',\n        score: 96,\n        note: 'Transliteration and patronymic expansion matched',\n      },\n      {\n        field: 'Known Aliases & AKAs',\n        submittedValue: 'Victor Ivanov, V. P. Ivanov',\n        watchlistValue: 'Viktor Ivanov, Victor Petrovich Ivanov, Victor Ivanov-Karpov',\n        matchType: 'partial',\n        score: 94,\n        note: 'Direct alias hit in OFAC Specially Designated database',\n      },\n      {\n        field: 'Date of Birth / Inception',\n        submittedValue: '1974-05-12',\n        watchlistValue: '1974-05-12 (Moscow, USSR / Russian Federation)',\n        matchType: 'exact',\n        score: 100,\n        note: '100% exact cryptographic DOB date match',\n      },\n      {\n        field: 'Passport / National ID',\n        submittedValue: '77-04-889102 (Russian Federation)',\n        watchlistValue: '77-04-889102 / Int. Passport 51-09-112344',\n        matchType: 'exact',\n        score: 100,\n        note: 'Official primary national identity document match',\n      },\n      {\n        field: 'Registered Address',\n        submittedValue: 'Presnenskaya Naberezhnaya 12, Moscow',\n        watchlistValue: 'Presnenskaya Embankment 12, Fl. 4, Moscow 123112, Russia',\n        matchType: 'fuzzy',\n        score: 92,\n        note: 'Street and district normalization matched',\n      },\n      {\n        field: 'PEP Status & Legal Program',\n        submittedValue: 'Executive Director (Disclosed Non-PEP)',\n        watchlistValue: 'OFAC SDN [UKRAINE-EO13662] · PEP Tier 2 · Mandatory Asset Freeze',\n        matchType: 'exact',\n        score: 100,\n        note: 'Undeclared PEP Tier 2 designation active on UK HMT / EU Sanctions',\n      },\n    ],\n  },\n  {\n    id: 'SANCT-2026-002',\n    entityName: 'Sarah Connor',\n    originalScript: 'Sarah Connor',\n    entityType: 'individual',\n    matchScore: 12,\n    matchStatus: 'clear',\n    sanctionList: 'No Sanctions Matches (All Databases Checked)',\n    program: 'None · Standard Retail Profile',\n    matchedAttributesSummary: 'No sanction matches · Low risk profile',\n    country: 'United States',\n    jurisdiction: 'Global / FATF Compliant',\n    dateOfBirthOrIncorporation: '1985-02-28',\n    nationalIdOrLei: 'SSN ***-**-4910',\n    address: '742 Evergreen Terrace, Los Angeles, CA 90001, USA',\n    aliases: ['Sarah J. Connor'],\n    pepLevel: 'Non-PEP',\n    remarks: 'Clear of all OFAC, EU, UN, and PEP lists. Auto-approved by automated compliance pipeline.',\n    lastScreened: '18m ago',\n    attributeComparisons: [\n      {\n        field: 'Full Legal Name',\n        submittedValue: 'Sarah Connor',\n        watchlistValue: 'CONNOR, Sara Helena (Low Soundex Similarity)',\n        matchType: 'fuzzy',\n        score: 18,\n        note: 'Distant phonetical overlap below decision threshold',\n      },\n      {\n        field: 'Known Aliases & AKAs',\n        submittedValue: 'Sarah J. Connor',\n        watchlistValue: 'No matching designated aliases found',\n        matchType: 'clean',\n        score: 0,\n        note: 'Zero hits across all official alias directories',\n      },\n      {\n        field: 'Date of Birth / Inception',\n        submittedValue: '1985-02-28',\n        watchlistValue: '1962-11-04 (Bogota, Colombia)',\n        matchType: 'unmatched',\n        score: 0,\n        note: 'DOB discrepancy (>22 years divergence)',\n      },\n      {\n        field: 'Passport / National ID',\n        submittedValue: 'SSN ***-**-4910 (USA)',\n        watchlistValue: 'COL-9902148 (Republic of Colombia)',\n        matchType: 'unmatched',\n        score: 0,\n        note: 'Different country of issuance and identifier structure',\n      },\n      {\n        field: 'Registered Address',\n        submittedValue: '742 Evergreen Terrace, Los Angeles, CA, USA',\n        watchlistValue: 'Calle 72 #10-34, Bogota, Colombia',\n        matchType: 'unmatched',\n        score: 0,\n        note: 'Zero geographic intersection',\n      },\n      {\n        field: 'PEP Status & Legal Program',\n        submittedValue: 'Individual Retail Client',\n        watchlistValue: 'Clean / Unrestricted Jurisdiction',\n        matchType: 'clean',\n        score: 0,\n        note: 'No adverse media or PEP exposure',\n      },\n    ],\n  },\n  {\n    id: 'SANCT-2026-003',\n    entityName: 'Elena Rostova',\n    originalScript: 'Elena Rostova-Dimitriou',\n    entityType: 'individual',\n    matchScore: 0,\n    matchStatus: 'clear',\n    sanctionList: 'No Sanctions Matches (All Databases Checked)',\n    program: 'None · Private Banking Profile',\n    matchedAttributesSummary: 'No sanction matches · High assurance clean record',\n    country: 'Cyprus',\n    jurisdiction: 'EU / Global Compliant',\n    dateOfBirthOrIncorporation: '1991-09-17',\n    nationalIdOrLei: 'CY-ID 9920194',\n    address: 'Archbishop Makarios III Ave 45, Limassol 3025, Cyprus',\n    aliases: ['Elena Rostova-Dimitriou'],\n    pepLevel: 'Non-PEP',\n    remarks: 'Verified clean record across UN Consolidated, OFAC SDN, UK HMT, and Interpol Red Notices.',\n    lastScreened: '32m ago',\n    attributeComparisons: [\n      {\n        field: 'Full Legal Name',\n        submittedValue: 'Elena Rostova',\n        watchlistValue: 'No target record matches identified in any watchlist',\n        matchType: 'clean',\n        score: 0,\n        note: 'Zero hits across 42 global sanction jurisdictions',\n      },\n      {\n        field: 'Known Aliases & AKAs',\n        submittedValue: 'Elena Rostova-Dimitriou',\n        watchlistValue: 'No target record matches',\n        matchType: 'clean',\n        score: 0,\n        note: 'Zero alias records found',\n      },\n      {\n        field: 'Date of Birth / Inception',\n        submittedValue: '1991-09-17',\n        watchlistValue: 'No target record matches',\n        matchType: 'clean',\n        score: 0,\n        note: 'Clean verification result',\n      },\n      {\n        field: 'Passport / National ID',\n        submittedValue: 'CY-ID 9920194 (Cyprus / EU)',\n        watchlistValue: 'No target record matches',\n        matchType: 'clean',\n        score: 0,\n        note: 'Clean verification result',\n      },\n      {\n        field: 'Registered Address',\n        submittedValue: 'Archbishop Makarios III Ave 45, Limassol, Cyprus',\n        watchlistValue: 'No target record matches',\n        matchType: 'clean',\n        score: 0,\n        note: 'Verified standard EU residential registry',\n      },\n      {\n        field: 'PEP Status & Legal Program',\n        submittedValue: 'Private Banking Client',\n        watchlistValue: 'Verified Non-PEP · Zero Adverse Media Flag',\n        matchType: 'clean',\n        score: 0,\n        note: 'Clean compliance status',\n      },\n    ],\n  },\n  {\n    id: 'SANCT-2026-004',\n    entityName: 'Sberbank Trade Corp',\n    originalScript: 'ПАО Сбербанк / Sberbank Trade Corp',\n    entityType: 'corporate',\n    matchScore: 98,\n    matchStatus: 'prohibited_match',\n    sanctionList: 'EU Sanctions Article 5',\n    program: 'EU Reg 833/2014 Annex XIII · UK Sanctions S.I. 2022/194 · OFAC SSI Directives',\n    matchedAttributesSummary: 'LEI RU-9912048, Sector: Financials, Subsidiary of Sberbank PJSC',\n    country: 'Russia',\n    jurisdiction: 'EU / UK / OFAC Sectoral',\n    dateOfBirthOrIncorporation: '2008-11-14',\n    nationalIdOrLei: 'LEI: 253400X89892182 / INN: 7707083893',\n    address: 'Vavilova St 19, Moscow, 117997, Russia',\n    aliases: ['Sber Trade LLC', 'Sberbank Trading House', 'PJSC Sberbank Sub-Entity'],\n    pepLevel: 'State-Owned Enterprise (SOE) · Comprehensive Asset Freeze',\n    remarks:\n      'Subject to broad asset freeze and prohibitions on financial dealings, capital markets, and correspondent accounts.',\n    lastScreened: '1h ago',\n    attributeComparisons: [\n      {\n        field: 'Legal Entity Name',\n        submittedValue: 'Sberbank Trade Corp',\n        watchlistValue: 'PJSC SBERBANK / Sberbank Trade Corp (ПАО Сбербанк)',\n        matchType: 'exact',\n        score: 99,\n        note: 'Substantial majority-owned direct subsidiary matching designated parent',\n      },\n      {\n        field: 'Known Aliases & AKAs',\n        submittedValue: 'Sber Trade LLC, Sberbank Trading House',\n        watchlistValue: 'Sberbank Trading House / Sber Trade / Sberbank Capital LLC',\n        matchType: 'exact',\n        score: 100,\n        note: '100% match on registered trading names in EU Annex XIII',\n      },\n      {\n        field: 'Date of Incorporation',\n        submittedValue: '2008-11-14',\n        watchlistValue: '2008-11-14 (Moscow, Russian Federation)',\n        matchType: 'exact',\n        score: 100,\n        note: 'Registration date matching corporate charter record',\n      },\n      {\n        field: 'LEI / Corporate Tax ID',\n        submittedValue: 'LEI 253400X89892182 / INN 7707083893',\n        watchlistValue: 'LEI 253400X89892182 / INN 7707083893 / OGRN 1027700132195',\n        matchType: 'exact',\n        score: 100,\n        note: 'Unique global Legal Entity Identifier (LEI) direct match',\n      },\n      {\n        field: 'Registered Head Office',\n        submittedValue: 'Vavilova St 19, Moscow, 117997, Russia',\n        watchlistValue: '19 Vavilova St, Moscow 117997, Russian Federation',\n        matchType: 'exact',\n        score: 98,\n        note: 'Exact match with sanctioned financial headquarters address',\n      },\n      {\n        field: 'Sanction Program & Enforcement',\n        submittedValue: 'Corporate Investment Account',\n        watchlistValue: 'EU Article 5 / UK HMT Sanctions / OFAC 50% Rule Asset Freeze',\n        matchType: 'exact',\n        score: 100,\n        note: 'Mandatory transaction blocking and immediate regulatory freeze required',\n      },\n    ],\n  },\n]\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/compliance-sanctions-screener/compliance-sanctions-data.ts"
    },
    {
      "path": "packages/registry-angular/blocks/compliance-sanctions-screener/index.ts",
      "content": "export {\n  UiComplianceSanctionsScreenerComponent,\n  type EntityType,\n  type SanctionRecord,\n} from './compliance-sanctions-screener.component'\nexport { UiSanctionsInvestigationDialogComponent } from './sanctions-investigation-dialog.component'\nexport type { MatchStatus, NotificationBanner, SanctionAttributeComparison } from './compliance-sanctions-types'\nexport { defaultSanctionRecords } from './compliance-sanctions-data'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/compliance-sanctions-screener/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/dialog.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/select.json",
    "https://uipkge.dev/r/angular/slider.json",
    "https://uipkge.dev/r/angular/table.json"
  ],
  "description": "AML/KYC OFAC, Politically Exposed Persons (PEP), and global sanctions list screening workbench with fuzzy match threshold tuning, real-time entity inspection modal, and prohibited match enforcement.",
  "categories": [
    "legal",
    "dashboard",
    "finance",
    "security"
  ]
}