{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "training-compliance-tracker",
  "title": "Training Compliance Tracker",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/training-compliance-tracker/training-compliance-tracker.component.ts",
      "content": "// Annual mandatory employee compliance training dashboard with certification badges,\n// renewal deadlines, assessment scorecards, verified credential preview modal, and\n// certificate export controls. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, HostListener, Input, computed, signal } from '@angular/core'\nimport {\n  AlertCircle,\n  Award,\n  BadgeCheck,\n  Building2,\n  CalendarClock,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Download,\n  FileCheck,\n  FileDown,\n  LucideAngularModule,\n  PlayCircle,\n  RefreshCw,\n  RotateCcw,\n  Search,\n  Share2,\n  Shield,\n  ShieldCheck,\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 {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardFooterComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\n\nexport interface ComplianceCourse {\n  id: string\n  code: string\n  title: string\n  category: string\n  categoryKey: 'security' | 'ethics' | 'governance' | 'privacy' | 'finance'\n  standard: string\n  duration: string\n  durationHours: number\n  score: number\n  scoreStatus: string\n  completionDate: string\n  expirationDate: string\n  validityMonths: number\n  daysUntilExpiry: number\n  credentialId: string\n  sha256Digest: string\n  verified: boolean\n  instructor: string\n  accreditationBody: string\n  description: string\n}\n\nconst coursesData: ComplianceCourse[] = [\n  {\n    id: 'course-sec-201',\n    code: 'SEC-201',\n    title: 'Information Security & Data Protection (SOC2 / ISO 27001)',\n    category: 'Security & Privacy',\n    categoryKey: 'security',\n    standard: 'AICPA SOC 2 Type II (CC6.1–CC6.8) & ISO/IEC 27001:2022 ISMS',\n    duration: '1.5 Hours · Video + Exam',\n    durationHours: 1.5,\n    score: 100,\n    scoreStatus: '100% · Passed',\n    completionDate: 'Aug 10, 2026',\n    expirationDate: 'Aug 10, 2027',\n    validityMonths: 12,\n    daysUntilExpiry: 354,\n    credentialId: 'CERT-SEC-8921',\n    sha256Digest: '7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069',\n    verified: true,\n    instructor: 'Dr. Marcus Vance (Chief Information Security Officer)',\n    accreditationBody: 'AICPA & International Organization for Standardization (ISO)',\n    description:\n      'Covers zero-trust access, threat modeling, cryptographic key storage, cloud security postures, automated patch cycles, and incident response SLAs.',\n  },\n  {\n    id: 'course-eth-104',\n    code: 'ETH-104',\n    title: 'Workplace Harassment Prevention (California AB 1825)',\n    category: 'Ethics & Legal',\n    categoryKey: 'ethics',\n    standard: 'California Government Code § 12950.1 / AB 1825 & SB 1343',\n    duration: '2.0 Hours · Interactive Scenario',\n    durationHours: 2.0,\n    score: 100,\n    scoreStatus: '100% · Passed',\n    completionDate: 'Jul 14, 2026',\n    expirationDate: 'Jul 14, 2027',\n    validityMonths: 12,\n    daysUntilExpiry: 327,\n    credentialId: 'CERT-ETH-4412',\n    sha256Digest: '3d9e8471b0219ca66219f85c18174a10df84b1fa3d677284addd200126d83120',\n    verified: true,\n    instructor: 'Sarah Jenkins, Esq. (Director of People & Legal Compliance)',\n    accreditationBody: 'California Civil Rights Department (CRD / DFEH)',\n    description:\n      'Mandatory supervisory training on workplace culture, protected characteristics, bystander intervention techniques, retaliation prevention, and complaint escalations.',\n  },\n  {\n    id: 'course-gov-302',\n    code: 'GOV-302',\n    title: 'Anti-Bribery & Foreign Corrupt Practices Act (FCPA)',\n    category: 'Corporate Governance',\n    categoryKey: 'governance',\n    standard: 'US Foreign Corrupt Practices Act (15 U.S.C. § 78dd-1) & OECD Guidelines',\n    duration: '1.0 Hour · Case Studies + Exam',\n    durationHours: 1.0,\n    score: 96,\n    scoreStatus: '96% · Passed',\n    completionDate: 'Apr 15, 2026',\n    expirationDate: 'Apr 15, 2027',\n    validityMonths: 12,\n    daysUntilExpiry: 237,\n    credentialId: 'CERT-GOV-3108',\n    sha256Digest: '19fa4429bb56f082c18148a1d65dfc2d4b1fa3d677284addd200126d409218a1',\n    verified: true,\n    instructor: 'David K. Thorne (Global Ethics & Trade Compliance Counsel)',\n    accreditationBody: 'U.S. Department of Justice & OECD Anti-Bribery Directorate',\n    description:\n      'Anti-corruption controls, third-party intermediary vetting, prohibition of facilitation payments, gift/hospitality thresholds, and internal books and records integrity.',\n  },\n  {\n    id: 'course-reg-205',\n    code: 'REG-205',\n    title: 'HIPAA Security & Health Privacy Standards',\n    category: 'Regulatory & Privacy',\n    categoryKey: 'privacy',\n    standard: '45 CFR Part 160 & Part 164 Subparts A, C, and E (ePHI Safeguards)',\n    duration: '1.0 Hour · Video + Assessment',\n    durationHours: 1.0,\n    score: 98,\n    scoreStatus: '98% · Passed',\n    completionDate: 'Jun 02, 2026',\n    expirationDate: 'Jun 02, 2027',\n    validityMonths: 12,\n    daysUntilExpiry: 285,\n    credentialId: 'CERT-HPA-7729',\n    sha256Digest: '55ca0982df43b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200',\n    verified: true,\n    instructor: 'Rachel Sterling (Healthcare Privacy & HIPAA Compliance Officer)',\n    accreditationBody: 'U.S. Department of Health & Human Services (HHS OCR)',\n    description:\n      'Handling of Protected Health Information (PHI/ePHI), minimum necessary standard, physical and technical safeguards, Business Associate Agreements, and breach notifications.',\n  },\n  {\n    id: 'course-fin-401',\n    code: 'FIN-401',\n    title: 'Insider Trading & Fair Disclosure (SEC)',\n    category: 'Financial Compliance',\n    categoryKey: 'finance',\n    standard: 'Securities Exchange Act Rule 10b-5 & SEC Regulation Fair Disclosure (Reg FD)',\n    duration: '1.0 Hour · Video + Exam',\n    durationHours: 1.0,\n    score: 100,\n    scoreStatus: '100% · Passed',\n    completionDate: 'May 19, 2026',\n    expirationDate: 'May 19, 2027',\n    validityMonths: 12,\n    daysUntilExpiry: 271,\n    credentialId: 'CERT-SEC-6043',\n    sha256Digest: '91ea2d4719fa4429bb56f082c18148a1d65dfc2d4b1fa3d677284addd200126d',\n    verified: true,\n    instructor: 'Jonathan Meyer (Chief Legal Officer & General Counsel)',\n    accreditationBody: 'U.S. Securities and Exchange Commission (SEC)',\n    description:\n      'Material Non-Public Information (MNPI) boundaries, pre-clearance procedures, quarterly trading blackouts, Rule 10b5-1 executive trading plans, and non-selective disclosure protocols.',\n  },\n]\n\nconst filterCategories = [\n  { id: 'all', label: 'All Modules', count: 5 },\n  { id: 'security', label: 'Security & Privacy', count: 2 },\n  { id: 'ethics', label: 'Ethics & Legal', count: 1 },\n  { id: 'governance', label: 'Corporate Governance', count: 1 },\n  { id: 'finance', label: 'Financial Compliance', count: 1 },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-training-compliance-tracker, [ui-training-compliance-tracker]',\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    UiCardDescriptionComponent,\n    UiCardFooterComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiProgressComponent,\n    UiSeparatorComponent,\n    UiTableComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <div data-slot=\"training-compliance-tracker\" [class]=\"rootClass\">\n      <!-- Header Card -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-content class=\"p-5 sm:p-6\">\n          <div class=\"flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between\">\n            <div class=\"space-y-3\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <span class=\"text-muted-foreground text-xs font-medium\"> Enterprise HRMS & Regulatory Assurance </span>\n                <span\n                  ui-badge\n                  wrap\n                  variant=\"outline\"\n                  class=\"border-success/30 bg-success/10 text-success text-xs font-medium\"\n                >\n                  FY 2026–2027 Annual Cycle\n                </span>\n              </div>\n\n              <div>\n                <h2 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n                  Mandatory Compliance Training & Certifications\n                </h2>\n                <p class=\"text-muted-foreground mt-1 text-sm\">\n                  Official employee regulatory transcripts, verified digital credentials, and annual recertification\n                  schedules.\n                </p>\n              </div>\n\n              <div class=\"text-muted-foreground flex flex-wrap items-center gap-3 pt-1 text-xs\">\n                <div\n                  class=\"border-border bg-muted/40 text-foreground flex items-center gap-2 rounded-md border px-2.5 py-1.5 font-medium\"\n                >\n                  <div\n                    class=\"bg-primary/10 text-primary flex size-5 items-center justify-center rounded-full text-xs font-bold\"\n                  >\n                    ER\n                  </div>\n                  <span>Elena Rostova · Senior Staff Engineer</span>\n                </div>\n                <div class=\"flex items-center gap-1.5 font-mono tabular-nums\">\n                  <span class=\"text-muted-foreground\">ID:</span>\n                  <span class=\"text-foreground font-medium\">EMP-4092</span>\n                </div>\n                <ui-separator orientation=\"vertical\" class=\"h-3.5\" />\n                <div class=\"flex items-center gap-1\">\n                  <lucide-icon [img]=\"Building2\" class=\"text-muted-foreground size-3.5\" />\n                  <span>Core Platform Infrastructure</span>\n                </div>\n                <ui-separator orientation=\"vertical\" class=\"h-3.5\" />\n                <div class=\"flex items-center gap-1\">\n                  <span>San Francisco, CA (HQ)</span>\n                </div>\n              </div>\n            </div>\n\n            <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center lg:flex-col lg:items-end\">\n              <div\n                class=\"border-success/30 bg-success/10 text-success dark:bg-success/10 inline-flex items-center gap-2.5 rounded-lg border px-3.5 py-2 text-xs font-semibold shadow-xs\"\n              >\n                <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-4.5 shrink-0\" />\n                <div class=\"flex flex-col\">\n                  <span>100% Compliant · All 5 Annual Certifications Valid</span>\n                  <span class=\"text-success/90 text-xs font-normal\">Zero overdue requirements · Audit attested</span>\n                </div>\n              </div>\n\n              <button\n                ui-button\n                aria-label=\"Download attachment\"\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"hover:bg-accent gap-2 shadow-xs\"\n                [disabled]=\"isDownloadingAll()\"\n                (click)=\"handleDownloadAllPdf()\"\n              >\n                @if (isDownloadingAll()) {\n                  <lucide-icon [img]=\"RefreshCw\" class=\"size-3.5 animate-spin\" />\n                } @else {\n                  <lucide-icon [img]=\"FileDown\" class=\"text-foreground size-3.5\" />\n                }\n                <span>{{ isDownloadingAll() ? 'Generating PDF Bundle...' : 'Download All Certificates PDF' }}</span>\n              </button>\n            </div>\n          </div>\n\n          @if (downloadBannerMessage()) {\n            <div\n              class=\"border-success/30 bg-success/10 text-success dark:bg-success/10 dark:text-foreground mt-4 flex items-center gap-2 rounded-md border p-2.5 text-xs transition-colors\"\n            >\n              <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-4 shrink-0\" />\n              <span>{{ downloadBannerMessage() }}</span>\n            </div>\n          }\n\n          @if (retakeSuccessMessage()) {\n            <div\n              class=\"border-info/30 bg-info/10 text-info dark:bg-info/10 dark:text-foreground mt-4 flex items-center gap-2 rounded-md border p-2.5 text-xs transition-colors\"\n            >\n              <lucide-icon [img]=\"RotateCcw\" class=\"text-info size-4 shrink-0\" />\n              <span>{{ retakeSuccessMessage() }}</span>\n            </div>\n          }\n        </div>\n      </div>\n\n      <!-- 4 Training Overview KPI Cards -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        <div\n          ui-card\n          class=\"border-border bg-card shadow-xs transition-[color,background-color,border-color,box-shadow] hover:shadow-sm\"\n        >\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-medium\">Completed Certifications</h3>\n            <div class=\"bg-success/10 text-success flex size-8 items-center justify-center rounded-md\">\n              <lucide-icon [img]=\"Award\" class=\"size-4.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-3\">\n            <div>\n              <div\n                class=\"text-foreground flex items-baseline gap-1.5 font-mono text-2xl font-bold tracking-tight tabular-nums\"\n              >\n                5 / 5\n              </div>\n              <p class=\"text-muted-foreground text-xs\">Modules Completed · 100% Finished</p>\n            </div>\n            <div class=\"space-y-1\">\n              <ui-progress [value]=\"100\" class=\"bg-success/20 h-1.5\" />\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span class=\"text-success font-medium\">SOC2 & ISO Ready</span>\n                <span class=\"font-mono tabular-nums\">5/5 passed</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div\n          ui-card\n          class=\"border-border bg-card shadow-xs transition-[color,background-color,border-color,box-shadow] hover:shadow-sm\"\n        >\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-medium\">Total Training Hours</h3>\n            <div class=\"bg-info/10 text-info flex size-8 items-center justify-center rounded-md\">\n              <lucide-icon [img]=\"Clock\" class=\"size-4.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-3\">\n            <div>\n              <div\n                class=\"text-foreground flex items-baseline gap-1.5 font-mono text-2xl font-bold tracking-tight tabular-nums\"\n              >\n                6.5\n                <span class=\"text-muted-foreground text-sm font-normal\">Hours</span>\n              </div>\n              <p class=\"text-muted-foreground text-xs\">6.5 Hours Logged in 2026</p>\n            </div>\n            <div class=\"space-y-1\">\n              <ui-progress [value]=\"100\" class=\"bg-info/20 h-1.5\" />\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span class=\"text-info font-medium\">Quota: 6.0h Target</span>\n                <span class=\"font-mono tabular-nums\">108% logged</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div\n          ui-card\n          class=\"border-border bg-card shadow-xs transition-[color,background-color,border-color,box-shadow] hover:shadow-sm\"\n        >\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-medium\">Next Renewal Due</h3>\n            <div class=\"bg-warning/10 text-warning flex size-8 items-center justify-center rounded-md\">\n              <lucide-icon [img]=\"CalendarClock\" class=\"size-4.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-3\">\n            <div>\n              <div class=\"text-foreground font-mono text-lg font-bold tracking-tight tabular-nums sm:text-xl\">\n                April 15, 2027\n              </div>\n              <p class=\"text-warning text-xs font-medium\">In 8 months · Earliest Renewal</p>\n            </div>\n            <div class=\"border-border bg-muted/40 flex items-center justify-between rounded border px-2 py-1 text-xs\">\n              <span class=\"text-muted-foreground truncate\">FCPA Anti-Bribery</span>\n              <span ui-badge wrap variant=\"outline\" class=\"border-warning/30 text-warning font-mono text-xs\">\n                237 days\n              </span>\n            </div>\n          </div>\n        </div>\n\n        <div\n          ui-card\n          class=\"border-border bg-card shadow-xs transition-[color,background-color,border-color,box-shadow] hover:shadow-sm\"\n        >\n          <div ui-card-header class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n            <h3 ui-card-title class=\"text-muted-foreground text-xs font-medium\">Company-Wide Compliance</h3>\n            <div class=\"bg-chart-1/10 text-chart-1 flex size-8 items-center justify-center rounded-md\">\n              <lucide-icon [img]=\"Users\" class=\"size-4.5\" />\n            </div>\n          </div>\n          <div ui-card-content class=\"space-y-3\">\n            <div>\n              <div\n                class=\"text-foreground flex items-baseline gap-1.5 font-mono text-2xl font-bold tracking-tight tabular-nums\"\n              >\n                98.4%\n              </div>\n              <p class=\"text-muted-foreground text-xs\">98.4% Staff Certified (1,420/1,443)</p>\n            </div>\n            <div class=\"space-y-1\">\n              <ui-progress [value]=\"98.4\" class=\"bg-chart-1/20 h-1.5\" />\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span class=\"text-chart-1 font-medium\">+1.2% this quarter</span>\n                <span class=\"font-mono tabular-nums\">23 pending</span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Filter Toolbar & Search -->\n      <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"flex flex-wrap items-center gap-1.5\">\n          @for (cat of categories; track cat.id) {\n            <button type=\"button\" [class]=\"filterPillClass(cat.id)\" (click)=\"activeFilter.set(cat.id)\">\n              <span>{{ cat.label }}</span>\n              <span [class]=\"filterCountClass(cat.id)\">{{ cat.count }}</span>\n            </button>\n          }\n        </div>\n\n        <div class=\"relative w-full sm:w-64\">\n          <lucide-icon\n            [img]=\"Search\"\n            class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\"\n          />\n          <input\n            [value]=\"searchQuery()\"\n            (input)=\"searchQuery.set($any($event.target).value)\"\n            type=\"text\"\n            placeholder=\"Filter courses...\"\n            class=\"border-input bg-background text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 h-8 w-full min-w-0 rounded-md border pr-3 pl-8 text-xs focus-visible:ring-2 focus-visible:outline-none\"\n          />\n          @if (searchQuery()) {\n            <button\n              type=\"button\"\n              class=\"text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2\"\n              aria-label=\"Clear search\"\n              (click)=\"searchQuery.set('')\"\n            >\n              <lucide-icon [img]=\"X\" class=\"size-3.5\" />\n            </button>\n          }\n        </div>\n      </div>\n\n      <!-- Mandatory Compliance Modules Table Card -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-header class=\"p-5 pb-3\">\n          <div class=\"flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between\">\n            <div>\n              <h3 ui-card-title class=\"text-foreground text-base font-semibold tracking-tight\">\n                Mandatory Compliance Modules\n              </h3>\n              <p ui-card-description class=\"text-muted-foreground text-xs\">\n                Annual regulatory curriculum required under corporate governance and SOC 2 / ISO 27001 audit controls.\n              </p>\n            </div>\n            <div class=\"flex items-center gap-2 pt-2 sm:pt-0\">\n              <span class=\"text-muted-foreground text-xs\">\n                Showing\n                <span class=\"text-foreground font-mono font-medium tabular-nums\">{{ filteredCourses().length }}</span>\n                of\n                <span class=\"text-foreground font-mono font-medium tabular-nums\">5</span> modules\n              </span>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"p-0\">\n          <div class=\"overflow-x-auto\">\n            <table ui-table>\n              <thead ui-table-header class=\"bg-muted/40\">\n                <tr ui-table-row class=\"hover:bg-transparent\">\n                  <th\n                    ui-table-head\n                    class=\"text-muted-foreground min-w-[280px] py-3 text-xs font-semibold tracking-wider uppercase\"\n                  >\n                    Course Title & Category\n                  </th>\n                  <th\n                    ui-table-head\n                    class=\"text-muted-foreground min-w-[140px] py-3 text-xs font-semibold tracking-wider uppercase\"\n                  >\n                    Duration\n                  </th>\n                  <th\n                    ui-table-head\n                    class=\"text-muted-foreground min-w-[140px] py-3 text-xs font-semibold tracking-wider uppercase\"\n                  >\n                    Score on Final Assessment\n                  </th>\n                  <th\n                    ui-table-head\n                    class=\"text-muted-foreground min-w-[120px] py-3 text-xs font-semibold tracking-wider uppercase\"\n                  >\n                    Completion Date\n                  </th>\n                  <th\n                    ui-table-head\n                    class=\"text-muted-foreground min-w-[120px] py-3 text-xs font-semibold tracking-wider uppercase\"\n                  >\n                    Expiration Date\n                  </th>\n                  <th\n                    ui-table-head\n                    class=\"text-muted-foreground min-w-[160px] py-3 text-xs font-semibold tracking-wider uppercase\"\n                  >\n                    Certificate Badge\n                  </th>\n                  <th\n                    ui-table-head\n                    class=\"text-muted-foreground min-w-[180px] py-3 text-right text-xs font-semibold tracking-wider uppercase\"\n                  >\n                    Actions\n                  </th>\n                </tr>\n              </thead>\n\n              <tbody ui-table-body>\n                @for (course of filteredCourses(); track course.id) {\n                  <tr ui-table-row class=\"hover:bg-muted/30 transition-colors\">\n                    <td ui-table-cell class=\"py-3.5 align-middle\">\n                      <div class=\"space-y-1\">\n                        <div class=\"flex items-center gap-2\">\n                          <span class=\"text-foreground text-sm font-medium\">{{ course.title }}</span>\n                        </div>\n                        <div class=\"flex flex-wrap items-center gap-2\">\n                          <span ui-badge wrap variant=\"secondary\" class=\"text-xs font-medium\">\n                            {{ course.category }}\n                          </span>\n                          <span class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                            Code: {{ course.code }}\n                          </span>\n                          <span\n                            class=\"text-muted-foreground max-w-[200px] truncate text-xs\"\n                            [attr.title]=\"course.standard\"\n                          >\n                            {{ course.standard }}\n                          </span>\n                        </div>\n                      </div>\n                    </td>\n\n                    <td ui-table-cell class=\"py-3.5 align-middle\">\n                      <div class=\"text-foreground flex items-center gap-1.5 font-mono text-xs tabular-nums\">\n                        <lucide-icon [img]=\"Clock\" class=\"text-muted-foreground size-3.5\" />\n                        <span>{{ course.duration }}</span>\n                      </div>\n                    </td>\n\n                    <td ui-table-cell class=\"py-3.5 align-middle\">\n                      <div class=\"space-y-1\">\n                        <div\n                          class=\"text-success flex items-center gap-1.5 font-mono text-sm font-semibold tabular-nums\"\n                        >\n                          <lucide-icon [img]=\"CheckCircle2\" class=\"size-3.5 shrink-0\" />\n                          <span>{{ course.scoreStatus }}</span>\n                        </div>\n                        <div class=\"text-muted-foreground flex items-center gap-1 text-xs\">\n                          <span>Pass threshold: 80%</span>\n                        </div>\n                      </div>\n                    </td>\n\n                    <td ui-table-cell class=\"py-3.5 align-middle\">\n                      <div class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                        {{ course.completionDate }}\n                      </div>\n                    </td>\n\n                    <td ui-table-cell class=\"py-3.5 align-middle\">\n                      <div class=\"space-y-0.5\">\n                        <div class=\"text-foreground font-mono text-xs font-medium tabular-nums\">\n                          {{ course.expirationDate }}\n                        </div>\n                        <div class=\"text-success font-mono text-xs tabular-nums\">\n                          Valid ({{ course.daysUntilExpiry }}d remaining)\n                        </div>\n                      </div>\n                    </td>\n\n                    <td ui-table-cell class=\"py-3.5 align-middle\">\n                      <div class=\"space-y-1\">\n                        <div\n                          class=\"border-success/30 bg-success/10 text-success inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-semibold\"\n                        >\n                          <lucide-icon [img]=\"BadgeCheck\" class=\"text-success size-3.5\" />\n                          <span>Verified Credential</span>\n                        </div>\n                        <div class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                          {{ course.credentialId }}\n                        </div>\n                      </div>\n                    </td>\n\n                    <td ui-table-cell class=\"py-3.5 text-right align-middle\">\n                      <div class=\"flex items-center justify-end gap-1.5\">\n                        <button\n                          ui-button\n                          variant=\"outline\"\n                          size=\"xs\"\n                          class=\"hover:bg-accent h-7 gap-1 px-2.5 text-xs font-medium shadow-2xs\"\n                          (click)=\"openCertificateModal(course)\"\n                        >\n                          <lucide-icon [img]=\"FileCheck\" class=\"text-muted-foreground size-3\" />\n                          <span>View Certificate</span>\n                        </button>\n\n                        <button\n                          ui-button\n                          variant=\"ghost\"\n                          size=\"xs\"\n                          class=\"text-muted-foreground hover:text-foreground h-7 gap-1 px-2 text-xs font-medium\"\n                          (click)=\"openRetakeModal(course)\"\n                        >\n                          <lucide-icon [img]=\"RotateCcw\" class=\"size-3\" />\n                          <span>Retake</span>\n                        </button>\n                      </div>\n                    </td>\n                  </tr>\n                }\n\n                @if (filteredCourses().length === 0) {\n                  <tr ui-table-row>\n                    <td ui-table-cell [attr.colspan]=\"7\" class=\"text-muted-foreground py-8 text-center text-xs\">\n                      No compliance modules match your search or filter criteria.\n                    </td>\n                  </tr>\n                }\n              </tbody>\n            </table>\n          </div>\n        </div>\n\n        <div\n          ui-card-footer\n          class=\"border-border bg-muted/20 text-muted-foreground flex flex-col gap-2 border-t p-4 text-xs sm:flex-row sm:items-center sm:justify-between\"\n        >\n          <div class=\"flex items-center gap-2\">\n            <lucide-icon [img]=\"Shield\" class=\"text-success size-4 shrink-0\" />\n            <span>Audited & Attested by Schellman & Co., LLC for SOC 2 Type II & AICPA Security Trust Criteria.</span>\n          </div>\n          <div class=\"flex items-center gap-2 font-mono tabular-nums\">\n            <span>Ledger Sync: Aug 21, 2026 09:42 UTC</span>\n            <span class=\"text-success font-medium\">100% In-Policy</span>\n          </div>\n        </div>\n      </div>\n\n      <!-- Certificate Inspection Modal -->\n      @if (selectedCertificate(); as cert) {\n        <div\n          class=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 backdrop-blur-xs transition-opacity\"\n          (click)=\"onOverlayClick($event, 'certificate')\"\n        >\n          <div\n            class=\"border-border bg-card text-card-foreground relative w-full max-w-2xl overflow-hidden rounded-xl border shadow-sm\"\n          >\n            <div class=\"border-border bg-muted/40 flex items-center justify-between border-b px-5 py-3.5\">\n              <div class=\"flex items-center gap-2\">\n                <div class=\"bg-success/10 text-success flex size-6 items-center justify-center rounded-full\">\n                  <lucide-icon [img]=\"BadgeCheck\" class=\"size-4\" />\n                </div>\n                <div>\n                  <h3 class=\"text-foreground text-xs font-semibold\">Verified Compliance Credential</h3>\n                  <p class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                    Credential ID: {{ cert.credentialId }}\n                  </p>\n                </div>\n              </div>\n\n              <button\n                type=\"button\"\n                class=\"text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:ring-ring rounded-md p-1 transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n                aria-label=\"Close modal\"\n                (click)=\"closeCertificateModal()\"\n              >\n                <lucide-icon [img]=\"X\" class=\"size-4\" />\n              </button>\n            </div>\n\n            <div class=\"space-y-5 p-6\">\n              <div\n                class=\"border-success/30 bg-success/5 dark:bg-success/10 relative rounded-lg border-2 border-dashed p-6 text-center\"\n              >\n                <div\n                  class=\"border-success/40 bg-success/10 text-success mx-auto flex size-12 items-center justify-center rounded-full border shadow-xs\"\n                >\n                  <lucide-icon [img]=\"Award\" class=\"size-6\" />\n                </div>\n\n                <div class=\"mt-3 space-y-1\">\n                  <span class=\"text-success text-xs font-semibold tracking-wide\">\n                    Official Certificate of Mastery & Regulatory Compliance\n                  </span>\n                  <h4 class=\"text-foreground text-lg font-bold\">{{ cert.title }}</h4>\n                  <p class=\"text-muted-foreground text-xs\">{{ cert.standard }}</p>\n                </div>\n\n                <ui-separator class=\"my-4\" />\n\n                <div class=\"space-y-1.5\">\n                  <p class=\"text-muted-foreground text-xs\">This certifies that</p>\n                  <p class=\"text-foreground text-base font-bold\">Elena Rostova</p>\n                  <p class=\"text-muted-foreground text-xs\">Senior Staff Engineer · EMP-4092</p>\n                  <p class=\"text-muted-foreground/90 mx-auto max-w-lg pt-1 text-xs leading-relaxed\">\n                    {{ cert.description }}\n                  </p>\n                </div>\n\n                <div class=\"border-border/60 mt-5 grid grid-cols-2 gap-3 border-t pt-4 text-left sm:grid-cols-4\">\n                  <div class=\"space-y-0.5\">\n                    <span class=\"text-muted-foreground text-xs\">Exam Score</span>\n                    <p class=\"text-success font-mono text-xs font-bold tabular-nums\">{{ cert.scoreStatus }}</p>\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <span class=\"text-muted-foreground text-xs\">Duration</span>\n                    <p class=\"text-foreground font-mono text-xs font-semibold tabular-nums\">\n                      {{ cert.durationHours }} Hours\n                    </p>\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <span class=\"text-muted-foreground text-xs\">Issued Date</span>\n                    <p class=\"text-foreground font-mono text-xs tabular-nums\">{{ cert.completionDate }}</p>\n                  </div>\n                  <div class=\"space-y-0.5\">\n                    <span class=\"text-muted-foreground text-xs\">Valid Until</span>\n                    <p class=\"text-foreground font-mono text-xs font-medium tabular-nums\">{{ cert.expirationDate }}</p>\n                  </div>\n                </div>\n              </div>\n\n              <div class=\"border-border bg-muted/40 space-y-2 rounded-lg border p-3.5 text-xs\">\n                <div class=\"flex items-center justify-between\">\n                  <div class=\"text-foreground flex items-center gap-1.5 font-medium\">\n                    <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-3.5\" />\n                    <span>Cryptographic Digest (SHA-256)</span>\n                  </div>\n                  <button\n                    type=\"button\"\n                    class=\"text-primary flex items-center gap-1 text-xs hover:underline\"\n                    (click)=\"copyToClipboard(cert.sha256Digest, 'digest')\"\n                  >\n                    @if (copiedDigest()) {\n                      <lucide-icon [img]=\"Check\" class=\"text-success size-3\" />\n                    } @else {\n                      <lucide-icon [img]=\"Copy\" class=\"size-3\" />\n                    }\n                    <span>{{ copiedDigest() ? 'Copied' : 'Copy Hash' }}</span>\n                  </button>\n                </div>\n                <p class=\"text-muted-foreground font-mono text-xs break-all\">{{ cert.sha256Digest }}</p>\n                <div\n                  class=\"border-border/50 text-muted-foreground flex flex-wrap items-center justify-between gap-2 border-t pt-1\"\n                >\n                  <span>Accreditation: {{ cert.accreditationBody }}</span>\n                  <span class=\"font-mono tabular-nums\">Ledger: OpenAttestation v3</span>\n                </div>\n              </div>\n            </div>\n\n            <div\n              class=\"border-border bg-muted/40 flex flex-col-reverse gap-2 border-t p-4 sm:flex-row sm:items-center sm:justify-between\"\n            >\n              <button\n                ui-button\n                variant=\"ghost\"\n                size=\"sm\"\n                class=\"text-xs\"\n                (click)=\"copyToClipboard('https://uipkge.dev/verify/' + cert.credentialId, 'url')\"\n              >\n                @if (copiedVerifyUrl()) {\n                  <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n                } @else {\n                  <lucide-icon [img]=\"Share2\" class=\"size-3.5\" />\n                }\n                <span>{{ copiedVerifyUrl() ? 'Link Copied!' : 'Copy Verification Link' }}</span>\n              </button>\n\n              <div class=\"flex items-center gap-2\">\n                <button ui-button variant=\"outline\" size=\"sm\" class=\"text-xs\" (click)=\"closeCertificateModal()\">\n                  Close\n                </button>\n                <button\n                  ui-button\n                  aria-label=\"Download attachment\"\n                  variant=\"default\"\n                  size=\"sm\"\n                  class=\"gap-1.5 text-xs shadow-xs\"\n                  (click)=\"downloadFromCertificate()\"\n                >\n                  <lucide-icon [img]=\"Download\" class=\"size-3.5\" />\n                  <span>Download PDF Certificate</span>\n                </button>\n              </div>\n            </div>\n          </div>\n        </div>\n      }\n\n      <!-- Retake Course Confirmation Modal -->\n      @if (retakeModalCourse(); as retake) {\n        <div\n          class=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 backdrop-blur-xs transition-opacity\"\n          (click)=\"onOverlayClick($event, 'retake')\"\n        >\n          <div\n            class=\"border-border bg-card text-card-foreground relative w-full max-w-lg overflow-hidden rounded-xl border shadow-sm\"\n          >\n            <div class=\"border-border bg-muted/40 flex items-center justify-between border-b px-5 py-3.5\">\n              <div class=\"flex items-center gap-2\">\n                <div class=\"bg-primary/10 text-primary flex size-6 items-center justify-center rounded-full\">\n                  <lucide-icon [img]=\"RotateCcw\" class=\"size-3.5\" />\n                </div>\n                <h3 class=\"text-foreground text-sm font-bold\">Launch Refresher Assessment</h3>\n              </div>\n              <button\n                aria-label=\"Close retake modal\"\n                type=\"button\"\n                class=\"text-muted-foreground hover:bg-accent hover:text-foreground rounded-md p-1\"\n                (click)=\"closeRetakeModal()\"\n              >\n                <lucide-icon [img]=\"X\" class=\"size-4\" />\n              </button>\n            </div>\n\n            <div class=\"space-y-4 p-5 text-xs\">\n              <div class=\"space-y-1\">\n                <span class=\"text-muted-foreground font-mono text-xs font-medium\">Module: {{ retake.code }}</span>\n                <h4 class=\"text-foreground text-sm font-semibold\">{{ retake.title }}</h4>\n              </div>\n\n              <div class=\"border-warning/30 bg-warning/10 text-warning rounded-md border p-3\">\n                <div class=\"flex gap-2\">\n                  <lucide-icon [img]=\"AlertCircle\" class=\"text-warning size-4 shrink-0\" />\n                  <div class=\"space-y-1 leading-relaxed\">\n                    <p class=\"font-semibold\">Notice regarding existing valid credential:</p>\n                    <p>\n                      Your current passing score ({{ retake.score }}%) and verified credential ({{\n                        retake.credentialId\n                      }}) will remain active and valid in company compliance audits until the new assessment is\n                      submitted.\n                    </p>\n                  </div>\n                </div>\n              </div>\n\n              <div class=\"border-border bg-muted/30 grid grid-cols-2 gap-2 rounded-md border p-3 font-mono\">\n                <div>\n                  <span class=\"text-muted-foreground\">Estimated Time:</span>\n                  <p class=\"text-foreground font-semibold\">{{ retake.duration }}</p>\n                </div>\n                <div>\n                  <span class=\"text-muted-foreground\">Passing Threshold:</span>\n                  <p class=\"text-success font-semibold\">80% or Higher</p>\n                </div>\n              </div>\n            </div>\n\n            <div class=\"border-border bg-muted/40 flex items-center justify-end gap-2 border-t p-4\">\n              <button\n                ui-button\n                aria-label=\"Close retake modal\"\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"text-xs\"\n                (click)=\"closeRetakeModal()\"\n              >\n                Cancel\n              </button>\n              <button\n                ui-button\n                variant=\"default\"\n                size=\"sm\"\n                class=\"gap-1.5 text-xs shadow-xs\"\n                (click)=\"handleConfirmRetake()\"\n              >\n                <lucide-icon [img]=\"PlayCircle\" class=\"size-3.5\" />\n                <span>Launch Course Environment</span>\n              </button>\n            </div>\n          </div>\n        </div>\n      }\n    </div>\n  `,\n})\nexport class UiTrainingComplianceTrackerComponent {\n  protected readonly AlertCircle = AlertCircle\n  protected readonly Award = Award\n  protected readonly BadgeCheck = BadgeCheck\n  protected readonly Building2 = Building2\n  protected readonly CalendarClock = CalendarClock\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Copy = Copy\n  protected readonly Download = Download\n  protected readonly FileCheck = FileCheck\n  protected readonly FileDown = FileDown\n  protected readonly PlayCircle = PlayCircle\n  protected readonly RefreshCw = RefreshCw\n  protected readonly RotateCcw = RotateCcw\n  protected readonly Search = Search\n  protected readonly Share2 = Share2\n  protected readonly Shield = Shield\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Users = Users\n  protected readonly X = X\n\n  protected readonly categories = filterCategories\n\n  @Input() set defaultFilter(v: string | undefined) {\n    if (v !== undefined) this.activeFilter.set(v)\n  }\n  @Input('class') className?: string\n\n  readonly activeFilter = signal('all')\n  readonly searchQuery = signal('')\n  readonly selectedCertificate = signal<ComplianceCourse | null>(null)\n  readonly retakeModalCourse = signal<ComplianceCourse | null>(null)\n  readonly isDownloadingAll = signal(false)\n  readonly downloadBannerMessage = signal<string | null>(null)\n  readonly copiedCertId = signal(false)\n  readonly copiedDigest = signal(false)\n  readonly copiedVerifyUrl = signal(false)\n  readonly retakeSuccessMessage = signal<string | null>(null)\n\n  readonly filteredCourses = computed(() => {\n    const filter = this.activeFilter()\n    const query = this.searchQuery().trim().toLowerCase()\n    return coursesData.filter((course) => {\n      let matchesCategory = true\n      if (filter === 'security') {\n        matchesCategory = course.categoryKey === 'security' || course.categoryKey === 'privacy'\n      } else if (filter === 'ethics') {\n        matchesCategory = course.categoryKey === 'ethics'\n      } else if (filter === 'governance') {\n        matchesCategory = course.categoryKey === 'governance' || course.categoryKey === 'finance'\n      } else if (filter === 'finance') {\n        matchesCategory = course.categoryKey === 'finance'\n      }\n      if (!query) return matchesCategory\n      const matchesSearch =\n        course.title.toLowerCase().includes(query) ||\n        course.code.toLowerCase().includes(query) ||\n        course.category.toLowerCase().includes(query) ||\n        course.standard.toLowerCase().includes(query) ||\n        course.credentialId.toLowerCase().includes(query) ||\n        course.instructor.toLowerCase().includes(query)\n      return matchesCategory && matchesSearch\n    })\n  })\n\n  get rootClass(): string {\n    return cn('w-full space-y-6', this.className)\n  }\n\n  filterPillClass(id: string): string {\n    const isActive = this.activeFilter() === id\n    return cn(\n      'focus-visible:ring-ring inline-flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n      isActive\n        ? 'bg-primary text-primary-foreground shadow-xs'\n        : 'border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground border',\n    )\n  }\n\n  filterCountClass(id: string): string {\n    const isActive = this.activeFilter() === id\n    return cn(\n      'py-0.2 rounded-full px-1.5 font-mono text-xs tabular-nums',\n      isActive ? 'bg-primary-foreground/20 text-primary-foreground' : 'bg-muted text-muted-foreground',\n    )\n  }\n\n  handleDownloadAllPdf(): void {\n    if (this.isDownloadingAll()) return\n    this.isDownloadingAll.set(true)\n    this.downloadBannerMessage.set('Compiling 5 verified compliance certificates into archival PDF...')\n    setTimeout(() => {\n      this.isDownloadingAll.set(false)\n      this.downloadBannerMessage.set(\n        '✓ Download complete: Elena_Rostova_Annual_Compliance_Certificates_2026.pdf (1.8 MB)',\n      )\n      setTimeout(() => this.downloadBannerMessage.set(null), 4500)\n    }, 1600)\n  }\n\n  downloadFromCertificate(): void {\n    this.handleDownloadAllPdf()\n    this.closeCertificateModal()\n  }\n\n  openCertificateModal(course: ComplianceCourse): void {\n    this.selectedCertificate.set(course)\n    this.copiedCertId.set(false)\n    this.copiedDigest.set(false)\n    this.copiedVerifyUrl.set(false)\n  }\n\n  closeCertificateModal(): void {\n    this.selectedCertificate.set(null)\n  }\n\n  openRetakeModal(course: ComplianceCourse): void {\n    this.retakeModalCourse.set(course)\n  }\n\n  closeRetakeModal(): void {\n    this.retakeModalCourse.set(null)\n  }\n\n  handleConfirmRetake(): void {\n    const course = this.retakeModalCourse()\n    if (!course) return\n    const title = course.title\n    this.closeRetakeModal()\n    this.retakeSuccessMessage.set(\n      `Interactive refresher environment launched for \"${title}\". Your existing credential remains valid.`,\n    )\n    setTimeout(() => this.retakeSuccessMessage.set(null), 4500)\n  }\n\n  copyToClipboard(text: string, type: 'certId' | 'digest' | 'url'): void {\n    try {\n      void navigator.clipboard?.writeText(text)\n    } catch {\n      // Clipboard unavailable — still show copied feedback.\n    }\n    if (type === 'certId') {\n      this.copiedCertId.set(true)\n      setTimeout(() => this.copiedCertId.set(false), 2000)\n    } else if (type === 'digest') {\n      this.copiedDigest.set(true)\n      setTimeout(() => this.copiedDigest.set(false), 2000)\n    } else if (type === 'url') {\n      this.copiedVerifyUrl.set(true)\n      setTimeout(() => this.copiedVerifyUrl.set(false), 2000)\n    }\n  }\n\n  onOverlayClick(event: MouseEvent, which: 'certificate' | 'retake'): void {\n    if (event.target === event.currentTarget) {\n      if (which === 'certificate') this.closeCertificateModal()\n      else this.closeRetakeModal()\n    }\n  }\n\n  @HostListener('window:keydown', ['$event'])\n  onKeyDown(event: KeyboardEvent): void {\n    if (event.key === 'Escape') {\n      if (this.selectedCertificate()) this.closeCertificateModal()\n      if (this.retakeModalCourse()) this.closeRetakeModal()\n    }\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/training-compliance-tracker/training-compliance-tracker.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/training-compliance-tracker/index.ts",
      "content": "export { UiTrainingComplianceTrackerComponent, type ComplianceCourse } from './training-compliance-tracker.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/training-compliance-tracker/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/progress.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/table.json"
  ],
  "description": "Annual mandatory employee compliance training dashboard with certification badges, renewal deadlines, assessment scorecards, verified credential preview modal, and certificate export controls.",
  "categories": [
    "hr",
    "app",
    "security"
  ]
}