gangvy 4 mesiacov pred
commit
33612d5ea4
57 zmenil súbory, kde vykonal 19440 pridanie a 0 odobranie
  1. 17 0
      .editorconfig
  2. 46 0
      .gitignore
  3. 4 0
      .vscode/extensions.json
  4. 20 0
      .vscode/launch.json
  5. 42 0
      .vscode/tasks.json
  6. 53 0
      README.md
  7. 98 0
      angular.json
  8. 64 0
      deploy.ps1
  9. 282 0
      docs/external-creator-sourcing-api-evaluation.md
  10. 334 0
      docs/overnight-static-demo-backlog.md
  11. 36 0
      docs/pages/01-workbench-upload.md
  12. 32 0
      docs/pages/02-demand-confirmation.md
  13. 34 0
      docs/pages/03-rule-center.md
  14. 32 0
      docs/pages/04-recommendation-engine.md
  15. 29 0
      docs/pages/05-recommendation-list-export.md
  16. 30 0
      docs/pages/06-feedback-learning.md
  17. 29 0
      docs/pages/07-resource-library.md
  18. 30 0
      docs/pages/08-template-center.md
  19. 60 0
      docs/pages/09-account-detail-notes.md
  20. 163 0
      docs/product-requirements.md
  21. 101 0
      docs/static-demo-review-report.md
  22. 9525 0
      package-lock.json
  23. 48 0
      package.json
  24. BIN
      public/favicon.ico
  25. 213 0
      server/server.ts
  26. 12 0
      src/app/app.config.ts
  27. 66 0
      src/app/app.html
  28. 3 0
      src/app/app.routes.ts
  29. 3415 0
      src/app/app.scss
  30. 23 0
      src/app/app.spec.ts
  31. 32 0
      src/app/app.ts
  32. 168 0
      src/app/components/account-detail.component.html
  33. 15 0
      src/app/components/account-detail.component.ts
  34. 2461 0
      src/app/demo-state.service.ts
  35. 244 0
      src/app/models.ts
  36. 214 0
      src/app/pages/creator-search-page.component.html
  37. 15 0
      src/app/pages/creator-search-page.component.ts
  38. 175 0
      src/app/pages/delivery-page.component.html
  39. 13 0
      src/app/pages/delivery-page.component.ts
  40. 105 0
      src/app/pages/learning-page.component.html
  41. 13 0
      src/app/pages/learning-page.component.ts
  42. 154 0
      src/app/pages/resources-page.component.html
  43. 13 0
      src/app/pages/resources-page.component.ts
  44. 138 0
      src/app/pages/rules-page.component.html
  45. 13 0
      src/app/pages/rules-page.component.ts
  46. 152 0
      src/app/pages/tasks-page.component.html
  47. 12 0
      src/app/pages/tasks-page.component.ts
  48. 112 0
      src/app/pages/templates-page.component.html
  49. 12 0
      src/app/pages/templates-page.component.ts
  50. 417 0
      src/app/pages/workspace-page.component.html
  51. 17 0
      src/app/pages/workspace-page.component.ts
  52. 13 0
      src/index.html
  53. 6 0
      src/main.ts
  54. 22 0
      src/styles.scss
  55. 15 0
      tsconfig.app.json
  56. 34 0
      tsconfig.json
  57. 14 0
      tsconfig.spec.json

+ 17 - 0
.editorconfig

@@ -0,0 +1,17 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.ts]
+quote_type = single
+ij_typescript_use_double_quotes = false
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false

+ 46 - 0
.gitignore

@@ -0,0 +1,46 @@
+# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
+
+# Compiled output
+/dist
+/tmp
+/out-tsc
+/bazel-out
+
+# Node
+/node_modules
+npm-debug.log
+yarn-error.log
+*.log
+*.err.log
+output/
+.playwright-cli/
+
+# IDEs and editors
+.idea/
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# Visual Studio Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# Miscellaneous
+/.angular/cache
+.sass-cache/
+/connect.lock
+/coverage
+/libpeerconnection.log
+testem.log
+/typings
+
+# System files
+.DS_Store
+Thumbs.db

+ 4 - 0
.vscode/extensions.json

@@ -0,0 +1,4 @@
+{
+  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
+  "recommendations": ["angular.ng-template"]
+}

+ 20 - 0
.vscode/launch.json

@@ -0,0 +1,20 @@
+{
+  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "ng serve",
+      "type": "chrome",
+      "request": "launch",
+      "preLaunchTask": "npm: start",
+      "url": "http://localhost:4200/"
+    },
+    {
+      "name": "ng test",
+      "type": "chrome",
+      "request": "launch",
+      "preLaunchTask": "npm: test",
+      "url": "http://localhost:9876/debug.html"
+    }
+  ]
+}

+ 42 - 0
.vscode/tasks.json

@@ -0,0 +1,42 @@
+{
+  // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "type": "npm",
+      "script": "start",
+      "isBackground": true,
+      "problemMatcher": {
+        "owner": "typescript",
+        "pattern": "$tsc",
+        "background": {
+          "activeOnStart": true,
+          "beginsPattern": {
+            "regexp": "(.*?)"
+          },
+          "endsPattern": {
+            "regexp": "bundle generation complete"
+          }
+        }
+      }
+    },
+    {
+      "type": "npm",
+      "script": "test",
+      "isBackground": true,
+      "problemMatcher": {
+        "owner": "typescript",
+        "pattern": "$tsc",
+        "background": {
+          "activeOnStart": true,
+          "beginsPattern": {
+            "regexp": "(.*?)"
+          },
+          "endsPattern": {
+            "regexp": "bundle generation complete"
+          }
+        }
+      }
+    }
+  ]
+}

+ 53 - 0
README.md

@@ -0,0 +1,53 @@
+# 提号AI Demo
+
+面向商务和媒介团队的 Brief 智能拆解与媒体推荐 Demo。一稿用于客户沟通,重点展示业务闭环和交互,不接入真实 OA 数据库与平台采集。
+
+## 技术栈
+
+- Frontend:Angular 20 + SCSS
+- Backend:Node.js 24 原生 TypeScript Mock API
+- Export:Demo 使用 HTML Excel 方式生成 `.xls`
+
+## 运行方式
+
+安装依赖后启动前端:
+
+```bash
+npm.cmd install
+npm.cmd start
+```
+
+另开一个终端启动 Mock API:
+
+```bash
+npm.cmd run api
+```
+
+默认地址:
+
+- Web:http://localhost:4200
+- API:http://localhost:4300/api/health
+
+## 已实现范围
+
+- Brief 上传入口和模板入口
+- AI 需求抽取结果展示
+- 提号规则启用/停用
+- AI 提号执行进度
+- 推荐名单预览和导出
+- 客户反馈提炼规则
+- 任务记录、资源库、规则库、反馈学习、模板中心页面
+
+## 文档
+
+- 总 PRD:[docs/product-requirements.md](docs/product-requirements.md)
+- 子页面 PRD:[docs/pages](docs/pages)
+
+## 后续接入点
+
+- Excel/Docx 真实解析
+- OA 媒体资源接口或数据库
+- 本地资源库字段映射
+- 小红书、抖音、B站等平台后台采样
+- 推荐名单精细化 Excel 样式导出
+- 用户权限、任务版本、审计日志

+ 98 - 0
angular.json

@@ -0,0 +1,98 @@
+{
+  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+  "version": 1,
+  "newProjectRoot": "projects",
+  "projects": {
+    "tihao-ai": {
+      "projectType": "application",
+      "schematics": {
+        "@schematics/angular:component": {
+          "style": "scss"
+        }
+      },
+      "root": "",
+      "sourceRoot": "src",
+      "prefix": "app",
+      "architect": {
+        "build": {
+          "builder": "@angular/build:application",
+          "options": {
+            "browser": "src/main.ts",
+            "polyfills": [
+              "zone.js"
+            ],
+            "tsConfig": "tsconfig.app.json",
+            "inlineStyleLanguage": "scss",
+            "assets": [
+              {
+                "glob": "**/*",
+                "input": "public"
+              }
+            ],
+            "styles": [
+              "src/styles.scss"
+            ]
+          },
+          "configurations": {
+            "production": {
+              "budgets": [
+                {
+                  "type": "initial",
+                  "maximumWarning": "620kB",
+                  "maximumError": "1.2MB"
+                },
+                {
+                  "type": "anyComponentStyle",
+                  "maximumWarning": "56kB",
+                  "maximumError": "64kB"
+                }
+              ],
+              "outputHashing": "all"
+            },
+            "development": {
+              "optimization": false,
+              "extractLicenses": false,
+              "sourceMap": true
+            }
+          },
+          "defaultConfiguration": "production"
+        },
+        "serve": {
+          "builder": "@angular/build:dev-server",
+          "configurations": {
+            "production": {
+              "buildTarget": "tihao-ai:build:production"
+            },
+            "development": {
+              "buildTarget": "tihao-ai:build:development"
+            }
+          },
+          "defaultConfiguration": "development"
+        },
+        "extract-i18n": {
+          "builder": "@angular/build:extract-i18n"
+        },
+        "test": {
+          "builder": "@angular/build:karma",
+          "options": {
+            "polyfills": [
+              "zone.js",
+              "zone.js/testing"
+            ],
+            "tsConfig": "tsconfig.spec.json",
+            "inlineStyleLanguage": "scss",
+            "assets": [
+              {
+                "glob": "**/*",
+                "input": "public"
+              }
+            ],
+            "styles": [
+              "src/styles.scss"
+            ]
+          }
+        }
+      }
+    }
+  }
+}

+ 64 - 0
deploy.ps1

@@ -0,0 +1,64 @@
+# tihao-ai demo deployment script.
+# Builds the Angular app with the /dev/tihao-ai/ prefix, uploads it to Huawei OBS,
+# grants public-read, then refreshes the CDN directory.
+
+$ErrorActionPreference = "Stop"
+Set-StrictMode -Version Latest
+
+$ProjectName = "tihao-ai"
+$BasePath = "/dev/$ProjectName/"
+$BucketPath = "obs://nova-cloud/dev/$ProjectName"
+$PublicUrl = "https://app.fmode.cn/dev/$ProjectName/"
+$DistPath = Join-Path $PSScriptRoot "dist\$ProjectName\browser"
+
+# Tool paths.
+$OBSUTIL = "E:\obsutil_windows_amd64_5.7.9\obsutil.exe"
+$HCLOUD = "E:\huaweicloud-cli-windows-amd64\hcloud.exe"
+
+# Same deployment target as E:\workspace\apig-pay\deploy.ps1.
+# Credentials are read from environment variables so they are not committed to git.
+$ObsAccessKey = $env:TIHAO_OBS_ACCESS_KEY
+$ObsSecretKey = $env:TIHAO_OBS_SECRET_KEY
+$ObsEndpoint = if ($env:TIHAO_OBS_ENDPOINT) { $env:TIHAO_OBS_ENDPOINT } else { "obs.cn-south-1.myhuaweicloud.com" }
+
+$CdnAccessKey = $env:TIHAO_CDN_ACCESS_KEY
+$CdnSecretKey = $env:TIHAO_CDN_SECRET_KEY
+$CdnRegion = if ($env:TIHAO_CDN_REGION) { $env:TIHAO_CDN_REGION } else { "cn-north-1" }
+
+if (-not $ObsAccessKey -or -not $ObsSecretKey -or -not $CdnAccessKey -or -not $CdnSecretKey) {
+  throw "Missing deployment credentials. Set TIHAO_OBS_ACCESS_KEY, TIHAO_OBS_SECRET_KEY, TIHAO_CDN_ACCESS_KEY, and TIHAO_CDN_SECRET_KEY before running this script."
+}
+
+if (-not (Test-Path -LiteralPath $OBSUTIL)) {
+  throw "obsutil not found: $OBSUTIL"
+}
+
+if (-not (Test-Path -LiteralPath $HCLOUD)) {
+  throw "hcloud not found: $HCLOUD"
+}
+
+Push-Location $PSScriptRoot
+try {
+  Write-Host "Building $ProjectName with base href $BasePath"
+  & .\node_modules\.bin\ng.cmd build "--base-href=$BasePath"
+
+  if (-not (Test-Path -LiteralPath $DistPath)) {
+    throw "Build output not found: $DistPath"
+  }
+
+  Write-Host "Removing old OBS files: $BucketPath"
+  & $OBSUTIL rm $BucketPath -r -f "-i=$ObsAccessKey" "-k=$ObsSecretKey" "-e=$ObsEndpoint"
+
+  Write-Host "Syncing build output to OBS: $DistPath -> $BucketPath"
+  & $OBSUTIL sync $DistPath $BucketPath "-i=$ObsAccessKey" "-k=$ObsSecretKey" "-e=$ObsEndpoint" "-acl=public-read"
+
+  Write-Host "Applying public-read ACL"
+  & $OBSUTIL chattri $BucketPath -r -f "-i=$ObsAccessKey" "-k=$ObsSecretKey" "-e=$ObsEndpoint" "-acl=public-read"
+
+  Write-Host "Refreshing CDN directory: $PublicUrl"
+  & $HCLOUD CDN CreateRefreshTasks/v2 "--cli-region=$CdnRegion" "--refresh_task.urls.1=$PublicUrl" "--refresh_task.type=directory" "--cli-access-key=$CdnAccessKey" "--cli-secret-key=$CdnSecretKey"
+
+  Write-Host "Deployment complete: $PublicUrl"
+} finally {
+  Pop-Location
+}

+ 282 - 0
docs/external-creator-sourcing-api-evaluation.md

@@ -0,0 +1,282 @@
+# 外部提号数据 API 方案评估
+
+更新时间:2026-05-12
+
+## 1. 结论
+
+项目的核心需求是“根据客户 Brief 自动找博主”,不是单纯抓取公开内容。因此外部方案优先级应该从“社媒原始采集 API”调整为“商业达人库 / 创作者搜索 API”。
+
+本轮判断:
+
+- Just One API 是目前最接近“现成提号接口”的候选方案,尤其适合小红书蒲公英、抖音星图这类商业达人场景。
+- TikHub 更适合做内容采样和验证,例如近 10 条笔记、评论、近期活跃度、风格判断,不适合单独承担完整提号。
+- KOLRank 或同类企业达人库 API 更适合作为长期数据底座,用于账号信息补全、榜单、监测、回采、订阅和资源库刷新。
+- 蒲公英、星图、花火等官方商业平台 API 适合报价、合作状态、订单和投后数据,不适合做全站找号主数据源。
+
+推荐路线:
+
+> 本地资源库作为主资产,Just One 做外部商业达人召回,TikHub 做内容采样验证,KOLRank/同类数据商做长期数据底座,官方商业平台做报价和投后回填。
+
+## 2. 项目需求拆解
+
+当前项目需要支持的“找博主”流程:
+
+1. 解析客户 Brief,抽取平台、行业、关键词、预算、城市、粉丝画像、内容风格、排除项。
+2. 从本地资源库和外部数据源生成候选博主池。
+3. 对候选博主补全报价、粉丝量、地域、内容标签、粉丝画像、互动指标、近期内容表现。
+4. 采样近 10 条内容,判断内容风格、商业浓度、近期活跃度、是否符合 Brief。
+5. 融合历史合作、供应商关系、黑名单、客户反馈等本地沉淀数据。
+6. AI 重排并输出内部复核版和客户推荐版名单。
+
+难点集中在第 2-4 步:如果完全自研,需要分别封装小红书、抖音、B站等平台搜索、账号主页、内容列表、评论、商业报价、粉丝画像等能力,复杂度高且稳定性不确定。
+
+## 3. 候选外部方案定位
+
+### 3.1 Just One API
+
+定位:商业达人搜索 / 蒲公英与星图类数据聚合。
+
+适合承担:
+
+- 按关键词、粉丝区间、报价区间、达人性别、粉丝画像、内容标签搜索创作者。
+- 获取达人报价、合作状态、商业标签、粉丝基础信息。
+- 作为 Brief 到候选博主的第一层外部召回源。
+
+不应承担:
+
+- 唯一最终排序。
+- 完整内容风格判断。
+- 评论正文 VOC 分析。
+- 本地历史合作、客户偏好、供应商可信度判断。
+
+注意:API key 属于敏感信息,只应通过环境变量或后端密钥管理配置,不能写入前端、文档或日志。
+
+### 3.2 TikHub
+
+定位:社媒内容采样和验证 API。
+
+适合承担:
+
+- 小红书笔记搜索、笔记详情、评论、用户作品列表。
+- 抖音用户搜索、视频搜索、用户主页作品。
+- B站视频、评论、用户内容采样。
+- 对候选账号做近 10 条内容采样、风格判断、评论/VOC 验证、近期活跃度校验。
+
+不应承担:
+
+- 完整商业提号引擎。
+- 报价、合作状态、投放适配等商业字段的唯一来源。
+
+### 3.3 KOLRank / 同类企业达人库 API
+
+定位:长期达人数据底座。
+
+适合承担:
+
+- 多平台账号信息补全。
+- 账号数据刷新、监测、回采、订阅。
+- 榜单和历史表现数据。
+- 本地资源库字段补齐与过期数据刷新。
+
+不一定直接适合:
+
+- 按自然语言 Brief 一步生成最终名单。
+- 近 10 条内容的精细风格判断。
+
+### 3.4 官方商业平台 API
+
+包括小红书蒲公英、抖音星图、B站花火等。
+
+适合承担:
+
+- 官方报价、合作状态、订单状态。
+- 授权账号下的投后表现数据。
+- 投放复盘和商业可投性校验。
+
+不适合承担:
+
+- 全站关键词找博主。
+- 任意账号近 10 条内容采样。
+- 任意笔记评论正文采集。
+- 全站 KOC/KOL 发现。
+
+## 4. Just One API 初步实测结论
+
+本轮使用小红书蒲公英创作者搜索相关接口做了初步验证。密钥不记录在本文档中。
+
+### 4.1 DHA / 母婴类 Brief
+
+可行度:A-
+
+验证结果:
+
+- `keyword=DHA` 可召回约 3469 个候选。
+- 增加女性达人筛选后,可召回约 2392 个候选。
+- 返回字段包含达人名、userId、红书号、地域、图文报价、视频报价、最低报价、合作状态、个人标签、内容特征标签。
+- 搜索结果里出现了符合预算和人设的账号,例如母婴、妈妈、萌娃、婴幼儿阶段相关标签账号,报价也能落在中腰部预算范围内。
+
+说明:
+
+- 对“DHA、母婴、妈妈人设、预算约束、商业合作状态”这类 Brief,Just One 能提供有实际价值的候选池。
+- 后续需要继续验证创作者详情、粉丝画像、笔记表现接口,确认是否能稳定覆盖女粉比例、年龄层、阅读中位、CPE、预估阅读单价等硬指标。
+
+### 4.2 Nest / 城市空间探店类 Brief
+
+可行度:B
+
+验证结果:
+
+- 城市探店类需求更依赖地域、同省不跨区、线下到店意愿、空间/家居/生活方式内容匹配。
+- Just One 搜索结果中有地域字段,但是否支持严格城市筛选仍需进一步验证。
+- 更现实的做法是“关键词召回 + location 后过滤 + 本地资源库补充 + TikHub 内容采样验证”。
+
+说明:
+
+- 这类需求不建议只依赖 Just One。
+- 本地资源库里的历史合作、城市、供应商、报价可信度会更关键。
+- TikHub 可用于核验账号近期是否真的在做探店、空间、家居、生活方式内容。
+
+### 4.3 实测限制
+
+- 后续调用出现 `INSUFFICIENT BALANCE`,因此创作者详情、粉丝画像、笔记表现接口没有完整跑完。
+- `contentTag=母婴,记录生活` 这类中文自由文本参数曾返回 400,推测内容标签需要使用供应商枚举值或字典值,不能直接传中文。
+- 搜索结果列表中的部分 `fansCount` 返回 0,不能只依赖搜索列表判断粉丝量,需要调用详情或画像接口补齐。
+
+## 5. 推荐系统架构
+
+建议在项目中抽象统一的外部数据适配层,不让业务页面直接依赖某个供应商字段。
+
+```text
+Brief 解析
+  -> SearchCriteria 标准查询条件
+  -> 本地资源库召回
+  -> Just One CreatorSearchProvider 外部商业召回
+  -> TikHub ContentSamplingProvider 内容采样验证
+  -> KOLRank / 企业数据 API 账号数据补全
+  -> 官方商业平台报价和投后补充
+  -> NormalizeAdapter 统一字段
+  -> AI Scoring / Rerank
+  -> 推荐名单导出
+```
+
+核心接口建议:
+
+- `CreatorSearchProvider`:根据关键词、平台、预算、粉丝、性别、地域、内容标签召回候选博主。
+- `CreatorProfileProvider`:补全账号主页、粉丝数、地域、报价、合作状态、标签、粉丝画像。
+- `ContentSamplingProvider`:获取近 10 条内容、标题、正文、互动、发布时间、评论样本。
+- `CommercialDataProvider`:获取报价、合作状态、订单、投后指标。
+- `NormalizeAdapter`:把不同供应商字段映射为项目统一的 `CandidateCreator`、`CreatorProfile`、`ContentSample`、`CommercialMetrics`。
+- `ProviderHealthMonitor`:记录接口余额、错误率、限流、字段缺失率、数据更新时间。
+
+## 6. 统一数据模型建议
+
+### CandidateCreator
+
+- `platform`:平台,如 xiaohongshu、douyin、bilibili。
+- `externalProvider`:来源,如 local、justone、tikhub、kolrank。
+- `platformUserId`:平台用户 ID。
+- `displayName`:账号名。
+- `profileUrl`:主页链接。
+- `location`:地域。
+- `fansCount`:粉丝数。
+- `contentTags`:内容标签。
+- `personaTags`:人设标签。
+- `imagePrice`:图文报价。
+- `videoPrice`:视频报价。
+- `minPrice`:最低报价。
+- `cooperationStatus`:合作状态。
+- `sourceConfidence`:来源可信度。
+
+### CreatorProfile
+
+- `gender`:达人性别。
+- `fanGenderDistribution`:粉丝性别分布。
+- `fanAgeDistribution`:粉丝年龄分布。
+- `medianReadCount`:阅读中位数。
+- `medianEngagementCount`:互动中位数。
+- `estimatedCpe`:预估 CPE。
+- `estimatedReadUnitCost`:预估阅读单价。
+- `recentPostCount`:近期发布量。
+- `riskFlags`:风险标记。
+
+### ContentSample
+
+- `title`:标题。
+- `contentText`:正文摘要。
+- `publishTime`:发布时间。
+- `readCount`:阅读。
+- `likeCount`:点赞。
+- `commentCount`:评论量。
+- `collectCount`:收藏。
+- `shareCount`:分享。
+- `styleTags`:内容风格标签。
+- `adIntensity`:商业浓度判断。
+- `briefMatchReason`:匹配理由。
+
+## 7. PoC 验证计划
+
+建议用 3-5 个真实 Brief 做供应商压测,不只看接口是否能返回数据,而是看最终候选名单是否可用。
+
+### 7.1 测试 Brief
+
+- DHA / 母婴:小红书,妈妈人设,中腰部预算,女性粉丝 25-44,关注阅读中位和 CPE。
+- 城市空间探店:小红书或抖音,本地/同省,探店、家居、生活方式,关注到店可执行性。
+- 护肤转化:抖音,预算 1w 内,测评/种草,关注历史爆文率和转化内容能力。
+- B站成分党:B站,专业背书,长视频,关注内容深度和评论质量。
+
+### 7.2 验收指标
+
+- 每个 Brief 至少返回需求数量 3 倍的候选池。
+- 60%-70% 候选具备基本可复核价值,不是明显跑偏账号。
+- 关键字段覆盖率达到可用水平:平台 ID、主页、地域、粉丝数、报价、内容标签、粉丝画像、互动中位。
+- 内容采样可稳定返回近 10 条内容中的大部分。
+- 供应商接口错误、余额、限流、字段缺失可被监控和降级。
+- AI 重排后 Top 20 中至少 50% 能被媒介人工认为“可进入复核”。
+
+## 8. 接入优先级
+
+第一阶段:本地资源库 + Just One
+
+- 目标:先验证“根据 Brief 找博主”的外部商业召回能力。
+- 范围:小红书、抖音优先。
+- 输出:候选池、基础报价、合作状态、标签、地域。
+
+第二阶段:加入 TikHub
+
+- 目标:验证近 10 条内容采样、风格判断、评论/VOC、近期活跃度。
+- 范围:对 Just One 和本地库召回的候选做二次验证。
+- 输出:内容样本、风格标签、风险提示、Brief 匹配理由。
+
+第三阶段:加入 KOLRank / 同类数据底座
+
+- 目标:资源库长期刷新、账号数据补全、监测、榜单、订阅。
+- 范围:多平台账号库。
+- 输出:稳定的账号基础数据和历史表现。
+
+第四阶段:加入官方商业平台
+
+- 目标:报价可信度、订单状态、投后指标回填。
+- 范围:已经授权或已投放账号。
+- 输出:官方商业数据和复盘指标。
+
+## 9. 风险与注意事项
+
+- 供应商数据不是最终真相,需要保留人工复核、来源展示和字段更新时间。
+- 搜索接口返回结果可能受余额、限流、枚举参数、平台风控影响,需要做降级策略。
+- 不同供应商字段含义可能不一致,例如报价口径、粉丝数更新时间、互动中位统计周期,需要在 `NormalizeAdapter` 里标注来源和口径。
+- 内容标签、行业标签、粉丝画像等字段需要维护本地映射表,不能直接把供应商标签暴露给推荐逻辑。
+- 密钥必须保存在后端环境变量或密钥管理服务中,前端只调用本项目后端代理接口。
+- 对评论正文、用户内容采样等能力,需要评估平台条款、客户授权和数据合规边界。
+
+## 10. 建议决策
+
+短期不建议投入大量精力自研各平台“找博主”底层 API。
+
+更优选择是:
+
+1. 将 Just One 作为外部商业达人召回的第一候选供应商。
+2. 保留本地资源库作为最终可信资产和历史经验沉淀。
+3. 用 TikHub 补内容采样和评论验证。
+4. 用 AI 做 Brief 条件解析、字段融合、风险解释和重排,而不是直接相信外部 API 排序。
+5. 用 3-5 个真实 Brief 完成 PoC 后,再决定是否采购或接入更多供应商。
+

+ 334 - 0
docs/overnight-static-demo-backlog.md

@@ -0,0 +1,334 @@
+# 提号 AI 静态 Demo 通宵完善待办
+
+> 目标:把当前 Angular demo 完善成一个可独立演示的静态项目。重点不是接真数据,而是让客户一眼看懂“像蒲公英一样找博主 + AI 可解释选号 + 人工复核沉淀规则”的完整业务闭环。
+
+## 1. 对标蒲公英找博主方式
+
+蒲公英找博主可以拆成三类入口:
+
+1. 条件筛选式找人
+   - 按平台、行业类目、内容标签、粉丝量、报价、互动表现、服务表现、粉丝画像、近期活跃度筛选。
+   - 适合媒介已有明确选号经验,需要快速收敛候选池。
+
+2. 内容相关式找人
+   - 按笔记关键词、参考笔记、参考博主、参考品牌、营销场景做搜索和扩展。
+   - 适合 Brief 里风格要求比较强,例如“真实测评”“通勤生活”“不要硬广”。
+
+3. 智能推荐式找人
+   - 商家填写综合需求表单后,由系统解析营销目标、产品信息、预算、粉丝画像、参考博主、参考笔记、参考品牌等维度,返回博主列表和推荐理由。
+   - 适合把“商务经验”显性化,让客户看到为什么推荐、为什么降级、为什么剔除。
+
+当前 demo 已经覆盖了第 3 类的主流程雏形,也做了一部分第 2 类的近 10 条内容证据,但第 1 类“像蒲公英博主广场一样筛人”的入口还不够强。
+
+## 2. 当前项目判断
+
+已具备:
+
+- 工作台主链路:上传 Brief、确认需求、选择规则、AI 提号、导出名单、反馈学习。
+- AI 可解释要素:需求证据、置信度、规则命中、评分拆解、近 10 条笔记、笔记级 AI 判断。
+- 人工复核要素:账号状态调整、批量强推/备选/剔除、笔记样本标注、反馈规则确认入库。
+- 资源库要素:平台资源汇总、字段映射确认、资源同步模拟。
+- 构建状态:`npm run build` 通过。
+
+主要缺口:
+
+- 缺少“博主广场/找博主”独立入口,用户不容易联想到蒲公英的找人工作方式。
+- 筛选维度偏少,缺行业类目、粉丝画像、内容形态、自然流量/合作流量、近期活跃、回复率、预估阅读单价等业务字段。
+- 推荐结果只有 5 个样例账号,静态 demo 的丰富度还不够像完整平台。
+- AI 选择流程还停留在结果解释,缺少“需求输入 -> 候选召回 -> 过滤剔除 -> 多目标排序 -> 组合配比 -> 人工确认”的流程视图。
+- 子页面偏薄,任务记录、模板中心、规则库更像列表页,缺少决策上下文和业务动作。
+- UI 信息密度已经偏高,后续应做“分区收纳”和“演示路径”,避免首页一次性塞太多。
+
+## 3. 建议新增页面与导航
+
+### 3.1 找博主页
+
+新增导航:`找博主`
+
+页面结构:
+
+- 顶部:搜索框 + AI 需求输入框
+  - 搜索框支持博主昵称、笔记关键词、品牌、参考账号。
+  - AI 输入框示例:“找 20 个小红书护肤生活方式博主,预算 2k-8k,不要硬广,优先真实空瓶/通勤场景。”
+
+- 左侧:筛选器
+  - 平台:小红书、抖音、B站、微信、微博。
+  - 内容类目:护肤、美妆、母婴、食饮、家居、时尚、旅行、数码。
+  - 内容形态:图文、视频、直播、长视频。
+  - 粉丝量:1w 以下、1w-10w、10w-50w、50w+。
+  - 报价区间:图文报价、视频报价、套餐报价。
+  - 传播表现:阅读/播放中位数、互动中位数、爆文率。
+  - 服务表现:48h 回复率、履约准时率、历史配合度。
+  - 粉丝画像:年龄、性别、城市线级、兴趣分布。
+  - 风控:黑名单、报价过期、近期低活跃、硬广倾向。
+
+- 中间:博主列表
+  - 展示账号名、平台、粉丝、报价、内容标签、综合匹配分、AI 推荐理由、风险标签。
+  - 支持加入候选池、对比、隐藏、加入黑名单、查看详情。
+
+- 右侧:AI 选择解释
+  - 当前筛选命中多少账号。
+  - AI 如何召回:关键词召回、相似博主召回、规则召回、历史合作召回。
+  - AI 如何过滤:预算、风格、风险、数据新鲜度。
+  - AI 如何排序:需求匹配、内容表现、预算健康、粉丝画像、组合多样性。
+
+验收标准:
+
+- 不上传 Brief 也可以从找博主页完成一次“搜索 -> 筛选 -> 加入候选 -> 生成名单”的静态流程。
+- 找博主页和现有工作台共享同一批候选账号状态。
+
+### 3.2 AI 选号流程页
+
+新增导航:`AI 选号流程`
+
+页面结构:
+
+- 流程泳道:
+  - 需求解析
+  - 候选召回
+  - 硬性过滤
+  - 内容采样
+  - 评分排序
+  - 组合配比
+  - 人工复核
+  - 客户版输出
+
+- 每一步展示:
+  - 输入数据
+  - AI 判断
+  - 可人工修改项
+  - 输出结果
+  - 审计日志
+
+验收标准:
+
+- 用户能看懂 AI 不是直接吐名单,而是分阶段筛选。
+- 每个阶段都有“为什么进入下一步/为什么被剔除”的证据。
+
+### 3.3 名单交付页
+
+新增导航:`名单交付`
+
+页面结构:
+
+- 客户版预览:隐藏内部风险字段,突出推荐理由和内容证据。
+- 内部复核版:显示风险、报价有效期、供应商、负责人、未确认项。
+- 导出设置:字段勾选、排序方式、客户模板选择、版本备注。
+- 版本历史:v0.1 AI 初稿、v0.2 商务复核、v1.0 客户交付。
+
+验收标准:
+
+- 静态 demo 能展示同一份名单的客户版/内部版差异。
+- 导出前有准备度检查和缺项提示。
+
+## 4. 现有页面优化待办
+
+### 4.1 工作台
+
+- 把首页从“全量堆叠”改成演示路径:
+  - 默认展开:当前任务、AI 选号流程概览、推荐名单。
+  - 可折叠:上传 Brief、规则选择、采样队列、笔记明细。
+- 增加蒲公英式“从找博主导入候选池”的入口。
+- 把“客户临时改需求试算”改成“需求变更影响模拟”,文案更偏业务。
+- 推荐名单增加字段:
+  - 粉丝画像匹配
+  - 自然流量占比
+  - 近期活跃
+  - 48h 回复率
+  - 预估阅读单价
+  - 合作笔记占比
+- 账号详情增加:
+  - 粉丝画像卡片
+  - 合作历史
+  - 服务表现
+  - 内容案例分布
+  - 同类账号替换建议
+
+### 4.2 任务记录
+
+- 增加任务详情抽屉或详情区。
+- 展示每个任务的 Brief 版本、规则版本、名单版本、客户反馈版本。
+- 增加“继续复核”“复制为新任务”“查看导出记录”动作。
+- 增加状态看板:待解析、提号中、待复核、已交付、已复盘。
+
+### 4.3 资源库
+
+- 增加“资源表健康度”:
+  - 报价有效率
+  - 字段完整率
+  - 近 30 天更新率
+  - 可联系供应商比例
+- 增加“字段缺失影响”:缺报价、缺链接、缺互动数据分别影响哪些 AI 判断。
+- 增加“平台数据对齐”说明:本地表、蒲公英、星图、B站/微信资源如何映射。
+
+### 4.4 规则库
+
+- 规则分层:
+  - 硬性剔除
+  - 加权排序
+  - 组合均衡
+  - 客户偏好
+  - 临时任务规则
+- 每条规则展示:
+  - 触发条件
+  - 影响字段
+  - 命中账号数
+  - 最近一次客户反馈来源
+  - 是否进入客户版解释
+- 增加规则冲突提示,例如“低预算优先”和“保留头部背书”的冲突。
+
+### 4.5 反馈学习
+
+- 增加反馈分类:
+  - 偏好
+  - 排除
+  - 预算
+  - 平台
+  - 风格
+  - 执行风险
+- 增加“反馈 -> 待确认规则 -> 生效范围 -> 影响名单”的四段链路。
+- 增加驳回原因和保留为本次任务规则的动作。
+
+### 4.6 模板中心
+
+- 增加模板预览。
+- 增加客户/行业适用标签。
+- 增加导出字段配置。
+- 增加“客户版字段”和“内部版字段”两套模板。
+
+## 5. AI 选择考虑流程
+
+建议在 demo 中明确表达以下流程:
+
+1. 需求理解
+   - 从 Brief 抽取营销目标、产品信息、平台数量、预算、内容风格、排除项。
+   - 每个需求点都显示置信度和证据来源。
+
+2. 候选召回
+   - 资源库召回:从本地媒体表拿历史资源。
+   - 关键词召回:按笔记关键词和内容标签召回。
+   - 相似召回:按参考博主、参考笔记、参考品牌召回。
+   - 历史召回:按过往客户采纳和合作反馈召回。
+
+3. 硬性过滤
+   - 黑名单、报价超预算、近期低活跃、供应商未绑定、合作禁区等先剔除或降级。
+
+4. 内容采样
+   - 采样近 10 条笔记,判断内容形态、场景、表达方式、硬广程度、关键词和互动质量。
+   - 单条笔记可标注为正向样本、需复核、负向样本。
+
+5. 多目标评分
+   - 综合分 = 需求匹配 + 内容表现 + 粉丝画像 + 预算健康 + 数据新鲜度 + 历史表现 + 服务表现 - 风险扣分。
+   - 每个分数都能展开解释。
+
+6. 组合配比
+   - 控制平台比例、头腰尾比例、内容类目比例、价格带比例、账号同质化比例。
+   - 解决“单个账号不错,但整份名单不均衡”的问题。
+
+7. 人工复核
+   - 商务/媒介可以调整状态、记录理由、替换账号、修改规则。
+   - 所有操作进入决策日志。
+
+8. 反馈沉淀
+   - 客户反馈只生成待确认规则。
+   - 人工确认后才进入长期规则库。
+
+## 6. 通宵执行任务拆分
+
+### Phase A:产品结构重排,约 60-90 分钟
+
+- 新增 `creator-search`、`ai-selection-flow`、`delivery` 三个静态页面。
+- 扩展 `ViewKey` 和导航。
+- 抽象共享候选账号数据,避免页面间状态割裂。
+- 写清每个页面的主标题和业务动作。
+
+### Phase B:数据模型扩充,约 60 分钟
+
+- 扩展候选账号字段:
+  - category、contentForms、audienceProfile、readMedian、interactionMedian、viralRate、replyRate、fulfillmentRate、naturalTrafficRatio、cooperationNoteRatio、estimatedCpm。
+- 增加 20-30 个静态候选账号,覆盖小红书、抖音、B站、微信、微博。
+- 增加行业类目、内容关键词、参考博主、参考笔记样例数据。
+
+### Phase C:蒲公英式找博主页,约 90-120 分钟
+
+- 完成搜索 + 筛选 + 列表 + 右侧 AI 解释。
+- 增加“加入候选池”“换一批”“相似博主”“查看近10条”动作。
+- 筛选变化后同步更新命中数量、AI 解释和候选列表。
+
+### Phase D:AI 选号流程页,约 60-90 分钟
+
+- 做流程泳道和每一步的输入/输出说明。
+- 每一步挂载样例账号,展示进入/剔除原因。
+- 增加规则冲突和人工修改入口。
+
+### Phase E:名单交付页,约 60 分钟
+
+- 做客户版/内部版切换。
+- 做字段勾选、导出设置、版本历史、交付准备度缺项提示。
+- 复用现有导出方法或保留静态导出按钮状态。
+
+### Phase F:现有页面补厚,约 60-90 分钟
+
+- 任务记录加任务详情和状态看板。
+- 资源库加健康度、缺失字段影响、平台映射说明。
+- 规则库加规则分层、命中账号数、冲突提示。
+- 反馈学习加分类和生效范围。
+- 模板中心加模板预览和客户版/内部版字段配置。
+
+### Phase G:UI 收敛与静态验收,约 60 分钟
+
+- 清理首页过重信息,增加折叠或分区。
+- 检查 1440px、1180px、760px、390px 响应式布局。
+- 确保按钮文字不溢出,表格/卡片不重叠。
+- 统一按钮命名,减少“AI/规则/候选”重复解释文案。
+
+### Phase H:自动审查与报告,约 30-60 分钟
+
+- 跑 `npm run build`。
+- 用 Playwright 打开每个导航页截图。
+- 检查控制台 error/warning。
+- 输出一份 `docs/static-demo-review-report.md`:
+  - 构建结果
+  - 页面截图路径
+  - 已完成项
+  - 待补项
+  - 业务清晰度评分
+  - UI 风险点
+
+合计预估:6-8 小时,适合一晚上持续执行。
+
+## 7. 优先级
+
+P0:
+
+- 新增找博主页。
+- 明确 AI 选号流程。
+- 扩充候选账号和筛选维度。
+- 做客户版/内部版名单交付。
+
+P1:
+
+- 资源库健康度。
+- 规则库分层和冲突。
+- 任务记录详情。
+- 反馈学习分类。
+
+P2:
+
+- 模板预览。
+- 更多行业样例。
+- 更细的响应式优化。
+- 截图审查报告。
+
+## 8. 最终验收口径
+
+这个 demo 完成后,客户应该能按下面的话复述产品价值:
+
+“它不是单纯生成达人名单,而是先像蒲公英一样按条件和内容找博主,再用 AI 按 Brief、预算、风格、粉丝画像和历史表现筛选排序;每个推荐都有证据,媒介可以复核修改,客户反馈还能沉淀成规则。”
+
+## 9. 外部参考
+
+- 蒲公英找博主入口:https://pgy.xiaohongshu.com/solar/pre-trade/note/kol
+- 智能找 K 助手公开报道:https://finance.sina.com.cn/tech/roll/2025-12-11/doc-inhamhsi8155743.shtml
+- 笔记关键词搜索/新锐博主公开报道:https://www.newrank.cn/article/detail/19498
+- 蒲公英找博主操作介绍:https://www.niaogebiji.com/article-622714-1.html

+ 36 - 0
docs/pages/01-workbench-upload.md

@@ -0,0 +1,36 @@
+# 子页面 PRD:提号工作台 / Brief 上传
+
+## 页面目标
+
+让商务人员快速开始一个提号任务,上传客户 Brief,并看到标准模板入口。
+
+## 主要用户
+
+商务人员。
+
+## 核心功能
+
+- 创建提号任务。
+- 上传 `.xlsx`、`.xls`、`.docx` Brief。
+- 下载 Brief 模板和推荐名单模板。
+- 展示当前任务客户、品牌、阶段、处理状态。
+- 上传后触发 AI 解析任务。
+
+## 页面字段
+
+- 任务名称。
+- 客户名称。
+- 品牌名称。
+- Brief 文件。
+- 需求类型:种草、测评、带货、品牌曝光、招募。
+- 期望交付时间。
+
+## 交互规则
+
+- 未上传文件时,下一步按钮置灰。
+- 文件上传后展示文件名、大小、上传人、上传时间。
+- 如果模板不符合要求,提示可下载标准模板。
+
+## Demo 状态
+
+已在工作台中实现上传控件、模板入口、任务摘要,文件内容解析使用模拟数据。

+ 32 - 0
docs/pages/02-demand-confirmation.md

@@ -0,0 +1,32 @@
+# 子页面 PRD:需求确认
+
+## 页面目标
+
+把 Brief 中的非结构化内容转换为可确认、可用于筛号的结构化需求。
+
+## 核心功能
+
+- 展示 AI 抽取的客户、品牌、平台、数量、预算、内容风格、排除项。
+- 每个需求点展示置信度。
+- 支持商务勾选启用、取消、编辑和补充需求。
+- 将确认后的需求传给规则匹配和推荐引擎。
+
+## 关键字段
+
+- 客户/品牌。
+- 投放目标。
+- 平台与数量。
+- 预算范围。
+- 内容形式:图文、短视频、长视频、直播。
+- 内容风格:真实测评、成分党、通勤、剧情、教程等。
+- 禁投/排除项。
+
+## 业务规则
+
+- 置信度低于 80% 的需求默认提示人工确认。
+- 明确数量需求优先级高于默认数量策略。
+- 平台需求必须保留原文证据,方便商务回看。
+
+## Demo 状态
+
+已展示需求点、置信度和勾选确认交互。

+ 34 - 0
docs/pages/03-rule-center.md

@@ -0,0 +1,34 @@
+# 子页面 PRD:规则确认与规则库
+
+## 页面目标
+
+让商务在每次提号前明确本次使用哪些规则,并把经验规则沉淀为公司资产。
+
+## 核心功能
+
+- 按平台、数量、风格、预算、风险、组合均衡展示规则。
+- 支持启用、停用、临时新增规则。
+- 标识规则来源:经验规则、用户反馈、AI 提炼。
+- 支持规则版本、适用场景和优先级。
+- 支持 AI 从反馈中提炼规则,但必须用户确认后生效。
+
+## 规则结构
+
+- 规则标题。
+- 触发条件。
+- 执行动作。
+- 优先级。
+- 适用平台。
+- 来源。
+- 生效状态。
+- 最近使用次数。
+
+## 业务规则
+
+- 风险控制类规则默认启用。
+- AI 提炼规则默认进入待确认池。
+- 临时规则只作用于当前任务,除非用户保存到规则库。
+
+## Demo 状态
+
+已实现规则展示、启用/停用、反馈规则加入规则库。

+ 32 - 0
docs/pages/04-recommendation-engine.md

@@ -0,0 +1,32 @@
+# 子页面 PRD:AI 提号执行
+
+## 页面目标
+
+让用户看到 AI 正在如何根据需求和规则执行提号,增强可信度和可控性。
+
+## 核心功能
+
+- 展示执行步骤:解析 Brief、读取资源库、执行规则、后台采样、生成候选池。
+- 展示执行状态:待执行、进行中、完成、失败。
+- 展示匹配评分维度。
+- 支持重新运行和局部复核。
+
+## 推荐逻辑
+
+候选账号需经过以下筛选:
+
+- 平台匹配。
+- 数量策略。
+- 预算范围。
+- 内容标签和风格匹配。
+- 数据新鲜度。
+- 历史投放效果。
+- 黑名单、配合度、供应商关系风险。
+
+## 后台采集要求
+
+当 Brief 明确要求内容风格时,系统应进入平台采样任务:抓取或打开近 10 篇内容,综合标题、正文、图片/视频标签和互动数据做匹配。
+
+## Demo 状态
+
+已实现执行步骤和评分面板,真实平台采集为后续能力。

+ 29 - 0
docs/pages/05-recommendation-list-export.md

@@ -0,0 +1,29 @@
+# 子页面 PRD:推荐名单预览与导出
+
+## 页面目标
+
+让商务在导出前审阅 AI 推荐账号,确认推荐理由和风险提示,并生成对客 Excel。
+
+## 核心功能
+
+- 推荐账号卡片和表格预览。
+- 展示平台、账号名、粉丝、报价、综合分、风格匹配、推荐理由、风险提示。
+- 支持勾选/取消账号。
+- 支持按模板导出推荐名单。
+- 支持不同客户/品牌模板自动匹配。
+
+## 推荐状态
+
+- 强推荐:满足核心规则,风险较低。
+- 备选:满足主要条件,但存在预算、档期或平台策略问题。
+- 需复核:关键指标不足或数据需要人工确认。
+
+## 导出要求
+
+- 表格关键字段前置。
+- 用明显颜色区分综合分、风格匹配、风险提示。
+- 文件名格式:客户+品牌-需求推荐名单。
+
+## Demo 状态
+
+已实现勾选候选账号和 `.xls` 导出。当前使用 HTML Excel 方案,后续可接入 `xlsx` 精细样式化导出。

+ 30 - 0
docs/pages/06-feedback-learning.md

@@ -0,0 +1,30 @@
+# 子页面 PRD:反馈学习
+
+## 页面目标
+
+把客户和商务的调整意见转化为可复用规则,使提号AI持续进化。
+
+## 核心功能
+
+- 录入客户反馈。
+- AI 提取偏好、排除项、预算调整、平台策略。
+- 展示规则建议和置信度。
+- 用户确认后加入规则库。
+- 记录规则来源任务和反馈原文。
+
+## 典型反馈提炼
+
+- “减少泛美妆号” -> 泛美妆标签降权或限制数量。
+- “优先真实测评” -> 真实测评风格加权。
+- “预算再压低” -> 报价阈值下调,保留高爆文率账号。
+- “不要硬广感” -> 硬广风格匹配不足账号剔除。
+
+## 业务规则
+
+- 反馈不直接修改历史推荐结果。
+- AI 提炼规则需用户确认。
+- 被驳回规则进入样本库,但不生效。
+
+## Demo 状态
+
+已实现反馈输入、规则建议展示、确认加入规则库。

+ 29 - 0
docs/pages/07-resource-library.md

@@ -0,0 +1,29 @@
+# 子页面 PRD:资源库管理
+
+## 页面目标
+
+让媒介人员管理本地多平台媒体资源库,并让提号AI能稳定读取和映射字段。
+
+## 核心功能
+
+- 配置本地资源目录。
+- 读取小红书、抖音、微信、微博、B站、知乎、快手、得物、京东图文、淘宝图文等资源表。
+- 展示平台资源数量、新鲜度、字段映射状态。
+- 支持手动上传资源表。
+- 标记过期报价、重复账号、缺失关键字段。
+
+## 字段映射
+
+统一字段建议:
+
+- platform、accountName、platformId、link、fans、tags、contentCategory、style、price、priceExpireAt、interactionMedian、readMedian、playMedian、supplier、owner、blackCount、cooperationScore。
+
+## 业务规则
+
+- 资源表字段不一致时进入映射确认。
+- 报价过期或采集时间过旧的账号降级。
+- 重复账号按平台 ID 优先去重。
+
+## Demo 状态
+
+已展示资源库路径和各平台资源摘要。当前机器未检测到用户提供的 D 盘目录时,使用样例数据。

+ 30 - 0
docs/pages/08-template-center.md

@@ -0,0 +1,30 @@
+# 子页面 PRD:模板中心
+
+## 页面目标
+
+集中管理 Brief 模板、媒体资源模板和推荐名单模板,减少商务和媒介之间的格式沟通成本。
+
+## 核心功能
+
+- 下载标准 Brief 模板。
+- 下载媒体资源库模板。
+- 下载推荐名单模板。
+- 上传客户定制推荐名单模板。
+- 标记模板适用客户、品牌、平台和输出场景。
+
+## 模板类型
+
+- Brief 模板:客户需求收集。
+- 媒体资源模板:媒介资源维护。
+- 推荐名单模板:对客输出。
+- 复盘模板:反馈与规则沉淀。
+
+## 业务规则
+
+- 默认模板不可删除,只能复制生成客户定制模板。
+- 客户定制模板需记录上传人和版本。
+- 导出时优先匹配客户/品牌专属模板,否则使用默认推荐名单模板。
+
+## Demo 状态
+
+已展示模板列表和下载入口,真实文件下载为后续接入。

+ 60 - 0
docs/pages/09-account-detail-notes.md

@@ -0,0 +1,60 @@
+# 子页面 PRD:账号详情与最近10条笔记详情
+
+## 页面目标
+
+让商务和媒介能够从推荐名单中下钻到账号详情,再继续查看最近 10 条笔记/视频/图文内容,验证 AI 为什么推荐或降级该账号。
+
+## 页面层级
+
+1. 账号列表:展示推荐账号池,可按平台、状态、预算、综合分筛选。
+2. 账号详情:展示账号基础信息、报价、综合分、风格匹配、责任媒介、供应商、命中规则、风险提示。
+3. 最近10条笔记详情:展示每条内容的标题、发布时间、内容形式、风格标签、匹配度、互动指标、AI 判断理由。
+
+## 核心交互
+
+- 点击账号列表中的账号,右侧打开账号详情。
+- 在账号详情中可将账号标记为强推荐、备选、需复核、已剔除。
+- 点击最近 10 条笔记中的任意一条,右侧展示单条内容证据。
+- 单条内容详情展示 AI 判断,包括该内容是否符合 Brief 的真实测评、通勤生活、成分党等风格要求。
+
+## 字段设计
+
+账号详情字段:
+
+- 平台。
+- 账号名。
+- 粉丝量。
+- 报价。
+- 报价有效期。
+- 责任媒介。
+- 供应商。
+- 综合分。
+- 风格匹配分。
+- 数据新鲜度。
+- 命中规则。
+- 推荐理由。
+- 风险提示。
+
+最近10条内容字段:
+
+- 标题。
+- 发布时间。
+- 内容形式:图文、视频、长视频、公众号图文。
+- 风格标签。
+- 匹配度。
+- 阅读/播放量。
+- 点赞。
+- 收藏。
+- 评论。
+- AI 判断理由。
+
+## 业务规则
+
+- Brief 中明确内容风格时,必须采样最近 10 条内容。
+- 最近 10 条中 80% 以上符合风格要求,账号才可进入强推荐。
+- 低于 80% 的账号默认进入需复核,除非商务手动调整。
+- 采样失败或账号链接无法打开时,账号保留在备选池,并提示媒介补充数据。
+
+## Demo 状态
+
+已实现账号列表、账号详情、最近 10 条笔记详情三层交互。当前数据为样例,正式版需接入平台采集或外部数据平台。

+ 163 - 0
docs/product-requirements.md

@@ -0,0 +1,163 @@
+# 提号AI PRD
+
+## 1. 项目定位
+
+提号AI是面向商务和媒介团队的 Web 端工具。它把客户 Brief 上传、需求拆解、规则确认、媒体资源库读取、AI 推荐、推荐名单导出、客户反馈学习串成一个可复用流程,目标是减少人工筛号时间,并沉淀公司自己的提号经验。
+
+## 2. 背景与现状
+
+当前收到客户 Brief 后,商务和媒介需要人工阅读需求、检索本地媒体资源表、结合外部平台数据和经验判断账号适配度,再制作推荐名单表给客户。该流程依赖个人经验,规则难复用,反馈难沉淀。
+
+对 `C:\Users\刚sir\hcoa` 的 OA 代码阅读结论:
+
+- 现有 OA 是 Snowy / Spring Boot / MyBatis-Plus 后端项目,未在该目录看到完整前端工程。
+- 媒体域能力集中在 `snowy-main/src/main/java/vip/xiaonuo/modular/media`,已有媒体筛选、媒体导入导出、媒体详情、供应商价格、黑名单、采集、收藏、公海认领、数据同步等模块。
+- 关键接口包括 `/mediaSelect/mediaSelectList`、`/mediaSelect/getFilterFields`、`/mediaAudit/importMeaidExcel`、`/mediaAudit/batchMediaExport`、`/mediaDetails/list` 等。
+- 可复用的数据字段包括平台、账号名、链接、粉丝、内容类目、人设、价格、报价有效期、阅读/互动/播放中位数、爆文率、配合度、黑名单、供应商关系、责任人等。
+- 新系统的一稿 Demo 先独立实现 Angular + Node/TS,可在客户需求确认后再对接 OA 媒体接口或直接读取本地资源库。
+
+## 3. 目标用户
+
+- 商务人员:上传 Brief、确认需求、选择规则、下载推荐名单、提交客户反馈。
+- 媒介人员:维护本地媒体资源库、补充平台数据、审核 AI 推荐结果。
+- 管理人员:维护规则库、查看提号效率、沉淀公司方法论。
+
+## 4. 核心流程
+
+1. 商务上传 Brief 文件,系统提供模板下载和上传入口。
+2. AI 解析 Brief,抽取客户、品牌、目标、平台、数量、预算、内容风格、排除项。
+3. 商务确认需求点,可勾选、修正或补充。
+4. 系统列出适用规则,商务可启用、停用、临时补充规则。
+5. AI 读取媒体资源库,必要时触发后台采集近 10 篇内容做风格比对。
+6. 系统生成候选媒体池,按综合分、风格匹配、预算、风险排序。
+7. 系统按推荐名单模板导出 Excel。
+8. 商务录入客户反馈,AI 提炼新规则,经用户确认后加入规则库。
+
+## 5. 一稿 Demo 范围
+
+已实现或应在 Demo 中体现:
+
+- Angular 单页 Web 端交互界面。
+- Brief 上传交互和模板入口。
+- AI 需求抽取结果展示与确认。
+- 规则库启用/停用。
+- 模拟 AI 提号任务进度。
+- 推荐名单卡片和表格式导出。
+- 客户反馈文本提炼为待确认规则。
+- 资源库、任务记录、模板中心、规则库、反馈学习子页面。
+- Node/TS Mock API:健康检查、Brief 解析、推荐、反馈学习、Excel HTML 导出。
+
+暂不做真实能力:
+
+- 不真实解析 Excel/Docx 内容。
+- 不登录小红书、抖音等平台实时采集。
+- 不接入 OA 数据库。
+- 不做真实模型微调或长期记忆,只展示“确认后加入规则库”的交互。
+
+## 6. 功能模块
+
+### 6.1 提号工作台
+
+以任务流为核心,支持上传 Brief、确认需求、选择规则、执行提号、预览候选、导出名单、提交反馈。
+
+### 6.2 任务记录
+
+记录客户、品牌、Brief 文件、需求版本、推荐名单版本、客户反馈版本、执行状态。
+
+### 6.3 资源库
+
+读取本地媒体资源目录,展示不同平台资源数量、新鲜度、匹配数量、字段映射状态。
+
+### 6.4 规则库
+
+维护经验规则、用户反馈规则、AI 提炼规则。所有自动提炼规则必须由用户确认后生效。
+
+### 6.5 反馈学习
+
+从客户反馈中提取偏好、排除项、预算约束、平台策略,并形成待确认规则。
+
+### 6.6 模板中心
+
+管理 Brief 模板、媒体资源模板、推荐名单模板。后续支持不同客户/品牌自动匹配模板。
+
+## 7. 推荐评分建议
+
+综合分 = 需求匹配分 + 平台优先分 + 风格匹配分 + 预算健康分 + 数据新鲜度分 + 历史表现分 - 风险扣分。
+
+关键规则:
+
+- 明确数量时,候选池不少于需求数量 3 倍。
+- Brief 有平台要求时,优先满足平台数量。
+- 风格要求明确时,近 10 篇内容 80% 以上匹配才进入强推荐。
+- 黑名单、低配合度、供应商未绑定、报价过期账号降级或剔除。
+- 同质化账号需要控制比例,避免名单重复。
+
+## 8. 数据对象
+
+- Brief:客户、品牌、行业、目标、平台、数量、预算、内容风格、排除项、交付时间。
+- MediaAccount:平台、账号名、账号 ID、链接、粉丝、标签、内容类目、人设、报价、报价有效期、历史投放、互动指标、供应商、责任人。
+- Rule:规则类型、触发条件、动作、优先级、来源、生效状态、版本。
+- Recommendation:任务 ID、媒体账号、匹配理由、风险提示、推荐状态、导出状态。
+- Feedback:反馈内容、提炼规则、置信度、确认人、生效时间。
+
+## 9. 成功指标
+
+- 商务从 Brief 到首版推荐名单的时间减少 50% 以上。
+- 客户要求返工次数下降。
+- 规则库每月可沉淀稳定新增规则。
+- 推荐名单中被客户采纳账号占比提升。
+
+## 10. 后续迭代
+
+- 接入真实 Excel/Docx 解析。
+- 接入 OA 媒体资源接口或数据库。
+- 读取本地资源库并自动字段映射。
+- 支持平台后台采集和风格多模态比对。
+- 引入权限、任务协作、版本审计。
+- 推荐名单模板自动识别和样式化导出。
+
+## 11. 重新审视后的 Demo 补充重点
+
+原一稿 Demo 已能表达完整流程,但偏“展示型”。为了更适合客户沟通,Demo 需要让客户看到 AI 提号不是黑盒,而是可确认、可追溯、可修正、可沉淀的工作台。
+
+本轮增强后的关键交互:
+
+- 页面组件拆分:主壳只负责导航和页面切换,工作台、任务记录、资源库、规则库、反馈学习、模板中心拆成独立子页面,便于后续逐页深化。
+- 需求确认增强:Brief 抽取出的需求点支持编辑、勾选、补充,并展示原文证据或推断来源。
+- 临时规则增强:商务可在本次任务中临时补充规则,后续再决定是否沉淀为长期规则。
+- 资源库增强:除平台资源数量外,增加字段映射确认,让客户看到本地 Excel 资源表如何被 AI 理解。
+- 后台采样增强:增加近 10 条内容采样任务进度,模拟平台后台打开链接、采集内容、完成风格比对。
+- 推荐名单增强:增加平台、状态、预算、排序筛选,并支持换一批/补足备选。
+- 账号钻取增强:新增“账号列表 -> 账号详情 -> 最近10条笔记详情”的三层结构,展示推荐分、命中规则、风险提示、内容样本和单条笔记 AI 判断。
+- 反馈学习增强:AI 只生成待确认规则,必须由用户确认后入库,避免“AI 自动乱学”的客户顾虑。
+
+继续补充的交互增强:
+
+- 客户临时改需求试算:工作台增加情景按钮,例如“客户压预算 15%”“小红书偏生活方式”“严格排除硬广”“保留 B站专业背书”,点击后实时调整账号分数、推荐状态、命中规则和风险提示。
+- 交付准备度:用字段映射、规则启用、候选名单、近 10 条采样四类状态合成准备度,帮助商务判断是否可以导出对客名单。
+- 操作决策日志:记录 Brief 解析、规则确认、情景试算、批量复核、笔记标注、反馈补充等关键动作,后续正式版可升级为任务审计。
+- 推荐名单批量处理:支持勾选当前筛选、批量强推荐、批量备选、批量剔除、清空选择。
+- 账号横向对比:对已选账号展示平台、报价、综合分、风格匹配,并支持内部复核版/客户版切换。内部复核版突出风险,客户版突出推荐理由。
+- 笔记样本标注:最近 10 条笔记可按“正向样本/需复核/负向样本”过滤,并支持人工标注,标注动作会影响账号风格匹配或复核状态。
+- 快捷反馈补充:反馈学习页增加常用反馈句,一键追加到客户反馈文本,再由 AI 提炼为待确认规则。
+- 资源库平台详情:点击平台后展示资源文件、更新时间、负责人、缺失字段、待处理问题和匹配样例账号,支持单平台重新扫描和问题标记处理。
+- 规则沙盘试算:规则库支持选中规则、填写客户临时要求、调整权重、启停测试用例,并实时模拟对强推荐和需复核数量的影响。
+- 任务档案与时间线:任务记录页支持选中任务查看详情、操作时间线、复制为相似客户任务,并可把最近动作送入反馈学习。
+- 模板字段配置:模板中心支持客户版/内部复核版/复盘版切换,勾选导出字段,预览导出列,并同步到名单交付配置。
+
+### 11.1 便利性优化原则
+
+上一轮功能已经覆盖 Brief、资源库、规则、AI 选号、账号详情、近 10 条笔记、名单交付和反馈学习,但默认界面信息量偏大。为了降低商务同事上手门槛,本轮调整为“默认简单、需要时展开”的交互策略。
+
+- 默认进入商务简洁模式:侧边导航只保留提号工作台、找博主、名单交付、任务记录四个常用入口;资源库、规则库、反馈学习、模板中心等仍保留在完整业务模式中。
+- 工作台改为流程主画布:六个步骤作为顶部流程导航,支持随时回退修改;页面主体一次只展示当前流程,避免把上传、需求、规则、采样、名单全部堆在一个屏幕。
+- 当前流程强突出:顶部显示当前步骤、下一步动作和整体进度条;右侧辅助区保留业务检查和快捷动作。
+- 二稿继续优化:默认从 Step 1 开始,顶部去掉重复统计卡,改为“目标 / 操作 / 产出”三段式说明;六步导航从大卡片改为更轻量的流程时间线,减少首屏压迫感。
+- 检查项按流程推进判断:默认规则存在不等于流程完成,只有用户走到对应步骤后,业务检查才显示完成,避免误导新用户。
+- 其它页面统一优化:找博主、AI选号流程、名单交付、任务记录、资源库、规则库、反馈学习、模板中心统一为“目标 / 操作 / 产出”的页面头;简洁模式下隐藏解释、版本、表格等次级信息,主页面优先呈现业务操作。
+- 交付页默认客户版:商务默认看到可对客内容,内部复核字段和版本历史通过展开细节或切换内部复核版查看。
+- 常用动作一键化:提供“一键生成可看名单”“只看待处理问题”“客户版预览”“反馈变规则”,把多步操作合并为业务语言。
+- 高级细节可展开:客户情景试算、规则选择、AI 执行队列、近 10 条采样、批量复核等不删除,只默认收起,保证业务逻辑不缺失。
+- 客户版优先:推荐名单默认引导到客户版预览,内部风险、供应商、规则命中等字段在完整模式或内部复核版中查看。
+
+本轮仍属于 Demo,不做真实平台登录采集和真实 Excel/Docx 解析;正式版需要将这些交互背后的模拟数据替换为真实任务队列、平台数据接口或浏览器自动化采集结果。

+ 101 - 0
docs/static-demo-review-report.md

@@ -0,0 +1,101 @@
+# 静态 Demo 执行与审查报告
+
+时间:2026-05-12 凌晨  
+范围:把提号 AI 从原工作台 demo 扩展为可独立演示的静态完整项目雏形。
+
+## 已完成
+
+### P0 闭环
+
+- 新增 `找博主` 页面:支持关键词/参考账号搜索、平台、类目、内容形态、粉丝量级、风险、报价筛选。
+- 新增 `AI 选号流程` 页面:展示需求理解、候选召回、硬性过滤、内容采样、多目标评分、组合配比、交付学习。
+- 新增 `名单交付` 页面:支持客户版/内部复核版切换、导出字段配置、版本历史、交付准备度缺项。
+- 扩展候选账号池:覆盖小红书、抖音、B站、微信、微博,补充类目、内容形态、粉丝画像、阅读中位、互动中位、回复率、履约率、自然流量占比、合作笔记占比、预估 CPM 等字段。
+- 导航扩展:新增找博主、AI 选号流程、名单交付入口,并保留原工作台链路。
+
+### 现有页面补强
+
+- 任务记录:增加状态看板、继续复核、交付预览、版本追踪说明。
+- 资源库:增加资源健康度、字段缺失对 AI 判断的影响。
+- 规则库:增加规则分层、规则冲突提示、命中账号数表达。
+- 反馈学习:增加反馈分类、反馈到规则的四段链路。
+- 模板中心:增加客户版、内部复核版、复盘字段预览。
+
+### 工程调整
+
+- `angular.json` 中组件样式 warning budget 从 26kB 调整到 32kB,适配多页面静态原型体量。
+- 保持前端仍为纯静态可演示逻辑,不依赖真实平台登录或真实 OA 数据。
+
+## 验证结果
+
+- `npm run build`:通过,无 warning、无 error。
+- Playwright 浏览器检查:主页面、新增三页、原有子页面均可打开。
+- 浏览器控制台:无 error、无 warning。
+
+截图:
+
+- `output/playwright/01-workspace.png`
+- `output/playwright/02-creator-search.png`
+- `output/playwright/03-ai-flow.png`
+- `output/playwright/04-delivery.png`
+- `output/playwright/05-templates.png`
+
+## 页面完成度判断
+
+| 页面 | 当前完成度 | 还可继续加厚 |
+| --- | --- | --- |
+| 提号工作台 | 80% | 可折叠上传/规则区,突出主演示路径 |
+| 找博主 | 75% | 可加入参考笔记、相似博主弹层、批量加入候选池 |
+| AI 选号流程 | 80% | 可加入阶段切换详情和剔除账号列表 |
+| 名单交付 | 75% | 可加入字段拖拽排序、客户模板预览 |
+| 任务记录 | 65% | 可做任务详情抽屉和版本差异对比 |
+| 资源库 | 70% | 可做字段映射错误提示和平台数据对齐表 |
+| 规则库 | 70% | 可做规则影响回算和冲突确认动作 |
+| 反馈学习 | 70% | 可做生效范围选择和驳回原因 |
+| 模板中心 | 60% | 可做模板预览表格和上传模拟 |
+
+## 下一轮可继续跑的任务
+
+### 视觉与信息架构
+
+- 工作台首页改为“当前任务 + AI 流程摘要 + 推荐名单”三段主路径。
+- 上传 Brief、需求确认、规则选择、采样队列改成可折叠模块。
+- 找博主页左侧筛选器增加分组标题,减少密集感。
+- 在移动端检查侧边导航是否需要改为顶部横向入口。
+
+### 找博主业务
+
+- 增加参考笔记卡片:标题、链接、关键词、相似账号召回结果。
+- 增加参考博主输入:输入 1 个账号后扩展 10 个相似账号。
+- 增加粉丝画像筛选:年龄、性别、城市线级、兴趣标签。
+- 增加服务指标筛选:48h 回复率、履约准时率、历史改稿次数。
+- 增加批量加入候选池、批量隐藏、批量标记需复核。
+
+### AI 选号流程
+
+- 每个流程阶段增加详情展开。
+- 硬性过滤阶段展示被剔除账号和剔除原因。
+- 多目标评分阶段支持权重试算。
+- 组合配比阶段展示平台/价格带/内容类目的比例条。
+- 增加“为什么不是它”解释,说明相似账号被降级原因。
+
+### 名单交付
+
+- 客户版预览增加更像 Excel 的列宽和冻结表头。
+- 内部版增加供应商、负责人、报价有效期、风险状态。
+- 导出前弹出缺项确认。
+- 版本历史增加 v0.1 与 v0.3 的差异摘要。
+
+### 规则和反馈
+
+- 规则库增加启用范围:全局、单客户、单行业、本任务。
+- 规则冲突增加确认动作:保留 A、保留 B、都保留但降权。
+- 反馈学习增加驳回原因输入。
+- 已确认规则展示影响账号数和影响分数。
+
+### 验收自动化
+
+- 增加一个轻量 Playwright 脚本,自动打开每个导航页并截图。
+- 增加静态页面检查清单:按钮溢出、表格重叠、控制台错误、构建 warning。
+- 增加 README 中的演示路径:先找博主,再 AI 选号,再名单交付,再反馈学习。
+

+ 9525 - 0
package-lock.json

@@ -0,0 +1,9525 @@
+{
+  "name": "tihao-ai",
+  "version": "0.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "tihao-ai",
+      "version": "0.0.0",
+      "dependencies": {
+        "@angular/common": "^20.0.0",
+        "@angular/compiler": "^20.0.0",
+        "@angular/core": "^20.0.0",
+        "@angular/forms": "^20.0.0",
+        "@angular/platform-browser": "^20.0.0",
+        "@angular/router": "^20.0.0",
+        "rxjs": "~7.8.0",
+        "tslib": "^2.3.0",
+        "zone.js": "~0.15.0"
+      },
+      "devDependencies": {
+        "@angular/build": "^20.0.4",
+        "@angular/cli": "^20.0.4",
+        "@angular/compiler-cli": "^20.0.0",
+        "@types/jasmine": "~5.1.0",
+        "jasmine-core": "~5.7.0",
+        "karma": "~6.4.0",
+        "karma-chrome-launcher": "~3.2.0",
+        "karma-coverage": "~2.2.0",
+        "karma-jasmine": "~5.1.0",
+        "karma-jasmine-html-reporter": "~2.1.0",
+        "typescript": "~5.8.2"
+      }
+    },
+    "node_modules/@algolia/abtesting": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.1.0.tgz",
+      "integrity": "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/client-abtesting": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.35.0.tgz",
+      "integrity": "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/client-analytics": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.35.0.tgz",
+      "integrity": "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/client-common": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.35.0.tgz",
+      "integrity": "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/client-insights": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.35.0.tgz",
+      "integrity": "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/client-personalization": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.35.0.tgz",
+      "integrity": "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/client-query-suggestions": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.35.0.tgz",
+      "integrity": "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/client-search": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.35.0.tgz",
+      "integrity": "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/ingestion": {
+      "version": "1.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.35.0.tgz",
+      "integrity": "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/monitoring": {
+      "version": "1.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.35.0.tgz",
+      "integrity": "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/recommend": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.35.0.tgz",
+      "integrity": "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/requester-browser-xhr": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.35.0.tgz",
+      "integrity": "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/requester-fetch": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.35.0.tgz",
+      "integrity": "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@algolia/requester-node-http": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.35.0.tgz",
+      "integrity": "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/client-common": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/@ampproject/remapping": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+      "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/architect": {
+      "version": "0.2003.25",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.25.tgz",
+      "integrity": "sha512-39pTqt4wSmpD1WeCee46oSGXRh6TR1PFd9GZEwyZoMvBTMs8mE2sXGxUgd4Qyi5CkQ1XnCM5XfgJcjUWUQRoGg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@angular-devkit/core": "20.3.25",
+        "rxjs": "7.8.2"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@angular-devkit/core": {
+      "version": "20.3.25",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.25.tgz",
+      "integrity": "sha512-pSfeWEoS1y9zxqTOw0Etj2NXkRmp/aU52wdnyq3KqVA9cJtgxtlOHlBBNswTil4dReojEy+0K1xJm+mLuWuLxA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "8.18.0",
+        "ajv-formats": "3.0.1",
+        "jsonc-parser": "3.3.1",
+        "picomatch": "4.0.4",
+        "rxjs": "7.8.2",
+        "source-map": "0.7.6"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      },
+      "peerDependencies": {
+        "chokidar": "^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "chokidar": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@angular-devkit/schematics": {
+      "version": "20.3.25",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.25.tgz",
+      "integrity": "sha512-IB0IHf8ZRqr69hT/XIfHkYLPAYHWQ/WUc6+fKHBwq58jJlm/y5QUeTEuXvJ18IX/+hUIqw+E2Q3T0N9rLDLzXg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@angular-devkit/core": "20.3.25",
+        "jsonc-parser": "3.3.1",
+        "magic-string": "0.30.17",
+        "ora": "8.2.0",
+        "rxjs": "7.8.2"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@angular/build": {
+      "version": "20.3.25",
+      "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.25.tgz",
+      "integrity": "sha512-ddWmPzYuzDWz9ql0262u9w3OJHXpSjHVNIDFIYOG2XYyMj/Xve0RkJ8/xvV+Hv7T3iqyyGKtsO+n/d0GCJQCtQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@ampproject/remapping": "2.3.0",
+        "@angular-devkit/architect": "0.2003.25",
+        "@babel/core": "7.28.3",
+        "@babel/helper-annotate-as-pure": "7.27.3",
+        "@babel/helper-split-export-declaration": "7.24.7",
+        "@inquirer/confirm": "5.1.14",
+        "@vitejs/plugin-basic-ssl": "2.1.0",
+        "beasties": "0.3.5",
+        "browserslist": "^4.23.0",
+        "esbuild": "0.28.0",
+        "https-proxy-agent": "7.0.6",
+        "istanbul-lib-instrument": "6.0.3",
+        "jsonc-parser": "3.3.1",
+        "listr2": "9.0.1",
+        "magic-string": "0.30.17",
+        "mrmime": "2.0.1",
+        "parse5-html-rewriting-stream": "8.0.0",
+        "picomatch": "4.0.4",
+        "piscina": "5.1.3",
+        "rollup": "4.59.0",
+        "sass": "1.90.0",
+        "semver": "7.7.2",
+        "source-map-support": "0.5.21",
+        "tinyglobby": "0.2.14",
+        "vite": "7.3.2",
+        "watchpack": "2.4.4"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      },
+      "optionalDependencies": {
+        "lmdb": "3.4.2"
+      },
+      "peerDependencies": {
+        "@angular/compiler": "^20.0.0",
+        "@angular/compiler-cli": "^20.0.0",
+        "@angular/core": "^20.0.0",
+        "@angular/localize": "^20.0.0",
+        "@angular/platform-browser": "^20.0.0",
+        "@angular/platform-server": "^20.0.0",
+        "@angular/service-worker": "^20.0.0",
+        "@angular/ssr": "^20.3.25",
+        "karma": "^6.4.0",
+        "less": "^4.2.0",
+        "ng-packagr": "^20.0.0",
+        "postcss": "^8.4.0",
+        "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0",
+        "tslib": "^2.3.0",
+        "typescript": ">=5.8 <6.0",
+        "vitest": "^3.1.1"
+      },
+      "peerDependenciesMeta": {
+        "@angular/core": {
+          "optional": true
+        },
+        "@angular/localize": {
+          "optional": true
+        },
+        "@angular/platform-browser": {
+          "optional": true
+        },
+        "@angular/platform-server": {
+          "optional": true
+        },
+        "@angular/service-worker": {
+          "optional": true
+        },
+        "@angular/ssr": {
+          "optional": true
+        },
+        "karma": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "ng-packagr": {
+          "optional": true
+        },
+        "postcss": {
+          "optional": true
+        },
+        "tailwindcss": {
+          "optional": true
+        },
+        "vitest": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@angular/cli": {
+      "version": "20.3.25",
+      "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.25.tgz",
+      "integrity": "sha512-QOSxza45CZY11kqPVpqsU+WGYF99rR/r9A9GykZQWuAHb5SEAxlXHyaaGMu/BMtBHy5HNIlJH25UlzelrbaNyQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@angular-devkit/architect": "0.2003.25",
+        "@angular-devkit/core": "20.3.25",
+        "@angular-devkit/schematics": "20.3.25",
+        "@inquirer/prompts": "7.8.2",
+        "@listr2/prompt-adapter-inquirer": "3.0.1",
+        "@modelcontextprotocol/sdk": "1.26.0",
+        "@schematics/angular": "20.3.25",
+        "@yarnpkg/lockfile": "1.1.0",
+        "algoliasearch": "5.35.0",
+        "ini": "5.0.0",
+        "jsonc-parser": "3.3.1",
+        "listr2": "9.0.1",
+        "npm-package-arg": "13.0.0",
+        "pacote": "21.0.4",
+        "resolve": "1.22.10",
+        "semver": "7.7.2",
+        "yargs": "18.0.0",
+        "zod": "4.1.13"
+      },
+      "bin": {
+        "ng": "bin/ng.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@angular/common": {
+      "version": "20.3.19",
+      "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.19.tgz",
+      "integrity": "sha512-hcB1eUEN8LGcKGc4DlRJ+abS6AYfbEHDZKg8LnXNugkbwI6Ebyh2AUYTDhzZL2S4aH+C8biHKgSYHFCqieCRhA==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      },
+      "peerDependencies": {
+        "@angular/core": "20.3.19",
+        "rxjs": "^6.5.3 || ^7.4.0"
+      }
+    },
+    "node_modules/@angular/compiler": {
+      "version": "20.3.19",
+      "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.19.tgz",
+      "integrity": "sha512-ETkgDKm0l2PuaBubgPJe0ccy8kE75DFu6/zKcz7TUuk3KrKF2OZAopbbjftsUSZGeCNvCdqHzjmcL6hQ6oAOwA==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      }
+    },
+    "node_modules/@angular/compiler-cli": {
+      "version": "20.3.19",
+      "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.19.tgz",
+      "integrity": "sha512-ET/JjO8s62kAHfgIsGXlvW5VUwLqHm03q1y/2yD7aQW/WdDvssMsvZv7Knl440989vdOFemIGTMwVPakmWqRmA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/core": "7.28.3",
+        "@jridgewell/sourcemap-codec": "^1.4.14",
+        "chokidar": "^4.0.0",
+        "convert-source-map": "^1.5.1",
+        "reflect-metadata": "^0.2.0",
+        "semver": "^7.0.0",
+        "tslib": "^2.3.0",
+        "yargs": "^18.0.0"
+      },
+      "bin": {
+        "ng-xi18n": "bundles/src/bin/ng_xi18n.js",
+        "ngc": "bundles/src/bin/ngc.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      },
+      "peerDependencies": {
+        "@angular/compiler": "20.3.19",
+        "typescript": ">=5.8 <6.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@angular/core": {
+      "version": "20.3.19",
+      "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.19.tgz",
+      "integrity": "sha512-SYnwW+q51bQoPtGFoGovm1P5GK9fMEXsG0lGaEAUapjskblAYyX7hLlM/jgueSojv2SjhqNF8aXR+gjHLhZVNA==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      },
+      "peerDependencies": {
+        "@angular/compiler": "20.3.19",
+        "rxjs": "^6.5.3 || ^7.4.0",
+        "zone.js": "~0.15.0"
+      },
+      "peerDependenciesMeta": {
+        "@angular/compiler": {
+          "optional": true
+        },
+        "zone.js": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@angular/forms": {
+      "version": "20.3.19",
+      "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.19.tgz",
+      "integrity": "sha512-WJotd+Lhl4FG2b0K+aQNyQDHhR515zKCuphjiUqEW7sifWrOQxANLKzPBngGrH75ayANFgPaDf7U3ZRIoblcQA==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      },
+      "peerDependencies": {
+        "@angular/common": "20.3.19",
+        "@angular/core": "20.3.19",
+        "@angular/platform-browser": "20.3.19",
+        "rxjs": "^6.5.3 || ^7.4.0"
+      }
+    },
+    "node_modules/@angular/platform-browser": {
+      "version": "20.3.19",
+      "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.19.tgz",
+      "integrity": "sha512-TRZfatH1B/kreDwFRwtpLEurJQ6044qh6DWpvxzTbugaG5otLQJKTk+1z81/KsJwQqc1+24v+yuywc1LM7aq7w==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      },
+      "peerDependencies": {
+        "@angular/animations": "20.3.19",
+        "@angular/common": "20.3.19",
+        "@angular/core": "20.3.19"
+      },
+      "peerDependenciesMeta": {
+        "@angular/animations": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@angular/router": {
+      "version": "20.3.19",
+      "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.19.tgz",
+      "integrity": "sha512-qHrMniHOsCJ4neZmcQVodjutJilyXAXk7EhLa931QyL0qyVKVomv6E0I3UFzRaC3ZeHc+hzBdU6C6bvMFKTl1g==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      },
+      "peerDependencies": {
+        "@angular/common": "20.3.19",
+        "@angular/core": "20.3.19",
+        "@angular/platform-browser": "20.3.19",
+        "rxjs": "^6.5.3 || ^7.4.0"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+      "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.28.5",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.29.3",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz",
+      "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.28.3",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz",
+      "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.27.1",
+        "@babel/generator": "^7.28.3",
+        "@babel/helper-compilation-targets": "^7.27.2",
+        "@babel/helper-module-transforms": "^7.28.3",
+        "@babel/helpers": "^7.28.3",
+        "@babel/parser": "^7.28.3",
+        "@babel/template": "^7.27.2",
+        "@babel/traverse": "^7.28.3",
+        "@babel/types": "^7.28.2",
+        "convert-source-map": "^2.0.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.3",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/convert-source-map": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+      "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.29.1",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
+      "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.0",
+        "@babel/types": "^7.29.0",
+        "@jridgewell/gen-mapping": "^0.3.12",
+        "@jridgewell/trace-mapping": "^0.3.28",
+        "jsesc": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.27.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
+      "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.27.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+      "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/compat-data": "^7.28.6",
+        "@babel/helper-validator-option": "^7.27.1",
+        "browserslist": "^4.24.0",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-globals": {
+      "version": "7.28.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+      "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+      "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/traverse": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+      "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.28.6",
+        "@babel/helper-validator-identifier": "^7.28.5",
+        "@babel/traverse": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-split-export-declaration": {
+      "version": "7.24.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
+      "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.24.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+      "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.28.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+      "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+      "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.29.2",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
+      "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/template": "^7.28.6",
+        "@babel/types": "^7.29.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.29.3",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
+      "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.29.0"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.28.6",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+      "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.28.6",
+        "@babel/parser": "^7.28.6",
+        "@babel/types": "^7.28.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+      "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.29.0",
+        "@babel/generator": "^7.29.0",
+        "@babel/helper-globals": "^7.28.0",
+        "@babel/parser": "^7.29.0",
+        "@babel/template": "^7.28.6",
+        "@babel/types": "^7.29.0",
+        "debug": "^4.3.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.29.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+      "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.27.1",
+        "@babel/helper-validator-identifier": "^7.28.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@colors/colors": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+      "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
+      "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
+      "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
+      "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
+      "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
+      "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
+      "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
+      "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
+      "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
+      "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
+      "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
+      "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
+      "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
+      "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
+      "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
+      "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
+      "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
+      "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
+      "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
+      "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
+      "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
+      "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openharmony-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
+      "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
+      "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
+      "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
+      "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
+      "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@gar/promise-retry": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz",
+      "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@hono/node-server": {
+      "version": "1.19.14",
+      "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz",
+      "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.14.1"
+      },
+      "peerDependencies": {
+        "hono": "^4"
+      }
+    },
+    "node_modules/@inquirer/ansi": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
+      "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@inquirer/checkbox": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz",
+      "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/ansi": "^1.0.2",
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/figures": "^1.0.15",
+        "@inquirer/type": "^3.0.10",
+        "yoctocolors-cjs": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/confirm": {
+      "version": "5.1.14",
+      "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz",
+      "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.1.15",
+        "@inquirer/type": "^3.0.8"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/core": {
+      "version": "10.3.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz",
+      "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/ansi": "^1.0.2",
+        "@inquirer/figures": "^1.0.15",
+        "@inquirer/type": "^3.0.10",
+        "cli-width": "^4.1.0",
+        "mute-stream": "^2.0.0",
+        "signal-exit": "^4.1.0",
+        "wrap-ansi": "^6.2.0",
+        "yoctocolors-cjs": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/editor": {
+      "version": "4.2.23",
+      "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz",
+      "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/external-editor": "^1.0.3",
+        "@inquirer/type": "^3.0.10"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/expand": {
+      "version": "4.0.23",
+      "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz",
+      "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/type": "^3.0.10",
+        "yoctocolors-cjs": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/external-editor": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz",
+      "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chardet": "^2.1.1",
+        "iconv-lite": "^0.7.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/figures": {
+      "version": "1.0.15",
+      "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz",
+      "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@inquirer/input": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz",
+      "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/type": "^3.0.10"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/number": {
+      "version": "3.0.23",
+      "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz",
+      "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/type": "^3.0.10"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/password": {
+      "version": "4.0.23",
+      "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz",
+      "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/ansi": "^1.0.2",
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/type": "^3.0.10"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/prompts": {
+      "version": "7.8.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.2.tgz",
+      "integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/checkbox": "^4.2.1",
+        "@inquirer/confirm": "^5.1.14",
+        "@inquirer/editor": "^4.2.17",
+        "@inquirer/expand": "^4.0.17",
+        "@inquirer/input": "^4.2.1",
+        "@inquirer/number": "^3.0.17",
+        "@inquirer/password": "^4.0.17",
+        "@inquirer/rawlist": "^4.1.5",
+        "@inquirer/search": "^3.1.0",
+        "@inquirer/select": "^4.3.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/rawlist": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz",
+      "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/type": "^3.0.10",
+        "yoctocolors-cjs": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/search": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz",
+      "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/figures": "^1.0.15",
+        "@inquirer/type": "^3.0.10",
+        "yoctocolors-cjs": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/select": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz",
+      "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/ansi": "^1.0.2",
+        "@inquirer/core": "^10.3.2",
+        "@inquirer/figures": "^1.0.15",
+        "@inquirer/type": "^3.0.10",
+        "yoctocolors-cjs": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@inquirer/type": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz",
+      "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@types/node": ">=18"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@isaacs/fs-minipass": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+      "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.0.4"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz",
+      "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@listr2/prompt-adapter-inquirer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.1.tgz",
+      "integrity": "sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@inquirer/type": "^3.0.7"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      },
+      "peerDependencies": {
+        "@inquirer/prompts": ">= 3 < 8",
+        "listr2": "9.0.1"
+      }
+    },
+    "node_modules/@lmdb/lmdb-darwin-arm64": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.2.tgz",
+      "integrity": "sha512-NK80WwDoODyPaSazKbzd3NEJ3ygePrkERilZshxBViBARNz21rmediktGHExoj9n5t9+ChlgLlxecdFKLCuCKg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-darwin-x64": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.4.2.tgz",
+      "integrity": "sha512-zevaowQNmrp3U7Fz1s9pls5aIgpKRsKb3dZWDINtLiozh3jZI9fBrI19lYYBxqdyiIyNdlyiidPnwPShj4aK+w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-linux-arm": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.4.2.tgz",
+      "integrity": "sha512-OmHCULY17rkx/RoCoXlzU7LyR8xqrksgdYWwtYa14l/sseezZ8seKWXcogHcjulBddER5NnEFV4L/Jtr2nyxeg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-linux-arm64": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.4.2.tgz",
+      "integrity": "sha512-ZBEfbNZdkneebvZs98Lq30jMY8V9IJzckVeigGivV7nTHJc+89Ctomp1kAIWKlwIG0ovCDrFI448GzFPORANYg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-linux-x64": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.4.2.tgz",
+      "integrity": "sha512-vL9nM17C77lohPYE4YaAQvfZCSVJSryE4fXdi8M7uWPBnU+9DJabgKVAeyDb84ZM2vcFseoBE4/AagVtJeRE7g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-win32-arm64": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.4.2.tgz",
+      "integrity": "sha512-SXWjdBfNDze4ZPeLtYIzsIeDJDJ/SdsA0pEXcUBayUIMO0FQBHfVZZyHXQjjHr4cvOAzANBgIiqaXRwfMhzmLw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@lmdb/lmdb-win32-x64": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.4.2.tgz",
+      "integrity": "sha512-IY+r3bxKW6Q6sIPiMC0L533DEfRJSXibjSI3Ft/w9Q8KQBNqEIvUFXt+09wV8S5BRk0a8uSF19YWxuRwEfI90g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@modelcontextprotocol/sdk": {
+      "version": "1.26.0",
+      "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz",
+      "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@hono/node-server": "^1.19.9",
+        "ajv": "^8.17.1",
+        "ajv-formats": "^3.0.1",
+        "content-type": "^1.0.5",
+        "cors": "^2.8.5",
+        "cross-spawn": "^7.0.5",
+        "eventsource": "^3.0.2",
+        "eventsource-parser": "^3.0.0",
+        "express": "^5.2.1",
+        "express-rate-limit": "^8.2.1",
+        "hono": "^4.11.4",
+        "jose": "^6.1.3",
+        "json-schema-typed": "^8.0.2",
+        "pkce-challenge": "^5.0.0",
+        "raw-body": "^3.0.0",
+        "zod": "^3.25 || ^4.0",
+        "zod-to-json-schema": "^3.25.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@cfworker/json-schema": "^4.1.1",
+        "zod": "^3.25 || ^4.0"
+      },
+      "peerDependenciesMeta": {
+        "@cfworker/json-schema": {
+          "optional": true
+        },
+        "zod": {
+          "optional": false
+        }
+      }
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
+      "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
+      "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
+      "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
+      "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
+      "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
+      "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@napi-rs/nice": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz",
+      "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">= 10"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/Brooooooklyn"
+      },
+      "optionalDependencies": {
+        "@napi-rs/nice-android-arm-eabi": "1.1.1",
+        "@napi-rs/nice-android-arm64": "1.1.1",
+        "@napi-rs/nice-darwin-arm64": "1.1.1",
+        "@napi-rs/nice-darwin-x64": "1.1.1",
+        "@napi-rs/nice-freebsd-x64": "1.1.1",
+        "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1",
+        "@napi-rs/nice-linux-arm64-gnu": "1.1.1",
+        "@napi-rs/nice-linux-arm64-musl": "1.1.1",
+        "@napi-rs/nice-linux-ppc64-gnu": "1.1.1",
+        "@napi-rs/nice-linux-riscv64-gnu": "1.1.1",
+        "@napi-rs/nice-linux-s390x-gnu": "1.1.1",
+        "@napi-rs/nice-linux-x64-gnu": "1.1.1",
+        "@napi-rs/nice-linux-x64-musl": "1.1.1",
+        "@napi-rs/nice-openharmony-arm64": "1.1.1",
+        "@napi-rs/nice-win32-arm64-msvc": "1.1.1",
+        "@napi-rs/nice-win32-ia32-msvc": "1.1.1",
+        "@napi-rs/nice-win32-x64-msvc": "1.1.1"
+      }
+    },
+    "node_modules/@napi-rs/nice-android-arm-eabi": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz",
+      "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-android-arm64": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz",
+      "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-darwin-arm64": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz",
+      "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-darwin-x64": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz",
+      "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-freebsd-x64": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz",
+      "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-arm-gnueabihf": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz",
+      "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-arm64-gnu": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz",
+      "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-arm64-musl": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz",
+      "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-ppc64-gnu": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz",
+      "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-riscv64-gnu": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz",
+      "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-s390x-gnu": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz",
+      "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-x64-gnu": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz",
+      "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-linux-x64-musl": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz",
+      "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-openharmony-arm64": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz",
+      "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-win32-arm64-msvc": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz",
+      "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-win32-ia32-msvc": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz",
+      "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@napi-rs/nice-win32-x64-msvc": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz",
+      "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@npmcli/agent": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz",
+      "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.1",
+        "lru-cache": "^11.2.1",
+        "socks-proxy-agent": "^8.0.3"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/agent/node_modules/lru-cache": {
+      "version": "11.3.6",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
+      "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/@npmcli/fs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz",
+      "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/git": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz",
+      "integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@gar/promise-retry": "^1.0.0",
+        "@npmcli/promise-spawn": "^9.0.0",
+        "ini": "^6.0.0",
+        "lru-cache": "^11.2.1",
+        "npm-pick-manifest": "^11.0.1",
+        "proc-log": "^6.0.0",
+        "semver": "^7.3.5",
+        "which": "^6.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/ini": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz",
+      "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/isexe": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+      "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/lru-cache": {
+      "version": "11.3.6",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
+      "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/which": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+      "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^4.0.0"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/installed-package-contents": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz",
+      "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "npm-bundled": "^5.0.0",
+        "npm-normalize-package-bin": "^5.0.0"
+      },
+      "bin": {
+        "installed-package-contents": "bin/index.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/node-gyp": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz",
+      "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/package-json": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz",
+      "integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@npmcli/git": "^7.0.0",
+        "glob": "^13.0.0",
+        "hosted-git-info": "^9.0.0",
+        "json-parse-even-better-errors": "^5.0.0",
+        "proc-log": "^6.0.0",
+        "semver": "^7.5.3",
+        "spdx-expression-parse": "^4.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/package-json/node_modules/balanced-match": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+      "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/@npmcli/package-json/node_modules/brace-expansion": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+      "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^4.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/@npmcli/package-json/node_modules/glob": {
+      "version": "13.0.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+      "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "minimatch": "^10.2.2",
+        "minipass": "^7.1.3",
+        "path-scurry": "^2.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@npmcli/package-json/node_modules/minimatch": {
+      "version": "10.2.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+      "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "brace-expansion": "^5.0.5"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@npmcli/package-json/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/promise-spawn": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz",
+      "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "which": "^6.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/promise-spawn/node_modules/isexe": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+      "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/@npmcli/promise-spawn/node_modules/which": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+      "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^4.0.0"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/redact": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz",
+      "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/run-script": {
+      "version": "10.0.4",
+      "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz",
+      "integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@npmcli/node-gyp": "^5.0.0",
+        "@npmcli/package-json": "^7.0.0",
+        "@npmcli/promise-spawn": "^9.0.0",
+        "node-gyp": "^12.1.0",
+        "proc-log": "^6.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@npmcli/run-script/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@parcel/watcher": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
+      "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "detect-libc": "^2.0.3",
+        "is-glob": "^4.0.3",
+        "node-addon-api": "^7.0.0",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher-android-arm64": "2.5.6",
+        "@parcel/watcher-darwin-arm64": "2.5.6",
+        "@parcel/watcher-darwin-x64": "2.5.6",
+        "@parcel/watcher-freebsd-x64": "2.5.6",
+        "@parcel/watcher-linux-arm-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm-musl": "2.5.6",
+        "@parcel/watcher-linux-arm64-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm64-musl": "2.5.6",
+        "@parcel/watcher-linux-x64-glibc": "2.5.6",
+        "@parcel/watcher-linux-x64-musl": "2.5.6",
+        "@parcel/watcher-win32-arm64": "2.5.6",
+        "@parcel/watcher-win32-ia32": "2.5.6",
+        "@parcel/watcher-win32-x64": "2.5.6"
+      }
+    },
+    "node_modules/@parcel/watcher-android-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
+      "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
+      "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
+      "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-freebsd-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
+      "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
+      "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
+      "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
+      "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
+      "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
+      "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
+      "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
+      "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-ia32": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
+      "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
+      "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher/node_modules/node-addon-api": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+      "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
+      "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
+      "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
+      "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
+      "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
+      "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
+      "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
+      "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
+      "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
+      "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
+      "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-gnu": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
+      "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-musl": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
+      "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
+      "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-musl": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
+      "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
+      "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-musl": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
+      "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
+      "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
+      "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
+      "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-openbsd-x64": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
+      "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-openharmony-arm64": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
+      "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
+      "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
+      "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-gnu": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
+      "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
+      "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@schematics/angular": {
+      "version": "20.3.25",
+      "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.25.tgz",
+      "integrity": "sha512-ezoJpPKhhjXgE3LxuNcJO/ghSXs8f73xrqGvqouag7IbuliJYbHrt22WH3X75XSbD0+iOdiqA2bARvAO/ezyxQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@angular-devkit/core": "20.3.25",
+        "@angular-devkit/schematics": "20.3.25",
+        "jsonc-parser": "3.3.1"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@sigstore/bundle": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz",
+      "integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@sigstore/protobuf-specs": "^0.5.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@sigstore/core": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.0.tgz",
+      "integrity": "sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@sigstore/protobuf-specs": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.1.tgz",
+      "integrity": "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/@sigstore/sign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.1.tgz",
+      "integrity": "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@gar/promise-retry": "^1.0.2",
+        "@sigstore/bundle": "^4.0.0",
+        "@sigstore/core": "^3.2.0",
+        "@sigstore/protobuf-specs": "^0.5.0",
+        "make-fetch-happen": "^15.0.4",
+        "proc-log": "^6.1.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@sigstore/sign/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@sigstore/tuf": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.2.tgz",
+      "integrity": "sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@sigstore/protobuf-specs": "^0.5.0",
+        "tuf-js": "^4.1.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@sigstore/verify": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.0.tgz",
+      "integrity": "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@sigstore/bundle": "^4.0.0",
+        "@sigstore/core": "^3.1.0",
+        "@sigstore/protobuf-specs": "^0.5.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@socket.io/component-emitter": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
+      "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@tufjs/canonical-json": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
+      "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@tufjs/models": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.1.0.tgz",
+      "integrity": "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@tufjs/canonical-json": "2.0.0",
+        "minimatch": "^10.1.1"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/@tufjs/models/node_modules/balanced-match": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+      "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/@tufjs/models/node_modules/brace-expansion": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+      "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^4.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/@tufjs/models/node_modules/minimatch": {
+      "version": "10.2.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+      "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "brace-expansion": "^5.0.5"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@types/cors": {
+      "version": "2.8.19",
+      "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
+      "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/jasmine": {
+      "version": "5.1.15",
+      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.15.tgz",
+      "integrity": "sha512-ZAC8KjmV2MJxbNTrwXFN+HKeajpXQZp6KpPiR6Aa4XvaEnjP6qh23lL/Rqb7AYzlp3h/rcwDrQ7Gg7q28cQTQg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "25.6.0",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
+      "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~7.19.0"
+      }
+    },
+    "node_modules/@types/ws": {
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+      "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@vitejs/plugin-basic-ssl": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz",
+      "integrity": "sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+      },
+      "peerDependencies": {
+        "vite": "^6.0.0 || ^7.0.0"
+      }
+    },
+    "node_modules/@yarnpkg/lockfile": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
+      "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/abbrev": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz",
+      "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/accepts": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+      "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-types": "^3.0.0",
+        "negotiator": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+      "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "8.18.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
+      "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "fast-uri": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ajv-formats": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+      "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/algoliasearch": {
+      "version": "5.35.0",
+      "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.35.0.tgz",
+      "integrity": "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@algolia/abtesting": "1.1.0",
+        "@algolia/client-abtesting": "5.35.0",
+        "@algolia/client-analytics": "5.35.0",
+        "@algolia/client-common": "5.35.0",
+        "@algolia/client-insights": "5.35.0",
+        "@algolia/client-personalization": "5.35.0",
+        "@algolia/client-query-suggestions": "5.35.0",
+        "@algolia/client-search": "5.35.0",
+        "@algolia/ingestion": "1.35.0",
+        "@algolia/monitoring": "1.35.0",
+        "@algolia/recommend": "5.35.0",
+        "@algolia/requester-browser-xhr": "5.35.0",
+        "@algolia/requester-fetch": "5.35.0",
+        "@algolia/requester-node-http": "5.35.0"
+      },
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
+    "node_modules/ansi-escapes": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz",
+      "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "environment": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/anymatch/node_modules/picomatch": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+      "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/base64id": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+      "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^4.5.0 || >= 5.9"
+      }
+    },
+    "node_modules/baseline-browser-mapping": {
+      "version": "2.10.27",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.27.tgz",
+      "integrity": "sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "baseline-browser-mapping": "dist/cli.cjs"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/beasties": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.3.5.tgz",
+      "integrity": "sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "css-select": "^6.0.0",
+        "css-what": "^7.0.0",
+        "dom-serializer": "^2.0.0",
+        "domhandler": "^5.0.3",
+        "htmlparser2": "^10.0.0",
+        "picocolors": "^1.1.1",
+        "postcss": "^8.4.49",
+        "postcss-media-query-parser": "^0.2.3"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/body-parser": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
+      "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "^3.1.2",
+        "content-type": "^1.0.5",
+        "debug": "^4.4.3",
+        "http-errors": "^2.0.0",
+        "iconv-lite": "^0.7.0",
+        "on-finished": "^2.4.1",
+        "qs": "^6.14.1",
+        "raw-body": "^3.0.1",
+        "type-is": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.14",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
+      "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.28.2",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+      "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "baseline-browser-mapping": "^2.10.12",
+        "caniuse-lite": "^1.0.30001782",
+        "electron-to-chromium": "^1.5.328",
+        "node-releases": "^2.0.36",
+        "update-browserslist-db": "^1.2.3"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/cacache": {
+      "version": "20.0.4",
+      "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.4.tgz",
+      "integrity": "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@npmcli/fs": "^5.0.0",
+        "fs-minipass": "^3.0.0",
+        "glob": "^13.0.0",
+        "lru-cache": "^11.1.0",
+        "minipass": "^7.0.3",
+        "minipass-collect": "^2.0.1",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "p-map": "^7.0.2",
+        "ssri": "^13.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/cacache/node_modules/balanced-match": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+      "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/cacache/node_modules/brace-expansion": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+      "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^4.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/cacache/node_modules/glob": {
+      "version": "13.0.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+      "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "minimatch": "^10.2.2",
+        "minipass": "^7.1.3",
+        "path-scurry": "^2.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/cacache/node_modules/lru-cache": {
+      "version": "11.3.6",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
+      "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/cacache/node_modules/minimatch": {
+      "version": "10.2.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+      "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "brace-expansion": "^5.0.5"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/call-bound": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "get-intrinsic": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001792",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz",
+      "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "CC-BY-4.0"
+    },
+    "node_modules/chalk": {
+      "version": "5.6.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+      "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/chardet": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz",
+      "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/chownr": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+      "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/cli-cursor": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+      "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "restore-cursor": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cli-spinners": {
+      "version": "2.9.2",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+      "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cli-truncate": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
+      "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "slice-ansi": "^5.0.0",
+        "string-width": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cli-width": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+      "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
+      "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^7.2.0",
+        "strip-ansi": "^7.1.0",
+        "wrap-ansi": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/cliui/node_modules/wrap-ansi": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
+      "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "string-width": "^7.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/colorette": {
+      "version": "2.0.20",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+      "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/connect": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+      "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "2.6.9",
+        "finalhandler": "1.1.2",
+        "parseurl": "~1.3.3",
+        "utils-merge": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/connect/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/connect/node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/connect/node_modules/finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/connect/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/connect/node_modules/on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/connect/node_modules/statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/content-disposition": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz",
+      "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/content-type": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/convert-source-map": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/cookie": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+      "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie-signature": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+      "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.6.0"
+      }
+    },
+    "node_modules/cors": {
+      "version": "2.8.6",
+      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
+      "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "object-assign": "^4",
+        "vary": "^1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/css-select": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz",
+      "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^7.0.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.2.2",
+        "nth-check": "^2.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz",
+      "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/custom-event": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
+      "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/date-format": {
+      "version": "4.0.14",
+      "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
+      "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/destroy": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/di": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
+      "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/dom-serialize": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
+      "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "custom-event": "~1.0.0",
+        "ent": "~2.2.0",
+        "extend": "^3.0.0",
+        "void-elements": "^2.0.0"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "domelementtype": "^2.3.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+      "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
+    "node_modules/dunder-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+      "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.5.351",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.351.tgz",
+      "integrity": "sha512-9D7Iqx8RImSvCnOsj86rCH6eQjZFQoM04Jn6HnZVM0Nu/G58/gmKYQ1d12MZTbjQbQSTGI8nwEy07ErsA2slLA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/emoji-regex": {
+      "version": "10.6.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+      "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/encodeurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+      "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/engine.io": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.7.tgz",
+      "integrity": "sha512-DgOngfDKM2EviOH3Mr9m7ks1q8roetLy/IMmYthAYzbpInMbYc/GS+fWFA3rl1gvwKVsQrVV61fo5emD1y3OJQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/cors": "^2.8.12",
+        "@types/node": ">=10.0.0",
+        "@types/ws": "^8.5.12",
+        "accepts": "~1.3.4",
+        "base64id": "2.0.0",
+        "cookie": "~0.7.2",
+        "cors": "~2.8.5",
+        "debug": "~4.4.1",
+        "engine.io-parser": "~5.2.1",
+        "ws": "~8.18.3"
+      },
+      "engines": {
+        "node": ">=10.2.0"
+      }
+    },
+    "node_modules/engine.io-parser": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
+      "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/engine.io/node_modules/accepts": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/engine.io/node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/engine.io/node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/engine.io/node_modules/negotiator": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/ent": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz",
+      "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.3",
+        "es-errors": "^1.3.0",
+        "punycode": "^1.4.1",
+        "safe-regex-test": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/env-paths": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+      "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/environment": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
+      "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/err-code": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+      "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-object-atoms": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+      "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.28.0",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
+      "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.28.0",
+        "@esbuild/android-arm": "0.28.0",
+        "@esbuild/android-arm64": "0.28.0",
+        "@esbuild/android-x64": "0.28.0",
+        "@esbuild/darwin-arm64": "0.28.0",
+        "@esbuild/darwin-x64": "0.28.0",
+        "@esbuild/freebsd-arm64": "0.28.0",
+        "@esbuild/freebsd-x64": "0.28.0",
+        "@esbuild/linux-arm": "0.28.0",
+        "@esbuild/linux-arm64": "0.28.0",
+        "@esbuild/linux-ia32": "0.28.0",
+        "@esbuild/linux-loong64": "0.28.0",
+        "@esbuild/linux-mips64el": "0.28.0",
+        "@esbuild/linux-ppc64": "0.28.0",
+        "@esbuild/linux-riscv64": "0.28.0",
+        "@esbuild/linux-s390x": "0.28.0",
+        "@esbuild/linux-x64": "0.28.0",
+        "@esbuild/netbsd-arm64": "0.28.0",
+        "@esbuild/netbsd-x64": "0.28.0",
+        "@esbuild/openbsd-arm64": "0.28.0",
+        "@esbuild/openbsd-x64": "0.28.0",
+        "@esbuild/openharmony-arm64": "0.28.0",
+        "@esbuild/sunos-x64": "0.28.0",
+        "@esbuild/win32-arm64": "0.28.0",
+        "@esbuild/win32-ia32": "0.28.0",
+        "@esbuild/win32-x64": "0.28.0"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+      "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/eventemitter3": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/eventsource": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz",
+      "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eventsource-parser": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/eventsource-parser": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz",
+      "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/exponential-backoff": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz",
+      "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
+      "dev": true,
+      "license": "Apache-2.0"
+    },
+    "node_modules/express": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
+      "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "accepts": "^2.0.0",
+        "body-parser": "^2.2.1",
+        "content-disposition": "^1.0.0",
+        "content-type": "^1.0.5",
+        "cookie": "^0.7.1",
+        "cookie-signature": "^1.2.1",
+        "debug": "^4.4.0",
+        "depd": "^2.0.0",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "etag": "^1.8.1",
+        "finalhandler": "^2.1.0",
+        "fresh": "^2.0.0",
+        "http-errors": "^2.0.0",
+        "merge-descriptors": "^2.0.0",
+        "mime-types": "^3.0.0",
+        "on-finished": "^2.4.1",
+        "once": "^1.4.0",
+        "parseurl": "^1.3.3",
+        "proxy-addr": "^2.0.7",
+        "qs": "^6.14.0",
+        "range-parser": "^1.2.1",
+        "router": "^2.2.0",
+        "send": "^1.1.0",
+        "serve-static": "^2.2.0",
+        "statuses": "^2.0.1",
+        "type-is": "^2.0.1",
+        "vary": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/express-rate-limit": {
+      "version": "8.5.1",
+      "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.1.tgz",
+      "integrity": "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ip-address": "^10.2.0"
+      },
+      "engines": {
+        "node": ">= 16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/express-rate-limit"
+      },
+      "peerDependencies": {
+        "express": ">= 4.11"
+      }
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz",
+      "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fastify"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/fastify"
+        }
+      ],
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/fdir": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+      "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/finalhandler": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
+      "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.4.0",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "on-finished": "^2.4.1",
+        "parseurl": "^1.3.3",
+        "statuses": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+      "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.16.0",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
+      "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fresh": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+      "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
+    "node_modules/fs-minipass": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz",
+      "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.0.3"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-east-asian-width": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz",
+      "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+      "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "es-define-property": "^1.0.1",
+        "es-errors": "^1.3.0",
+        "es-object-atoms": "^1.1.1",
+        "function-bind": "^1.1.2",
+        "get-proto": "^1.0.1",
+        "gopd": "^1.2.0",
+        "has-symbols": "^1.1.0",
+        "hasown": "^2.0.2",
+        "math-intrinsics": "^1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+      "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "dunder-proto": "^1.0.1",
+        "es-object-atoms": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/glob-to-regexp": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+      "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+      "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-tostringtag": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+      "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-symbols": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
+      "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/hono": {
+      "version": "4.12.18",
+      "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz",
+      "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=16.9.0"
+      }
+    },
+    "node_modules/hosted-git-info": {
+      "version": "9.0.3",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz",
+      "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "lru-cache": "^11.1.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/hosted-git-info/node_modules/lru-cache": {
+      "version": "11.3.6",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
+      "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/htmlparser2": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
+      "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
+      "dev": true,
+      "funding": [
+        "https://github.com/fb55/htmlparser2?sponsor=1",
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.2.2",
+        "entities": "^7.0.1"
+      }
+    },
+    "node_modules/htmlparser2/node_modules/entities": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
+      "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/http-cache-semantics": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
+      "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/http-errors": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+      "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "depd": "~2.0.0",
+        "inherits": "~2.0.4",
+        "setprototypeof": "~1.2.0",
+        "statuses": "~2.0.2",
+        "toidentifier": "~1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/http-proxy": {
+      "version": "1.18.1",
+      "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+      "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eventemitter3": "^4.0.0",
+        "follow-redirects": "^1.0.0",
+        "requires-port": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/http-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
+      "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/ignore-walk": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz",
+      "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "minimatch": "^10.0.3"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/ignore-walk/node_modules/balanced-match": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+      "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/ignore-walk/node_modules/brace-expansion": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+      "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^4.0.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      }
+    },
+    "node_modules/ignore-walk/node_modules/minimatch": {
+      "version": "10.2.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+      "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "brace-expansion": "^5.0.5"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/immutable": {
+      "version": "5.1.5",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
+      "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/ini": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz",
+      "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/ip-address": {
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
+      "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.16.2",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+      "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "hasown": "^2.0.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
+      "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-interactive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz",
+      "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-promise": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+      "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-regex": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+      "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "gopd": "^1.2.0",
+        "has-tostringtag": "^1.0.2",
+        "hasown": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-unicode-supported": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+      "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isbinaryfile": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz",
+      "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/gjtorikian/"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/istanbul-lib-coverage": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+      "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
+      "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/core": "^7.23.9",
+        "@babel/parser": "^7.23.9",
+        "@istanbuljs/schema": "^0.1.3",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^7.5.4"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-report": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+      "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "istanbul-lib-coverage": "^3.0.0",
+        "make-dir": "^4.0.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+      "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "debug": "^4.1.1",
+        "istanbul-lib-coverage": "^3.0.0",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-source-maps/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/istanbul-reports": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
+      "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "html-escaper": "^2.0.0",
+        "istanbul-lib-report": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jasmine-core": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.7.1.tgz",
+      "integrity": "sha512-QnurrtpKsPoixxG2R3d1xP0St/2kcX5oTZyDyQJMY+Vzi/HUlu1kGm+2V8Tz+9lV991leB1l0xcsyz40s9xOOw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/jose": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz",
+      "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/panva"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/jsesc": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+      "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz",
+      "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-schema-typed": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz",
+      "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonc-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+      "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "dev": true,
+      "license": "MIT",
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+      "dev": true,
+      "engines": [
+        "node >= 0.2.0"
+      ],
+      "license": "MIT"
+    },
+    "node_modules/karma": {
+      "version": "6.4.4",
+      "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz",
+      "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@colors/colors": "1.5.0",
+        "body-parser": "^1.19.0",
+        "braces": "^3.0.2",
+        "chokidar": "^3.5.1",
+        "connect": "^3.7.0",
+        "di": "^0.0.1",
+        "dom-serialize": "^2.2.1",
+        "glob": "^7.1.7",
+        "graceful-fs": "^4.2.6",
+        "http-proxy": "^1.18.1",
+        "isbinaryfile": "^4.0.8",
+        "lodash": "^4.17.21",
+        "log4js": "^6.4.1",
+        "mime": "^2.5.2",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.5",
+        "qjobs": "^1.2.0",
+        "range-parser": "^1.2.1",
+        "rimraf": "^3.0.2",
+        "socket.io": "^4.7.2",
+        "source-map": "^0.6.1",
+        "tmp": "^0.2.1",
+        "ua-parser-js": "^0.7.30",
+        "yargs": "^16.1.1"
+      },
+      "bin": {
+        "karma": "bin/karma"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/karma-chrome-launcher": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz",
+      "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "which": "^1.2.1"
+      }
+    },
+    "node_modules/karma-chrome-launcher/node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/karma-coverage": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz",
+      "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "istanbul-lib-coverage": "^3.2.0",
+        "istanbul-lib-instrument": "^5.1.0",
+        "istanbul-lib-report": "^3.0.0",
+        "istanbul-lib-source-maps": "^4.0.1",
+        "istanbul-reports": "^3.0.5",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/karma-coverage/node_modules/semver": {
+      "version": "6.3.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/karma-jasmine": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz",
+      "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jasmine-core": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "karma": "^6.0.0"
+      }
+    },
+    "node_modules/karma-jasmine-html-reporter": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz",
+      "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "jasmine-core": "^4.0.0 || ^5.0.0",
+        "karma": "^6.0.0",
+        "karma-jasmine": "^5.0.0"
+      }
+    },
+    "node_modules/karma-jasmine/node_modules/jasmine-core": {
+      "version": "4.6.1",
+      "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz",
+      "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/karma/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/karma/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/karma/node_modules/body-parser": {
+      "version": "1.20.5",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz",
+      "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "~3.1.2",
+        "content-type": "~1.0.5",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "~1.2.0",
+        "http-errors": "~2.0.1",
+        "iconv-lite": "~0.4.24",
+        "on-finished": "~2.4.1",
+        "qs": "~6.15.1",
+        "raw-body": "~2.5.3",
+        "type-is": "~1.6.18",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/karma/node_modules/chokidar": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/karma/node_modules/cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "node_modules/karma/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/karma/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/karma/node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/karma/node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/karma/node_modules/media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/karma/node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/karma/node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/karma/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/karma/node_modules/picomatch": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+      "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/karma/node_modules/raw-body": {
+      "version": "2.5.3",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
+      "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "~3.1.2",
+        "http-errors": "~2.0.1",
+        "iconv-lite": "~0.4.24",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/karma/node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/karma/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/karma/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/karma/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/karma/node_modules/type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/karma/node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/karma/node_modules/yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/karma/node_modules/yargs-parser": {
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/listr2": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz",
+      "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cli-truncate": "^4.0.0",
+        "colorette": "^2.0.20",
+        "eventemitter3": "^5.0.1",
+        "log-update": "^6.1.0",
+        "rfdc": "^1.4.1",
+        "wrap-ansi": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/listr2/node_modules/eventemitter3": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
+      "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/listr2/node_modules/wrap-ansi": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
+      "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "string-width": "^7.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/lmdb": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.2.tgz",
+      "integrity": "sha512-nwVGUfTBUwJKXd6lRV8pFNfnrCC1+l49ESJRM19t/tFb/97QfJEixe5DYRvug5JO7DSFKoKaVy7oGMt5rVqZvg==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "msgpackr": "^1.11.2",
+        "node-addon-api": "^6.1.0",
+        "node-gyp-build-optional-packages": "5.2.2",
+        "ordered-binary": "^1.5.3",
+        "weak-lru-cache": "^1.2.2"
+      },
+      "bin": {
+        "download-lmdb-prebuilds": "bin/download-prebuilds.js"
+      },
+      "optionalDependencies": {
+        "@lmdb/lmdb-darwin-arm64": "3.4.2",
+        "@lmdb/lmdb-darwin-x64": "3.4.2",
+        "@lmdb/lmdb-linux-arm": "3.4.2",
+        "@lmdb/lmdb-linux-arm64": "3.4.2",
+        "@lmdb/lmdb-linux-x64": "3.4.2",
+        "@lmdb/lmdb-win32-arm64": "3.4.2",
+        "@lmdb/lmdb-win32-x64": "3.4.2"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.18.1",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+      "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/log-symbols": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz",
+      "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^5.3.0",
+        "is-unicode-supported": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-symbols/node_modules/is-unicode-supported": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
+      "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-update": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
+      "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-escapes": "^7.0.0",
+        "cli-cursor": "^5.0.0",
+        "slice-ansi": "^7.1.0",
+        "strip-ansi": "^7.1.0",
+        "wrap-ansi": "^9.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-update/node_modules/is-fullwidth-code-point": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz",
+      "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "get-east-asian-width": "^1.3.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-update/node_modules/slice-ansi": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz",
+      "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "is-fullwidth-code-point": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+      }
+    },
+    "node_modules/log-update/node_modules/wrap-ansi": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
+      "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.2.1",
+        "string-width": "^7.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/log4js": {
+      "version": "6.9.1",
+      "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz",
+      "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "date-format": "^4.0.14",
+        "debug": "^4.3.4",
+        "flatted": "^3.2.7",
+        "rfdc": "^1.3.0",
+        "streamroller": "^3.1.5"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.17",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+      "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0"
+      }
+    },
+    "node_modules/make-dir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+      "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "semver": "^7.5.3"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/make-fetch-happen": {
+      "version": "15.0.5",
+      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.5.tgz",
+      "integrity": "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@gar/promise-retry": "^1.0.0",
+        "@npmcli/agent": "^4.0.0",
+        "@npmcli/redact": "^4.0.0",
+        "cacache": "^20.0.1",
+        "http-cache-semantics": "^4.1.1",
+        "minipass": "^7.0.2",
+        "minipass-fetch": "^5.0.0",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "negotiator": "^1.0.0",
+        "proc-log": "^6.0.0",
+        "ssri": "^13.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/make-fetch-happen/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/math-intrinsics": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+      "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/media-typer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+      "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/merge-descriptors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+      "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/mime": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
+      "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.54.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+      "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
+      "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "^1.54.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/mimic-function": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
+      "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+      "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+      "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/minipass-collect": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz",
+      "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.0.3"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/minipass-fetch": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.2.tgz",
+      "integrity": "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "minipass": "^7.0.3",
+        "minipass-sized": "^2.0.0",
+        "minizlib": "^3.0.1"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      },
+      "optionalDependencies": {
+        "iconv-lite": "^0.7.2"
+      }
+    },
+    "node_modules/minipass-flush": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz",
+      "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/minipass-flush/node_modules/minipass": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minipass-flush/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/minipass-pipeline": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+      "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minipass-pipeline/node_modules/minipass": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minipass-pipeline/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/minipass-sized": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz",
+      "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minizlib": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+      "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "minipass": "^7.1.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/mrmime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+      "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/msgpackr": {
+      "version": "1.11.12",
+      "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.12.tgz",
+      "integrity": "sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "optionalDependencies": {
+        "msgpackr-extract": "^3.0.2"
+      }
+    },
+    "node_modules/msgpackr-extract": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
+      "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "node-gyp-build-optional-packages": "5.2.2"
+      },
+      "bin": {
+        "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
+      },
+      "optionalDependencies": {
+        "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
+        "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
+        "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
+        "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
+        "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
+        "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
+      }
+    },
+    "node_modules/mute-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
+      "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.12",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+      "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/negotiator": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+      "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
+      "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/node-gyp": {
+      "version": "12.3.0",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz",
+      "integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "env-paths": "^2.2.0",
+        "exponential-backoff": "^3.1.1",
+        "graceful-fs": "^4.2.6",
+        "nopt": "^9.0.0",
+        "proc-log": "^6.0.0",
+        "semver": "^7.3.5",
+        "tar": "^7.5.4",
+        "tinyglobby": "^0.2.12",
+        "undici": "^6.25.0",
+        "which": "^6.0.0"
+      },
+      "bin": {
+        "node-gyp": "bin/node-gyp.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/node-gyp-build-optional-packages": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
+      "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "detect-libc": "^2.0.1"
+      },
+      "bin": {
+        "node-gyp-build-optional-packages": "bin.js",
+        "node-gyp-build-optional-packages-optional": "optional.js",
+        "node-gyp-build-optional-packages-test": "build-test.js"
+      }
+    },
+    "node_modules/node-gyp/node_modules/isexe": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+      "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/node-gyp/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/node-gyp/node_modules/which": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+      "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^4.0.0"
+      },
+      "bin": {
+        "node-which": "bin/which.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.38",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz",
+      "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/nopt": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz",
+      "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "abbrev": "^4.0.0"
+      },
+      "bin": {
+        "nopt": "bin/nopt.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/npm-bundled": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz",
+      "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "npm-normalize-package-bin": "^5.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-install-checks": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz",
+      "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "semver": "^7.1.1"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-normalize-package-bin": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz",
+      "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-package-arg": {
+      "version": "13.0.0",
+      "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.0.tgz",
+      "integrity": "sha512-+t2etZAGcB7TbbLHfDwooV9ppB2LhhcT6A+L9cahsf9mEUAoQ6CktLEVvEnpD0N5CkX7zJqnPGaFtoQDy9EkHQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "hosted-git-info": "^9.0.0",
+        "proc-log": "^5.0.0",
+        "semver": "^7.3.5",
+        "validate-npm-package-name": "^6.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-packlist": {
+      "version": "10.0.4",
+      "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz",
+      "integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "ignore-walk": "^8.0.0",
+        "proc-log": "^6.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-packlist/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-pick-manifest": {
+      "version": "11.0.3",
+      "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz",
+      "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "npm-install-checks": "^8.0.0",
+        "npm-normalize-package-bin": "^5.0.0",
+        "npm-package-arg": "^13.0.0",
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-registry-fetch": {
+      "version": "19.1.1",
+      "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz",
+      "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@npmcli/redact": "^4.0.0",
+        "jsonparse": "^1.3.1",
+        "make-fetch-happen": "^15.0.0",
+        "minipass": "^7.0.2",
+        "minipass-fetch": "^5.0.0",
+        "minizlib": "^3.0.1",
+        "npm-package-arg": "^13.0.0",
+        "proc-log": "^6.0.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/npm-registry-fetch/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/onetime": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+      "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mimic-function": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ora": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+      "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chalk": "^5.3.0",
+        "cli-cursor": "^5.0.0",
+        "cli-spinners": "^2.9.2",
+        "is-interactive": "^2.0.0",
+        "is-unicode-supported": "^2.0.0",
+        "log-symbols": "^6.0.0",
+        "stdin-discarder": "^0.2.2",
+        "string-width": "^7.2.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ordered-binary": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.1.tgz",
+      "integrity": "sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/p-map": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz",
+      "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/pacote": {
+      "version": "21.0.4",
+      "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.4.tgz",
+      "integrity": "sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "@npmcli/git": "^7.0.0",
+        "@npmcli/installed-package-contents": "^4.0.0",
+        "@npmcli/package-json": "^7.0.0",
+        "@npmcli/promise-spawn": "^9.0.0",
+        "@npmcli/run-script": "^10.0.0",
+        "cacache": "^20.0.0",
+        "fs-minipass": "^3.0.0",
+        "minipass": "^7.0.2",
+        "npm-package-arg": "^13.0.0",
+        "npm-packlist": "^10.0.1",
+        "npm-pick-manifest": "^11.0.1",
+        "npm-registry-fetch": "^19.0.0",
+        "proc-log": "^6.0.0",
+        "promise-retry": "^2.0.1",
+        "sigstore": "^4.0.0",
+        "ssri": "^13.0.0",
+        "tar": "^7.4.3"
+      },
+      "bin": {
+        "pacote": "bin/index.js"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/pacote/node_modules/proc-log": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
+      "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz",
+      "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "entities": "^8.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-html-rewriting-stream": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz",
+      "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "entities": "^6.0.0",
+        "parse5": "^8.0.0",
+        "parse5-sax-parser": "^8.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-html-rewriting-stream/node_modules/entities": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+      "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/parse5-sax-parser": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz",
+      "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parse5": "^8.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5/node_modules/entities": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
+      "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/path-scurry": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+      "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "lru-cache": "^11.0.0",
+        "minipass": "^7.1.2"
+      },
+      "engines": {
+        "node": "18 || 20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/path-scurry/node_modules/lru-cache": {
+      "version": "11.3.6",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
+      "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/path-to-regexp": {
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
+      "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+      "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/piscina": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.3.tgz",
+      "integrity": "sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20.x"
+      },
+      "optionalDependencies": {
+        "@napi-rs/nice": "^1.0.4"
+      }
+    },
+    "node_modules/pkce-challenge": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz",
+      "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=16.20.0"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.14",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
+      "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.11",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-media-query-parser": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+      "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/proc-log": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz",
+      "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/promise-retry": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+      "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "err-code": "^2.0.2",
+        "retry": "^0.12.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/qjobs": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
+      "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.9"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.15.1",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
+      "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
+      "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "bytes": "~3.1.2",
+        "http-errors": "~2.0.1",
+        "iconv-lite": "~0.7.0",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/reflect-metadata": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
+      "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
+      "dev": true,
+      "license": "Apache-2.0"
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/resolve": {
+      "version": "1.22.10",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+      "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-core-module": "^2.16.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/restore-cursor": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+      "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "onetime": "^7.0.0",
+        "signal-exit": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/rfdc": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+      "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "deprecated": "Rimraf versions prior to v4 are no longer supported",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "4.59.0",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
+      "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.8"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.59.0",
+        "@rollup/rollup-android-arm64": "4.59.0",
+        "@rollup/rollup-darwin-arm64": "4.59.0",
+        "@rollup/rollup-darwin-x64": "4.59.0",
+        "@rollup/rollup-freebsd-arm64": "4.59.0",
+        "@rollup/rollup-freebsd-x64": "4.59.0",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
+        "@rollup/rollup-linux-arm-musleabihf": "4.59.0",
+        "@rollup/rollup-linux-arm64-gnu": "4.59.0",
+        "@rollup/rollup-linux-arm64-musl": "4.59.0",
+        "@rollup/rollup-linux-loong64-gnu": "4.59.0",
+        "@rollup/rollup-linux-loong64-musl": "4.59.0",
+        "@rollup/rollup-linux-ppc64-gnu": "4.59.0",
+        "@rollup/rollup-linux-ppc64-musl": "4.59.0",
+        "@rollup/rollup-linux-riscv64-gnu": "4.59.0",
+        "@rollup/rollup-linux-riscv64-musl": "4.59.0",
+        "@rollup/rollup-linux-s390x-gnu": "4.59.0",
+        "@rollup/rollup-linux-x64-gnu": "4.59.0",
+        "@rollup/rollup-linux-x64-musl": "4.59.0",
+        "@rollup/rollup-openbsd-x64": "4.59.0",
+        "@rollup/rollup-openharmony-arm64": "4.59.0",
+        "@rollup/rollup-win32-arm64-msvc": "4.59.0",
+        "@rollup/rollup-win32-ia32-msvc": "4.59.0",
+        "@rollup/rollup-win32-x64-gnu": "4.59.0",
+        "@rollup/rollup-win32-x64-msvc": "4.59.0",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/router": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+      "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.4.0",
+        "depd": "^2.0.0",
+        "is-promise": "^4.0.0",
+        "parseurl": "^1.3.3",
+        "path-to-regexp": "^8.0.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/rxjs": {
+      "version": "7.8.2",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+      "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/safe-regex-test": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+      "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "is-regex": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/sass": {
+      "version": "1.90.0",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz",
+      "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chokidar": "^4.0.0",
+        "immutable": "^5.0.2",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher": "^2.4.1"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.7.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+      "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/send": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
+      "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.4.3",
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "etag": "^1.8.1",
+        "fresh": "^2.0.0",
+        "http-errors": "^2.0.1",
+        "mime-types": "^3.0.2",
+        "ms": "^2.1.3",
+        "on-finished": "^2.4.1",
+        "range-parser": "^1.2.1",
+        "statuses": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/serve-static": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
+      "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "encodeurl": "^2.0.0",
+        "escape-html": "^1.0.3",
+        "parseurl": "^1.3.3",
+        "send": "^1.2.0"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/express"
+      }
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3",
+        "side-channel-list": "^1.0.0",
+        "side-channel-map": "^1.0.1",
+        "side-channel-weakmap": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-list": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+      "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-weakmap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3",
+        "side-channel-map": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/sigstore": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.0.tgz",
+      "integrity": "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@sigstore/bundle": "^4.0.0",
+        "@sigstore/core": "^3.1.0",
+        "@sigstore/protobuf-specs": "^0.5.0",
+        "@sigstore/sign": "^4.1.0",
+        "@sigstore/tuf": "^4.0.1",
+        "@sigstore/verify": "^3.1.0"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/slice-ansi": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
+      "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.0.0",
+        "is-fullwidth-code-point": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+      }
+    },
+    "node_modules/smart-buffer": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+      "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 6.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/socket.io": {
+      "version": "4.8.3",
+      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz",
+      "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "accepts": "~1.3.4",
+        "base64id": "~2.0.0",
+        "cors": "~2.8.5",
+        "debug": "~4.4.1",
+        "engine.io": "~6.6.0",
+        "socket.io-adapter": "~2.5.2",
+        "socket.io-parser": "~4.2.4"
+      },
+      "engines": {
+        "node": ">=10.2.0"
+      }
+    },
+    "node_modules/socket.io-adapter": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz",
+      "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "~4.4.1",
+        "ws": "~8.18.3"
+      }
+    },
+    "node_modules/socket.io-parser": {
+      "version": "4.2.6",
+      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz",
+      "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@socket.io/component-emitter": "~3.1.0",
+        "debug": "~4.4.1"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/socket.io/node_modules/accepts": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/socket.io/node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/socket.io/node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/socket.io/node_modules/negotiator": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/socks": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.8.tgz",
+      "integrity": "sha512-NlGELfPrgX2f1TAAcz0WawlLn+0r3FyhhCRpFFK2CemXenPYvzMWWZINv3eDNo9ucdwme7oCHRY0Jnbs4aIkog==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ip-address": "^10.1.1",
+        "smart-buffer": "^4.2.0"
+      },
+      "engines": {
+        "node": ">= 10.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/socks-proxy-agent": {
+      "version": "8.0.5",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
+      "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "^4.3.4",
+        "socks": "^2.8.3"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.7.6",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+      "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/source-map-support/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/spdx-exceptions": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+      "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+      "dev": true,
+      "license": "CC-BY-3.0"
+    },
+    "node_modules/spdx-expression-parse": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
+      "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "node_modules/spdx-license-ids": {
+      "version": "3.0.23",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz",
+      "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==",
+      "dev": true,
+      "license": "CC0-1.0"
+    },
+    "node_modules/ssri": {
+      "version": "13.0.1",
+      "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz",
+      "integrity": "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "minipass": "^7.0.3"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+      "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/stdin-discarder": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
+      "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/streamroller": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz",
+      "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "date-format": "^4.0.14",
+        "debug": "^4.3.4",
+        "fs-extra": "^8.1.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+      "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^10.3.0",
+        "get-east-asian-width": "^1.0.0",
+        "strip-ansi": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+      "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.2.2"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/tar": {
+      "version": "7.5.14",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.14.tgz",
+      "integrity": "sha512-/7sHKgQO3JLP9ESlwTYUUftHUadOURUqq23xs1vjcnp8Vss6k0wCfzulyEtk5g91pjvnuriimGlyG7k6msrzRw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "@isaacs/fs-minipass": "^4.0.0",
+        "chownr": "^3.0.0",
+        "minipass": "^7.1.2",
+        "minizlib": "^3.1.0",
+        "yallist": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tar/node_modules/yallist": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+      "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.14",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
+      "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.4.4",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
+      "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "license": "0BSD"
+    },
+    "node_modules/tuf-js": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.1.0.tgz",
+      "integrity": "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@tufjs/models": "4.1.0",
+        "debug": "^4.4.3",
+        "make-fetch-happen": "^15.0.1"
+      },
+      "engines": {
+        "node": "^20.17.0 || >=22.9.0"
+      }
+    },
+    "node_modules/type-is": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+      "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "content-type": "^1.0.5",
+        "media-typer": "^1.1.0",
+        "mime-types": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.8.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+      "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/ua-parser-js": {
+      "version": "0.7.41",
+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz",
+      "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/ua-parser-js"
+        },
+        {
+          "type": "paypal",
+          "url": "https://paypal.me/faisalman"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/faisalman"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "ua-parser-js": "script/cli.js"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/undici": {
+      "version": "6.25.0",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz",
+      "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18.17"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "7.19.2",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
+      "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "escalade": "^3.2.0",
+        "picocolors": "^1.1.1"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/validate-npm-package-name": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz",
+      "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^18.17.0 || >=20.5.0"
+      }
+    },
+    "node_modules/vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/vite": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz",
+      "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.27.0",
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.3",
+        "postcss": "^8.5.6",
+        "rollup": "^4.43.0",
+        "tinyglobby": "^0.2.15"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^20.19.0 || >=22.12.0",
+        "jiti": ">=1.21.0",
+        "less": "^4.0.0",
+        "lightningcss": "^1.21.0",
+        "sass": "^1.70.0",
+        "sass-embedded": "^1.70.0",
+        "stylus": ">=0.54.8",
+        "sugarss": "^5.0.0",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/aix-ppc64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
+      "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/android-arm": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
+      "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/android-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
+      "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/android-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
+      "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
+      "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/darwin-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
+      "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
+      "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
+      "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-arm": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
+      "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
+      "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-ia32": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
+      "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-loong64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
+      "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
+      "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
+      "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
+      "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-s390x": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
+      "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/linux-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
+      "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
+      "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
+      "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
+      "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
+      "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/openharmony-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
+      "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/sunos-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
+      "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/win32-arm64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
+      "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/win32-ia32": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
+      "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/@esbuild/win32-x64": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
+      "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/vite/node_modules/esbuild": {
+      "version": "0.27.7",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
+      "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.27.7",
+        "@esbuild/android-arm": "0.27.7",
+        "@esbuild/android-arm64": "0.27.7",
+        "@esbuild/android-x64": "0.27.7",
+        "@esbuild/darwin-arm64": "0.27.7",
+        "@esbuild/darwin-x64": "0.27.7",
+        "@esbuild/freebsd-arm64": "0.27.7",
+        "@esbuild/freebsd-x64": "0.27.7",
+        "@esbuild/linux-arm": "0.27.7",
+        "@esbuild/linux-arm64": "0.27.7",
+        "@esbuild/linux-ia32": "0.27.7",
+        "@esbuild/linux-loong64": "0.27.7",
+        "@esbuild/linux-mips64el": "0.27.7",
+        "@esbuild/linux-ppc64": "0.27.7",
+        "@esbuild/linux-riscv64": "0.27.7",
+        "@esbuild/linux-s390x": "0.27.7",
+        "@esbuild/linux-x64": "0.27.7",
+        "@esbuild/netbsd-arm64": "0.27.7",
+        "@esbuild/netbsd-x64": "0.27.7",
+        "@esbuild/openbsd-arm64": "0.27.7",
+        "@esbuild/openbsd-x64": "0.27.7",
+        "@esbuild/openharmony-arm64": "0.27.7",
+        "@esbuild/sunos-x64": "0.27.7",
+        "@esbuild/win32-arm64": "0.27.7",
+        "@esbuild/win32-ia32": "0.27.7",
+        "@esbuild/win32-x64": "0.27.7"
+      }
+    },
+    "node_modules/vite/node_modules/tinyglobby": {
+      "version": "0.2.16",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+      "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/void-elements": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
+      "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/watchpack": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
+      "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.1.2"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/weak-lru-cache": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz",
+      "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/ws": {
+      "version": "8.18.3",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+      "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/yargs": {
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
+      "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^9.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "string-width": "^7.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^22.0.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=23"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "22.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
+      "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=23"
+      }
+    },
+    "node_modules/yoctocolors-cjs": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz",
+      "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/zod": {
+      "version": "4.1.13",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz",
+      "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/colinhacks"
+      }
+    },
+    "node_modules/zod-to-json-schema": {
+      "version": "3.25.2",
+      "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz",
+      "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==",
+      "dev": true,
+      "license": "ISC",
+      "peerDependencies": {
+        "zod": "^3.25.28 || ^4"
+      }
+    },
+    "node_modules/zone.js": {
+      "version": "0.15.1",
+      "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz",
+      "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==",
+      "license": "MIT"
+    }
+  }
+}

+ 48 - 0
package.json

@@ -0,0 +1,48 @@
+{
+  "name": "tihao-ai",
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "ng": "ng",
+    "start": "ng serve",
+    "api": "node server/server.ts",
+    "build": "ng build",
+    "watch": "ng build --watch --configuration development",
+    "test": "ng test"
+  },
+  "prettier": {
+    "overrides": [
+      {
+        "files": "*.html",
+        "options": {
+          "parser": "angular"
+        }
+      }
+    ]
+  },
+  "private": true,
+  "dependencies": {
+    "@angular/common": "^20.0.0",
+    "@angular/compiler": "^20.0.0",
+    "@angular/core": "^20.0.0",
+    "@angular/forms": "^20.0.0",
+    "@angular/platform-browser": "^20.0.0",
+    "@angular/router": "^20.0.0",
+    "rxjs": "~7.8.0",
+    "tslib": "^2.3.0",
+    "zone.js": "~0.15.0"
+  },
+  "devDependencies": {
+    "@angular/build": "^20.0.4",
+    "@angular/cli": "^20.0.4",
+    "@angular/compiler-cli": "^20.0.0",
+    "@types/jasmine": "~5.1.0",
+    "jasmine-core": "~5.7.0",
+    "karma": "~6.4.0",
+    "karma-chrome-launcher": "~3.2.0",
+    "karma-coverage": "~2.2.0",
+    "karma-jasmine": "~5.1.0",
+    "karma-jasmine-html-reporter": "~2.1.0",
+    "typescript": "~5.8.2"
+  }
+}

BIN
public/favicon.ico


+ 213 - 0
server/server.ts

@@ -0,0 +1,213 @@
+import { createServer, IncomingMessage, ServerResponse } from 'node:http';
+
+type JsonValue = Record<string, unknown> | Array<unknown>;
+
+interface Candidate {
+  platform: string;
+  name: string;
+  fans: string;
+  price: number;
+  score: number;
+  styleMatch: number;
+  status: string;
+  reason: string;
+  risk: string;
+}
+
+const port = Number(process.env.TIHAO_AI_API_PORT ?? 4300);
+
+const demoRequirements = [
+  { label: '客户/品牌', value: '客户A / 新锐护肤品牌', confidence: 96 },
+  { label: '投放目标', value: '新品种草、真实测评、站内转化蓄水', confidence: 92 },
+  { label: '平台需求', value: '小红书 20人、抖音 8人、B站 4人', confidence: 90 },
+  { label: '内容风格', value: '真实体验、通勤生活、轻专业成分党', confidence: 88 }
+];
+
+const demoRules = [
+  '按 Brief 平台优先提号',
+  '默认推荐数量不少于需求 3 倍',
+  '风格匹配低于 80% 自动降级',
+  '黑名单与低配合度剔除',
+  '优先近期采集有效价格'
+];
+
+const demoCandidates: Candidate[] = [
+  {
+    platform: '小红书',
+    name: '梨涡测评室',
+    fans: '18.6万',
+    price: 6800,
+    score: 94,
+    styleMatch: 91,
+    status: '强推荐',
+    reason: '近10篇中 9 篇为真实体验或成分拆解,互动中位数高于同价位账号 28%。',
+    risk: '视频内容偏少,可作为图文主推。'
+  },
+  {
+    platform: '抖音',
+    name: '林小林认真护肤',
+    fans: '42.1万',
+    price: 12800,
+    score: 87,
+    styleMatch: 82,
+    status: '备选',
+    reason: '爆文率和完播率表现稳定,预算接近上限,建议作为抖音头部备选。',
+    risk: '单条报价较高,需确认档期。'
+  }
+];
+
+function sendJson(response: ServerResponse, statusCode: number, payload: JsonValue): void {
+  const body = JSON.stringify(payload);
+  response.writeHead(statusCode, {
+    'Access-Control-Allow-Origin': '*',
+    'Access-Control-Allow-Headers': 'Content-Type',
+    'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',
+    'Content-Type': 'application/json; charset=utf-8',
+    'Content-Length': Buffer.byteLength(body)
+  });
+  response.end(body);
+}
+
+function sendExcel(response: ServerResponse, filename: string, candidates: Candidate[]): void {
+  const rows = candidates
+    .map(
+      (candidate) => `
+        <tr>
+          <td>${escapeHtml(candidate.platform)}</td>
+          <td>${escapeHtml(candidate.name)}</td>
+          <td>${escapeHtml(candidate.fans)}</td>
+          <td>${candidate.price}</td>
+          <td>${candidate.score}</td>
+          <td>${candidate.styleMatch}%</td>
+          <td>${escapeHtml(candidate.status)}</td>
+          <td>${escapeHtml(candidate.reason)}</td>
+          <td>${escapeHtml(candidate.risk)}</td>
+        </tr>`
+    )
+    .join('');
+
+  const body = `
+    <html>
+      <head>
+        <meta charset="UTF-8">
+        <style>
+          table { border-collapse: collapse; font-family: "Microsoft YaHei", Arial, sans-serif; }
+          th { background: #1f8a70; color: #fff; }
+          th, td { border: 1px solid #cfd7d1; padding: 8px 10px; }
+          td:nth-child(5), td:nth-child(6) { background: #eef7f3; font-weight: 700; }
+        </style>
+      </head>
+      <body>
+        <table>
+          <tr>
+            <th>平台</th><th>账号</th><th>粉丝量</th><th>报价</th><th>综合分</th><th>风格匹配</th><th>推荐状态</th><th>推荐理由</th><th>风险提示</th>
+          </tr>
+          ${rows}
+        </table>
+      </body>
+    </html>`;
+
+  response.writeHead(200, {
+    'Access-Control-Allow-Origin': '*',
+    'Content-Type': 'application/vnd.ms-excel; charset=utf-8',
+    'Content-Disposition': `attachment; filename="${encodeURIComponent(filename)}"`,
+    'Content-Length': Buffer.byteLength(body)
+  });
+  response.end(body);
+}
+
+function readBody(request: IncomingMessage): Promise<Record<string, unknown>> {
+  return new Promise((resolve) => {
+    let body = '';
+    request.on('data', (chunk) => {
+      body += chunk;
+    });
+    request.on('end', () => {
+      if (!body) {
+        resolve({});
+        return;
+      }
+
+      try {
+        resolve(JSON.parse(body));
+      } catch {
+        resolve({});
+      }
+    });
+  });
+}
+
+function escapeHtml(value: string): string {
+  return value
+    .replaceAll('&', '&amp;')
+    .replaceAll('<', '&lt;')
+    .replaceAll('>', '&gt;')
+    .replaceAll('"', '&quot;');
+}
+
+const server = createServer(async (request, response) => {
+  const requestUrl = new URL(request.url ?? '/', `http://${request.headers.host ?? 'localhost'}`);
+
+  if (request.method === 'OPTIONS') {
+    sendJson(response, 200, { ok: true });
+    return;
+  }
+
+  if (request.method === 'GET' && requestUrl.pathname === '/api/health') {
+    sendJson(response, 200, {
+      ok: true,
+      name: '提号AI Mock API',
+      resourcesPath: 'D:\\公司优秀媒体资源库\\4月份资源库'
+    });
+    return;
+  }
+
+  if (request.method === 'POST' && requestUrl.pathname === '/api/analyze-brief') {
+    sendJson(response, 200, {
+      requirements: demoRequirements,
+      rules: demoRules,
+      message: 'Demo 已模拟解析 Brief,真实环境会接入 Excel/Docx 解析与 LLM 抽取。'
+    });
+    return;
+  }
+
+  if (request.method === 'POST' && requestUrl.pathname === '/api/recommend') {
+    sendJson(response, 200, {
+      candidates: demoCandidates,
+      totalPool: 104,
+      message: 'Demo 已模拟按规则生成推荐池。'
+    });
+    return;
+  }
+
+  if (request.method === 'POST' && requestUrl.pathname === '/api/rules/learn') {
+    sendJson(response, 200, {
+      suggestions: [
+        {
+          title: '小红书减少泛美妆号,优先生活方式和通勤场景',
+          confidence: 93
+        },
+        {
+          title: '抖音预算压低时保留爆文率高账号',
+          confidence: 87
+        }
+      ]
+    });
+    return;
+  }
+
+  if (request.method === 'POST' && requestUrl.pathname === '/api/recommendations/export') {
+    const body = await readBody(request);
+    const candidates = Array.isArray(body['candidates'])
+      ? (body['candidates'] as Candidate[])
+      : demoCandidates;
+    sendExcel(response, '客户A-新锐护肤品牌-需求推荐名单.xls', candidates);
+    return;
+  }
+
+  sendJson(response, 404, { ok: false, message: 'Not found' });
+});
+
+server.listen(port, () => {
+  console.log(`Tihao AI mock API listening on http://localhost:${port}`);
+});

+ 12 - 0
src/app/app.config.ts

@@ -0,0 +1,12 @@
+import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';
+import { provideRouter } from '@angular/router';
+
+import { routes } from './app.routes';
+
+export const appConfig: ApplicationConfig = {
+  providers: [
+    provideBrowserGlobalErrorListeners(),
+    provideZoneChangeDetection({ eventCoalescing: true }),
+    provideRouter(routes)
+  ]
+};

+ 66 - 0
src/app/app.html

@@ -0,0 +1,66 @@
+<div class="app-shell">
+  <aside class="sidebar">
+    <div class="brand">
+      <div class="brand-mark">提</div>
+      <div>
+        <h1>提号AI</h1>
+        <p>Brief 到名单交付工作台</p>
+      </div>
+    </div>
+
+    <nav class="side-nav" aria-label="主导航">
+      <button
+        type="button"
+        *ngFor="let item of state.visibleNavItems"
+        [class.active]="state.activeView === item.key"
+        (click)="state.setView(item.key)"
+      >
+        <span>{{ item.label }}</span>
+        <small>{{ item.note }}</small>
+      </button>
+    </nav>
+
+    <button type="button" class="nav-mode-button" (click)="state.toggleSimpleMode()">
+      {{ state.simpleMode ? '显示完整业务模块' : '切回商务简洁模式' }}
+    </button>
+
+    <div class="sidebar-footer">
+      <span class="status-dot"></span>
+      <div>
+        <strong>Demo 模式</strong>
+        <small>{{ state.apiState }}</small>
+      </div>
+    </div>
+  </aside>
+
+  <main class="main">
+    <header class="topbar utility-topbar">
+      <div>
+        <p class="eyebrow">当前任务</p>
+        <h2>{{ state.taskDisplayName }}</h2>
+      </div>
+      <div class="topbar-status">
+        <span>{{ state.activeNavItem.label }}</span>
+        <span>流程 {{ state.currentStep }}/{{ state.steps.length }} · {{ state.steps[state.currentStep - 1].label }}</span>
+        <span>交付准备度 {{ state.exportReadiness }}%</span>
+      </div>
+      <div class="topbar-actions">
+        <button type="button" class="ghost-button" (click)="state.backToWorkflow()" title="回到提号工作台">回到工作台</button>
+        <button type="button" class="ghost-button" (click)="state.toggleSimpleMode()" title="切换简洁或完整模式">
+          {{ state.simpleMode ? '完整模式' : '简洁模式' }}
+        </button>
+      </div>
+    </header>
+
+    <ng-container [ngSwitch]="state.activeView">
+      <app-workspace-page *ngSwitchCase="'workspace'"></app-workspace-page>
+      <app-creator-search-page *ngSwitchCase="'creatorSearch'"></app-creator-search-page>
+      <app-delivery-page *ngSwitchCase="'delivery'"></app-delivery-page>
+      <app-tasks-page *ngSwitchCase="'tasks'"></app-tasks-page>
+      <app-resources-page *ngSwitchCase="'resources'"></app-resources-page>
+      <app-rules-page *ngSwitchCase="'rules'"></app-rules-page>
+      <app-learning-page *ngSwitchCase="'learning'"></app-learning-page>
+      <app-templates-page *ngSwitchCase="'templates'"></app-templates-page>
+    </ng-container>
+  </main>
+</div>

+ 3 - 0
src/app/app.routes.ts

@@ -0,0 +1,3 @@
+import { Routes } from '@angular/router';
+
+export const routes: Routes = [];

+ 3415 - 0
src/app/app.scss

@@ -0,0 +1,3415 @@
+app-root {
+  display: block;
+  min-height: 100vh;
+  color: #1f2528;
+  background: #f4f5f1;
+}
+
+button,
+input,
+textarea {
+  font: inherit;
+}
+
+button {
+  cursor: pointer;
+}
+
+.app-shell {
+  display: grid;
+  grid-template-columns: 280px minmax(0, 1fr);
+  min-height: 100vh;
+}
+
+.sidebar {
+  position: sticky;
+  top: 0;
+  height: 100vh;
+  padding: 24px 18px;
+  background: #26312f;
+  color: #f8faf7;
+  display: flex;
+  flex-direction: column;
+  gap: 24px;
+}
+
+.brand {
+  display: flex;
+  gap: 14px;
+  align-items: center;
+}
+
+.brand-mark {
+  width: 46px;
+  height: 46px;
+  border-radius: 8px;
+  display: grid;
+  place-items: center;
+  background: #f3c969;
+  color: #26312f;
+  font-weight: 800;
+  font-size: 22px;
+}
+
+.brand h1,
+.brand p,
+.topbar h2,
+.topbar p,
+h3,
+h4,
+p {
+  margin: 0;
+}
+
+.brand h1 {
+  font-size: 20px;
+}
+
+.brand p,
+.sidebar-footer small,
+.side-nav small {
+  color: #cad3cb;
+}
+
+.side-nav {
+  display: grid;
+  gap: 8px;
+}
+
+.side-nav button {
+  border: 0;
+  border-radius: 8px;
+  padding: 13px 14px;
+  color: #f8faf7;
+  background: transparent;
+  text-align: left;
+  display: grid;
+  gap: 4px;
+}
+
+.side-nav button:hover,
+.side-nav button.active {
+  background: #34423f;
+}
+
+.side-nav span {
+  font-weight: 700;
+}
+
+.side-nav small {
+  font-size: 12px;
+}
+
+.nav-mode-button {
+  border: 1px solid #44534f;
+  border-radius: 8px;
+  min-height: 40px;
+  padding: 0 12px;
+  background: #31403c;
+  color: #f8faf7;
+  font-weight: 800;
+}
+
+.nav-mode-button:hover {
+  background: #3c4d49;
+}
+
+.sidebar-footer {
+  margin-top: auto;
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  padding: 14px;
+  border: 1px solid #44534f;
+  border-radius: 8px;
+}
+
+.status-dot {
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  background: #5dd39e;
+}
+
+.main {
+  min-width: 0;
+  padding: 24px;
+}
+
+.topbar,
+.section-heading,
+.panel-heading {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 16px;
+}
+
+.topbar {
+  padding: 10px 0 22px;
+}
+
+.topbar h2 {
+  margin-top: 4px;
+  font-size: 24px;
+  line-height: 1.3;
+}
+
+.utility-topbar {
+  position: sticky;
+  top: 0;
+  z-index: 20;
+  margin: -24px -24px 18px;
+  padding: 14px 24px;
+  border-bottom: 1px solid #dfe4dc;
+  background: rgba(244, 245, 241, 0.96);
+  backdrop-filter: blur(10px);
+}
+
+.utility-topbar h2 {
+  font-size: 18px;
+  line-height: 1.25;
+}
+
+.topbar-status {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+  flex-wrap: wrap;
+  justify-content: center;
+}
+
+.topbar-status span {
+  border: 1px solid #dfe4dc;
+  border-radius: 999px;
+  background: #fff;
+  color: #4d5b56;
+  padding: 7px 10px;
+  font-size: 12px;
+  font-weight: 800;
+  white-space: nowrap;
+}
+
+.eyebrow {
+  color: #6f7b76;
+  font-size: 12px;
+  font-weight: 800;
+  letter-spacing: 0;
+}
+
+.topbar-actions {
+  display: flex;
+  gap: 10px;
+}
+
+.primary-button,
+.ghost-button,
+.text-button,
+.icon-button {
+  border-radius: 8px;
+  border: 1px solid transparent;
+  min-height: 38px;
+  padding: 0 14px;
+  font-weight: 800;
+}
+
+.primary-button {
+  background: #1f8a70;
+  color: #fff;
+}
+
+.primary-button:hover {
+  background: #176d59;
+}
+
+.primary-button.compact {
+  min-height: 34px;
+}
+
+.ghost-button {
+  background: #fff;
+  color: #26312f;
+  border-color: #d9dfd7;
+}
+
+.text-button {
+  background: transparent;
+  color: #1f8a70;
+  padding: 0;
+  min-height: auto;
+}
+
+.icon-button {
+  width: 38px;
+  padding: 0;
+  background: #edf1ee;
+  color: #26312f;
+  border-color: #d9dfd7;
+}
+
+.stepper {
+  display: grid;
+  grid-template-columns: repeat(6, minmax(0, 1fr));
+  gap: 8px;
+  margin-bottom: 16px;
+}
+
+.step {
+  min-height: 66px;
+  padding: 12px;
+  border-radius: 8px;
+  background: #fff;
+  border: 1px solid #dfe4dc;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.step span {
+  width: 26px;
+  height: 26px;
+  border-radius: 50%;
+  display: grid;
+  place-items: center;
+  background: #e8ece7;
+  color: #67716d;
+  font-weight: 800;
+}
+
+.step.done span,
+.step.active span {
+  background: #1f8a70;
+  color: #fff;
+}
+
+.step.active {
+  border-color: #1f8a70;
+}
+
+.summary-band {
+  display: grid;
+  grid-template-columns: 1.1fr 0.8fr 0.8fr 1.2fr;
+  gap: 1px;
+  overflow: hidden;
+  border-radius: 8px;
+  border: 1px solid #dfe4dc;
+  background: #dfe4dc;
+  margin-bottom: 16px;
+}
+
+.summary-band div {
+  background: #fff;
+  padding: 16px;
+}
+
+.summary-band p,
+.metric-row span,
+.score-panel span,
+.path-box span,
+.candidate-card small,
+.rule-card small,
+.activity-list small {
+  color: #6f7b76;
+}
+
+.summary-band strong {
+  display: block;
+  margin-top: 4px;
+}
+
+.business-assistant {
+  display: grid;
+  grid-template-columns: minmax(260px, 0.8fr) minmax(320px, 1fr) minmax(360px, 1.15fr);
+  gap: 14px;
+  margin-bottom: 16px;
+}
+
+.next-action-card,
+.business-checklist-card,
+.shortcut-card {
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 16px;
+}
+
+.next-action-card {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) auto;
+  gap: 14px;
+  align-items: center;
+  background: #f1faf6;
+  border-color: #b8ded2;
+}
+
+.next-action-card h3 {
+  margin: 3px 0 5px;
+  font-size: 20px;
+}
+
+.next-action-card small,
+.business-checklist small,
+.shortcut-grid small {
+  color: #6f7b76;
+  line-height: 1.45;
+}
+
+.business-checklist {
+  display: grid;
+  gap: 8px;
+  margin-top: 10px;
+}
+
+.business-checklist button {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  min-height: 54px;
+  padding: 9px;
+  display: grid;
+  grid-template-columns: 26px minmax(0, 1fr);
+  gap: 9px;
+  text-align: left;
+  align-items: center;
+}
+
+.business-checklist button.done {
+  border-color: #b8ded2;
+  background: #f6fbf8;
+}
+
+.business-checklist button > span {
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  display: grid;
+  place-items: center;
+  background: #edf1ee;
+  color: #6f7b76;
+  font-weight: 900;
+}
+
+.business-checklist button.done > span {
+  background: #1f8a70;
+  color: #fff;
+}
+
+.business-checklist div,
+.shortcut-grid button {
+  min-width: 0;
+}
+
+.shortcut-grid {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 8px;
+  margin-top: 10px;
+}
+
+.shortcut-grid button {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 11px;
+  text-align: left;
+  display: grid;
+  gap: 5px;
+}
+
+.shortcut-grid button:hover {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.simple-mode .recommendation-area {
+  border-color: #cadfd7;
+}
+
+.workspace-grid {
+  display: grid;
+  grid-template-columns: 0.9fr 1.1fr;
+  gap: 16px;
+  align-items: start;
+}
+
+.panel,
+.recommendation-area,
+.learning-area,
+.plain-view {
+  background: #fff;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+}
+
+.panel {
+  padding: 18px;
+}
+
+.panel-heading {
+  margin-bottom: 16px;
+}
+
+.panel-heading h3,
+.section-heading h3 {
+  margin-top: 2px;
+  font-size: 18px;
+}
+
+.upload-box {
+  min-height: 190px;
+  border: 1px dashed #aab5ae;
+  border-radius: 8px;
+  background: #f9faf7;
+  display: grid;
+  place-items: center;
+  gap: 8px;
+  text-align: center;
+  padding: 20px;
+  cursor: pointer;
+}
+
+.upload-box input {
+  display: none;
+}
+
+.upload-icon {
+  width: 42px;
+  height: 42px;
+  border-radius: 50%;
+  background: #dfeee9;
+  color: #1f8a70;
+  display: grid;
+  place-items: center;
+  font-size: 26px;
+}
+
+.upload-box small {
+  color: #6f7b76;
+}
+
+.template-strip {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-top: 12px;
+}
+
+.template-strip button,
+.tag-row span,
+.rule-category {
+  border: 1px solid #dfe4dc;
+  border-radius: 999px;
+  background: #fff;
+  color: #4d5b56;
+  padding: 6px 10px;
+  font-size: 12px;
+  font-weight: 700;
+}
+
+.requirement-list,
+.rule-list,
+.activity-list,
+.learned-list,
+.rule-management,
+.template-grid {
+  display: grid;
+  gap: 10px;
+}
+
+.requirement-item {
+  display: grid;
+  grid-template-columns: auto minmax(0, 1fr) auto;
+  gap: 10px;
+  align-items: center;
+  padding: 12px;
+  border: 1px solid #e4e8e1;
+  border-radius: 8px;
+}
+
+.requirement-item span {
+  display: grid;
+  gap: 3px;
+  min-width: 0;
+}
+
+.requirement-item small {
+  color: #6f7b76;
+  overflow-wrap: anywhere;
+}
+
+.requirement-item em {
+  font-style: normal;
+  color: #4461a8;
+  font-weight: 800;
+}
+
+.rules-panel,
+.engine-panel {
+  grid-column: span 1;
+}
+
+.rule-card {
+  display: flex;
+  justify-content: space-between;
+  gap: 14px;
+  padding: 13px;
+  border: 1px solid #e4e8e1;
+  border-radius: 8px;
+}
+
+.rule-card h4 {
+  margin: 6px 0 5px;
+  font-size: 15px;
+}
+
+.rule-card p {
+  color: #4d5b56;
+  line-height: 1.5;
+}
+
+.toggle {
+  flex: 0 0 44px;
+  width: 44px;
+  height: 24px;
+  padding: 2px;
+  border-radius: 999px;
+  border: 0;
+  background: #cfd7d1;
+}
+
+.toggle span {
+  width: 20px;
+  height: 20px;
+  border-radius: 50%;
+  background: #fff;
+  display: block;
+  transition: transform 0.15s ease;
+}
+
+.toggle.on {
+  background: #1f8a70;
+}
+
+.toggle.on span {
+  transform: translateX(20px);
+}
+
+.activity-list article {
+  display: grid;
+  grid-template-columns: 68px minmax(0, 1fr);
+  gap: 10px;
+  align-items: center;
+  padding: 12px;
+  border: 1px solid #e4e8e1;
+  border-radius: 8px;
+}
+
+.activity-list article.running {
+  border-color: #d56a52;
+}
+
+.activity-list span {
+  color: #d56a52;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.activity-list div {
+  display: grid;
+  gap: 4px;
+}
+
+.recommendation-area,
+.learning-area,
+.plain-view {
+  margin-top: 16px;
+  padding: 18px;
+}
+
+.page-hero {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) auto;
+  gap: 18px;
+  align-items: center;
+  margin-bottom: 16px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 18px;
+}
+
+.page-hero h2 {
+  margin: 4px 0 5px;
+  color: #18211f;
+  font-size: 26px;
+  line-height: 1.2;
+}
+
+.page-hero small {
+  color: #6f7b76;
+  line-height: 1.45;
+}
+
+.page-hero-copy {
+  min-width: 0;
+}
+
+.page-guide {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-top: 13px;
+}
+
+.page-guide span {
+  display: inline-flex;
+  align-items: center;
+  gap: 7px;
+  max-width: 100%;
+  border: 1px solid #dfe4dc;
+  border-radius: 999px;
+  background: #f9faf7;
+  color: #4d5b56;
+  padding: 7px 10px;
+  font-size: 12px;
+  font-weight: 700;
+}
+
+.page-guide b {
+  color: #1f8a70;
+}
+
+.page-actions {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  flex-wrap: wrap;
+  justify-content: flex-end;
+}
+
+.segmented-actions {
+  padding: 4px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #f5f7f3;
+}
+
+.segmented-actions .ghost-button {
+  background: transparent;
+  border-color: transparent;
+}
+
+.segmented-actions .ghost-button.active {
+  color: #1f8a70;
+  background: #fff;
+  border-color: #dfe4dc;
+}
+
+.candidate-check input {
+  display: none;
+}
+
+.candidate-check span {
+  width: 18px;
+  height: 18px;
+  display: block;
+  border: 2px solid #aab5ae;
+  border-radius: 5px;
+}
+
+.candidate-check input:checked + span {
+  border-color: #1f8a70;
+  background: #1f8a70;
+}
+
+.avatar {
+  width: 42px;
+  height: 42px;
+  border-radius: 50%;
+  display: grid;
+  place-items: center;
+  background: #e8ece7;
+  color: #26312f;
+  font-weight: 900;
+}
+
+.tag-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6px;
+}
+
+.risk {
+  color: #9f3e2c;
+}
+
+.learning-grid {
+  display: grid;
+  grid-template-columns: minmax(280px, 0.9fr) minmax(0, 1.1fr);
+  gap: 14px;
+  margin-top: 14px;
+}
+
+.learning-grid.standalone {
+  margin-top: 0;
+}
+
+textarea {
+  width: 100%;
+  min-height: 190px;
+  resize: vertical;
+  border: 1px solid #d9dfd7;
+  border-radius: 8px;
+  padding: 14px;
+  color: #26312f;
+  background: #fafbf8;
+}
+
+.learned-list article,
+.template-grid article,
+.resource-grid article {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  padding: 14px;
+}
+
+.learned-list p,
+.template-grid p {
+  color: #4d5b56;
+  line-height: 1.5;
+  margin: 6px 0 10px;
+}
+
+.data-table {
+  display: grid;
+  margin-top: 14px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.table-head,
+.table-row {
+  display: grid;
+  grid-template-columns: 1fr 1.4fr 0.8fr 1.2fr;
+  gap: 12px;
+  padding: 13px 14px;
+  align-items: center;
+}
+
+.table-head {
+  background: #edf1ee;
+  font-weight: 800;
+}
+
+.table-row + .table-row {
+  border-top: 1px solid #e4e8e1;
+}
+
+.path-box {
+  display: grid;
+  gap: 4px;
+  padding: 14px;
+  margin: 14px 0;
+  background: #f5f7f3;
+  border-radius: 8px;
+}
+
+.resource-grid,
+.template-grid {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 12px;
+}
+
+.resource-grid article {
+  display: grid;
+  gap: 8px;
+}
+
+.resource-grid span,
+.template-grid span {
+  color: #4461a8;
+  font-weight: 800;
+  font-size: 12px;
+}
+
+.progress {
+  height: 8px;
+  border-radius: 999px;
+  background: #e4e8e1;
+  overflow: hidden;
+}
+
+.progress i {
+  height: 100%;
+  display: block;
+  background: #1f8a70;
+}
+
+.rule-management article {
+  display: grid;
+  grid-template-columns: 88px minmax(0, 1fr) 120px 72px;
+  gap: 12px;
+  align-items: center;
+  padding: 14px;
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+}
+
+.rule-management p {
+  color: #4d5b56;
+  margin-top: 4px;
+}
+
+.rule-management em {
+  font-style: normal;
+  color: #d56a52;
+  font-weight: 800;
+}
+
+.muted {
+  color: #6f7b76;
+}
+
+.step {
+  color: inherit;
+  text-align: left;
+}
+
+.workspace-grid.extended {
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.panel-actions {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.ghost-button.compact {
+  min-height: 34px;
+}
+
+.review-strip {
+  display: grid;
+  grid-template-columns: repeat(5, minmax(0, 1fr));
+  gap: 10px;
+  margin-bottom: 16px;
+}
+
+.review-strip article,
+.task-board article,
+.sampling-list article,
+.mapping-grid article {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 12px;
+}
+
+.review-strip article {
+  display: grid;
+  gap: 6px;
+}
+
+.review-strip span {
+  width: fit-content;
+  border-radius: 999px;
+  padding: 4px 8px;
+  color: #9f3e2c;
+  background: #fce1dc;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.review-strip span.done {
+  color: #176d59;
+  background: #dfeee9;
+}
+
+.review-strip small,
+.sampling-list small,
+.sampling-list p,
+.task-board header span,
+.task-board small,
+.mapping-grid small,
+.section-mini-head small,
+.detail-head small,
+.detail-block small,
+.note-list button small,
+.note-detail p,
+.ai-reason p,
+.note-meta {
+  color: #6f7b76;
+}
+
+.requirement-item.editable {
+  grid-template-columns: auto minmax(0, 1fr) auto auto;
+}
+
+.requirement-item span input,
+.temp-rule-box input,
+.filter-bar input,
+.filter-bar select {
+  width: 100%;
+  border: 1px solid #d9dfd7;
+  border-radius: 8px;
+  padding: 9px 10px;
+  background: #fff;
+  color: #26312f;
+}
+
+.requirement-item span em {
+  color: #8b6b18;
+  font-size: 12px;
+  font-style: normal;
+}
+
+.requirement-item b {
+  color: #4461a8;
+}
+
+.compact-list {
+  max-height: 390px;
+  overflow: auto;
+  padding-right: 4px;
+}
+
+.temp-rule-box {
+  display: grid;
+  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto;
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+.temp-rule-box.full {
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  margin: 14px 0;
+}
+
+.temp-rule-box label {
+  display: grid;
+  gap: 6px;
+  color: #6f7b76;
+  font-weight: 700;
+  font-size: 12px;
+}
+
+.sampling-list {
+  display: grid;
+  gap: 10px;
+  margin-top: 14px;
+}
+
+.sampling-list article {
+  display: grid;
+  gap: 8px;
+}
+
+.sampling-list header,
+.task-board header,
+.task-board div,
+.section-mini-head,
+.detail-head,
+.learned-list header {
+  display: flex;
+  justify-content: space-between;
+  gap: 10px;
+}
+
+.filter-bar {
+  display: grid;
+  grid-template-columns: 160px 160px minmax(240px, 1fr) 160px;
+  gap: 10px;
+  margin-top: 14px;
+  padding: 12px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #f9faf7;
+}
+
+.filter-bar label {
+  display: grid;
+  gap: 6px;
+  color: #6f7b76;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.recommendation-layout {
+  display: grid;
+  grid-template-columns: minmax(360px, 0.85fr) minmax(0, 1.15fr);
+  gap: 14px;
+  margin-top: 14px;
+  align-items: start;
+}
+
+.recommendation-list {
+  display: grid;
+  gap: 10px;
+}
+
+.candidate-row {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  padding: 12px;
+  display: grid;
+  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
+  gap: 10px;
+  align-items: center;
+  background: #fff;
+  cursor: pointer;
+}
+
+.candidate-row.active {
+  border-color: #1f8a70;
+  box-shadow: 0 0 0 2px rgba(31, 138, 112, 0.12);
+}
+
+.candidate-row.dimmed {
+  opacity: 0.6;
+}
+
+.candidate-row p {
+  margin-top: 5px;
+  color: #4d5b56;
+  line-height: 1.45;
+}
+
+.candidate-score {
+  text-align: right;
+}
+
+.candidate-score strong {
+  display: block;
+  font-size: 22px;
+}
+
+.candidate-row em,
+.account-detail em {
+  font-style: normal;
+  padding: 5px 8px;
+  border-radius: 999px;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.candidate-row em.good,
+.account-detail em.good {
+  background: #dfeee9;
+  color: #176d59;
+}
+
+.candidate-row em.warn,
+.account-detail em.warn {
+  background: #fff0cf;
+  color: #89640e;
+}
+
+.candidate-row em.danger,
+.account-detail em.danger {
+  background: #fce1dc;
+  color: #9f3e2c;
+}
+
+.account-detail {
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 16px;
+  display: grid;
+  gap: 14px;
+}
+
+.detail-head {
+  align-items: flex-start;
+}
+
+.detail-head h3 {
+  margin: 3px 0;
+  font-size: 22px;
+}
+
+.detail-actions {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 8px;
+}
+
+.detail-actions button {
+  border: 1px solid #d9dfd7;
+  border-radius: 8px;
+  background: #fff;
+  padding: 9px 8px;
+  font-weight: 800;
+}
+
+.detail-actions button.active {
+  color: #fff;
+  background: #1f8a70;
+  border-color: #1f8a70;
+}
+
+.detail-metrics,
+.note-stat-grid {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 8px;
+}
+
+.detail-metrics div,
+.note-stat-grid div {
+  background: #f5f7f3;
+  border-radius: 8px;
+  padding: 11px;
+}
+
+.detail-metrics span,
+.note-stat-grid span {
+  display: block;
+  color: #6f7b76;
+  font-size: 12px;
+}
+
+.detail-metrics strong,
+.note-stat-grid strong {
+  display: block;
+  margin-top: 4px;
+  font-size: 18px;
+}
+
+.detail-block {
+  display: grid;
+  gap: 8px;
+}
+
+.detail-block p {
+  color: #39433f;
+  line-height: 1.55;
+}
+
+.breakdown-list {
+  display: grid;
+  gap: 8px;
+}
+
+.breakdown-list div {
+  display: grid;
+  grid-template-columns: 82px minmax(0, 1fr) 38px;
+  gap: 8px;
+  align-items: center;
+}
+
+.breakdown-list em,
+.note-list button em {
+  background: transparent;
+  color: #26312f;
+  padding: 0;
+}
+
+.notes-drilldown {
+  display: grid;
+  grid-template-columns: minmax(260px, 0.9fr) minmax(0, 1.1fr);
+  gap: 12px;
+  border-top: 1px solid #e4e8e1;
+  padding-top: 14px;
+}
+
+.note-list {
+  display: grid;
+  gap: 8px;
+  max-height: 520px;
+  overflow: auto;
+  padding-right: 4px;
+}
+
+.note-list button {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  display: grid;
+  grid-template-columns: 28px minmax(0, 1fr) 44px;
+  gap: 8px;
+  padding: 10px;
+  text-align: left;
+  align-items: center;
+}
+
+.note-list button.active {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.note-list button > span {
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  background: #e8ece7;
+  display: grid;
+  place-items: center;
+  font-weight: 800;
+}
+
+.note-list button strong,
+.note-list button small {
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.note-list button em {
+  color: #176d59;
+}
+
+.note-detail {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  padding: 14px;
+  display: grid;
+  gap: 12px;
+}
+
+.note-detail h4 {
+  font-size: 18px;
+}
+
+.note-meta {
+  display: flex;
+  gap: 8px;
+  flex-wrap: wrap;
+}
+
+.note-meta span,
+.note-meta strong {
+  border-radius: 999px;
+  padding: 5px 8px;
+  background: #f5f7f3;
+  font-size: 12px;
+}
+
+.note-meta strong {
+  color: #176d59;
+  background: #dfeee9;
+}
+
+.ai-reason {
+  border-left: 3px solid #1f8a70;
+  padding-left: 10px;
+}
+
+.task-board {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 12px;
+  margin-top: 14px;
+}
+
+.task-board article {
+  display: grid;
+  gap: 9px;
+}
+
+.task-board header strong {
+  color: #1f8a70;
+}
+
+.task-board h4 {
+  font-size: 17px;
+}
+
+.task-board p {
+  color: #4d5b56;
+}
+
+.wide-table .table-head,
+.wide-table .table-row {
+  grid-template-columns: 1fr 1.4fr 0.8fr 0.8fr 0.7fr 1.5fr;
+}
+
+.mapping-area {
+  margin-top: 16px;
+}
+
+.mapping-grid {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 10px;
+  margin-top: 10px;
+}
+
+.mapping-grid article {
+  display: grid;
+  grid-template-columns: auto minmax(0, 1fr) auto;
+  gap: 10px;
+  align-items: center;
+}
+
+.mapping-grid article.confirmed {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.mapping-grid label input {
+  display: none;
+}
+
+.mapping-grid label span {
+  width: 18px;
+  height: 18px;
+  display: block;
+  border: 2px solid #aab5ae;
+  border-radius: 5px;
+}
+
+.mapping-grid label input:checked + span {
+  border-color: #1f8a70;
+  background: #1f8a70;
+}
+
+.mapping-grid em {
+  font-style: normal;
+  color: #4461a8;
+  font-weight: 800;
+}
+
+.template-grid article.selected,
+.learned-list article.approved {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.learned-list header em {
+  font-style: normal;
+  color: #4461a8;
+  font-weight: 800;
+}
+
+.danger-text {
+  color: #9f3e2c;
+}
+
+.interaction-lab {
+  display: grid;
+  grid-template-columns: minmax(0, 1.5fr) minmax(280px, 0.7fr);
+  gap: 14px;
+  margin-bottom: 16px;
+}
+
+.scenario-panel,
+.readiness-panel {
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 14px;
+}
+
+.scenario-panel .section-mini-head em {
+  align-self: flex-start;
+  border-radius: 999px;
+  padding: 5px 9px;
+  color: #176d59;
+  background: #dfeee9;
+  font-style: normal;
+  font-weight: 800;
+  font-size: 12px;
+}
+
+.scenario-grid {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 10px;
+  margin-top: 12px;
+}
+
+.scenario-grid button {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 12px;
+  text-align: left;
+  display: grid;
+  gap: 7px;
+}
+
+.scenario-grid button.active {
+  border-color: #1f8a70;
+  background: #f1faf6;
+  box-shadow: 0 0 0 2px rgba(31, 138, 112, 0.1);
+}
+
+.scenario-grid small,
+.scenario-grid span,
+.decision-log small,
+.compare-panel p,
+.feedback-presets button {
+  color: #6f7b76;
+}
+
+.scenario-grid span {
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.readiness-panel {
+  display: grid;
+  gap: 12px;
+}
+
+.readiness-panel b {
+  font-size: 24px;
+  color: #1f8a70;
+}
+
+.progress.large {
+  height: 12px;
+}
+
+.mode-switch {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  padding: 4px;
+  border-radius: 8px;
+  background: #edf1ee;
+}
+
+.mode-switch button {
+  border: 0;
+  border-radius: 6px;
+  min-height: 34px;
+  background: transparent;
+  font-weight: 800;
+  color: #4d5b56;
+}
+
+.mode-switch button.active {
+  background: #fff;
+  color: #1f8a70;
+}
+
+.decision-log {
+  display: grid;
+  gap: 8px;
+}
+
+.decision-log article {
+  display: grid;
+  grid-template-columns: 44px minmax(0, 1fr);
+  gap: 8px;
+  padding: 9px;
+  border: 1px solid #edf1ee;
+  border-radius: 8px;
+}
+
+.decision-log span {
+  color: #4461a8;
+  font-size: 12px;
+  font-weight: 900;
+}
+
+.decision-log div {
+  display: grid;
+  gap: 2px;
+  min-width: 0;
+}
+
+.bulk-toolbar {
+  display: flex;
+  gap: 12px;
+  align-items: center;
+  flex-wrap: wrap;
+  margin-top: 12px;
+  padding: 12px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+}
+
+.bulk-toolbar strong {
+  color: #26312f;
+  margin-right: auto;
+}
+
+.compare-panel {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 10px;
+  margin-top: 12px;
+}
+
+.compare-panel article {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 12px;
+  display: grid;
+  gap: 10px;
+  cursor: pointer;
+}
+
+.compare-panel header {
+  display: flex;
+  justify-content: space-between;
+  gap: 8px;
+  align-items: center;
+}
+
+.compare-panel em,
+.note-list mark {
+  font-style: normal;
+  border-radius: 999px;
+  padding: 4px 7px;
+  font-size: 12px;
+  font-weight: 800;
+  white-space: nowrap;
+}
+
+.compare-panel em.good,
+.note-list mark.good {
+  background: #dfeee9;
+  color: #176d59;
+}
+
+.compare-panel em.warn,
+.note-list mark.warn {
+  background: #fff0cf;
+  color: #89640e;
+}
+
+.compare-panel em.danger,
+.note-list mark.danger {
+  background: #fce1dc;
+  color: #9f3e2c;
+}
+
+.compare-metrics {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 6px;
+}
+
+.compare-metrics span {
+  border-radius: 8px;
+  background: #f5f7f3;
+  padding: 8px;
+  color: #6f7b76;
+  font-size: 12px;
+}
+
+.compare-metrics b {
+  display: block;
+  margin-top: 3px;
+  color: #26312f;
+}
+
+.quick-review {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.quick-review button,
+.note-filter button,
+.note-verdict-actions button,
+.feedback-presets button {
+  border: 1px solid #d9dfd7;
+  border-radius: 8px;
+  background: #fff;
+  min-height: 34px;
+  padding: 0 10px;
+  font-weight: 800;
+}
+
+.quick-review button:hover,
+.note-verdict-actions button:hover,
+.feedback-presets button:hover {
+  border-color: #1f8a70;
+  color: #1f8a70;
+}
+
+.note-filter {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6px;
+}
+
+.note-filter button {
+  min-height: 30px;
+  border-radius: 999px;
+  font-size: 12px;
+}
+
+.note-filter button.active {
+  background: #1f8a70;
+  border-color: #1f8a70;
+  color: #fff;
+}
+
+.note-list button {
+  grid-template-columns: 28px minmax(0, 1fr) 42px auto;
+}
+
+.note-list mark {
+  justify-self: end;
+}
+
+.evidence-grid {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 8px;
+}
+
+.evidence-grid div {
+  border-radius: 8px;
+  background: #f5f7f3;
+  padding: 10px;
+  display: grid;
+  gap: 5px;
+}
+
+.evidence-grid span {
+  color: #6f7b76;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.evidence-grid strong {
+  color: #39433f;
+  font-size: 13px;
+  line-height: 1.45;
+}
+
+.note-verdict-actions {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 8px;
+}
+
+.feedback-box {
+  display: grid;
+  gap: 10px;
+}
+
+.feedback-presets {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 8px;
+}
+
+.feedback-presets button {
+  min-height: 48px;
+  text-align: left;
+  line-height: 1.4;
+}
+
+.empty-state {
+  border: 1px dashed #cfd7d1;
+  border-radius: 8px;
+  padding: 12px;
+  color: #6f7b76;
+  background: #f9faf7;
+}
+
+.creator-command {
+  display: grid;
+  grid-template-columns: minmax(0, 1.45fr) minmax(280px, 0.55fr);
+  gap: 14px;
+  margin-top: 14px;
+}
+
+.creator-search-box,
+.ai-side-note,
+.filter-panel,
+.creator-explain,
+.field-config,
+.version-list,
+.delivery-preview,
+.handoff-grid article,
+.flow-stage,
+.flow-overview article,
+.decision-matrix,
+.rule-conflict-box,
+.audit-box {
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+}
+
+.creator-search-box {
+  padding: 14px;
+  display: grid;
+  gap: 12px;
+}
+
+.creator-search-box label,
+.filter-panel label {
+  display: grid;
+  gap: 7px;
+  color: #6f7b76;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.creator-search-box input,
+.filter-panel select,
+.filter-panel input {
+  width: 100%;
+  border: 1px solid #d9dfd7;
+  border-radius: 8px;
+  padding: 10px 11px;
+  color: #26312f;
+  background: #fff;
+}
+
+.quick-prompts,
+.filter-presets,
+.creator-tags,
+.stage-accounts,
+.gap-list,
+.field-chip-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.quick-prompts button,
+.filter-presets button {
+  border: 1px solid #d9dfd7;
+  border-radius: 999px;
+  background: #fff;
+  min-height: 32px;
+  padding: 0 11px;
+  color: #4d5b56;
+  font-weight: 800;
+}
+
+.ai-side-note {
+  padding: 14px;
+  display: grid;
+  gap: 8px;
+  align-content: start;
+}
+
+.ai-side-note p,
+.creator-explain p,
+.flow-stage p,
+.rule-conflict-box p,
+.audit-box p,
+.handoff-grid p,
+.delivery-table p,
+.version-list p {
+  color: #4d5b56;
+  line-height: 1.5;
+}
+
+.ai-side-note small,
+.creator-bottom small,
+.delivery-readiness small,
+.version-list small {
+  color: #6f7b76;
+}
+
+.creator-layout {
+  display: grid;
+  grid-template-columns: 240px minmax(0, 1fr) 300px;
+  gap: 14px;
+  margin-top: 14px;
+  align-items: start;
+}
+
+.creator-layout.no-explain {
+  grid-template-columns: 260px minmax(0, 1fr);
+}
+
+.filter-panel {
+  padding: 14px;
+  display: grid;
+  gap: 13px;
+  position: sticky;
+  top: 16px;
+}
+
+.creator-results {
+  min-width: 0;
+  display: grid;
+  gap: 12px;
+}
+
+.creator-stats,
+.flow-overview {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 10px;
+}
+
+.creator-stats article {
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 12px;
+}
+
+.creator-stats span,
+.flow-overview span {
+  color: #6f7b76;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.creator-stats strong,
+.flow-overview strong {
+  display: block;
+  margin-top: 4px;
+  font-size: 24px;
+  color: #1f8a70;
+}
+
+.creator-list {
+  display: grid;
+  gap: 10px;
+}
+
+.creator-card {
+  display: grid;
+  grid-template-columns: 46px minmax(0, 1fr);
+  gap: 12px;
+  padding: 13px;
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  cursor: pointer;
+}
+
+.creator-card.active {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.creator-avatar {
+  width: 46px;
+  height: 46px;
+  border-radius: 8px;
+  display: grid;
+  place-items: center;
+  background: #e8ece7;
+  font-weight: 900;
+  color: #26312f;
+}
+
+.creator-main,
+.creator-main header {
+  min-width: 0;
+}
+
+.creator-main header,
+.creator-bottom {
+  display: flex;
+  justify-content: space-between;
+  gap: 10px;
+  align-items: flex-start;
+}
+
+.creator-main header strong,
+.creator-main header small {
+  display: block;
+}
+
+.creator-main header small {
+  color: #6f7b76;
+  margin-top: 3px;
+}
+
+.creator-main em,
+.flow-stage em,
+.delivery-preview em {
+  font-style: normal;
+  border-radius: 999px;
+  padding: 5px 8px;
+  font-size: 12px;
+  font-weight: 800;
+  white-space: nowrap;
+}
+
+.creator-main em.good {
+  background: #dfeee9;
+  color: #176d59;
+}
+
+.creator-main em.warn {
+  background: #fff0cf;
+  color: #89640e;
+}
+
+.creator-main em.danger {
+  background: #fce1dc;
+  color: #9f3e2c;
+}
+
+.creator-main p {
+  margin-top: 8px;
+  color: #39433f;
+  line-height: 1.5;
+}
+
+.creator-tags {
+  margin-top: 9px;
+}
+
+.creator-tags span,
+.stage-accounts span,
+.gap-list span {
+  border-radius: 999px;
+  padding: 5px 8px;
+  background: #f5f7f3;
+  color: #4d5b56;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.creator-data-grid {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 8px;
+  margin-top: 10px;
+}
+
+.creator-data-grid span {
+  border-radius: 8px;
+  background: #f5f7f3;
+  padding: 8px;
+  color: #6f7b76;
+  font-size: 12px;
+}
+
+.creator-data-grid b {
+  display: block;
+  margin-top: 3px;
+  color: #26312f;
+}
+
+.creator-bottom {
+  margin-top: 10px;
+  align-items: center;
+}
+
+.creator-explain {
+  padding: 14px;
+  display: grid;
+  gap: 11px;
+  position: sticky;
+  top: 16px;
+}
+
+.creator-explain article {
+  display: grid;
+  grid-template-columns: 28px minmax(0, 1fr);
+  gap: 10px;
+}
+
+.creator-explain article > span,
+.flow-stage header > span {
+  width: 28px;
+  height: 28px;
+  border-radius: 50%;
+  display: grid;
+  place-items: center;
+  background: #dfeee9;
+  color: #176d59;
+  font-weight: 900;
+}
+
+.flow-overview {
+  margin-top: 14px;
+}
+
+.flow-overview article {
+  padding: 14px;
+}
+
+.flow-lane {
+  display: grid;
+  gap: 12px;
+  margin-top: 14px;
+}
+
+.flow-stage {
+  padding: 15px;
+}
+
+.flow-stage header {
+  display: grid;
+  grid-template-columns: 32px minmax(0, 1fr) auto;
+  gap: 10px;
+  align-items: start;
+}
+
+.flow-stage header small {
+  display: block;
+  margin-top: 3px;
+  color: #6f7b76;
+}
+
+.flow-stage.done em {
+  background: #dfeee9;
+  color: #176d59;
+}
+
+.flow-stage.running em {
+  background: #fff0cf;
+  color: #89640e;
+}
+
+.stage-grid {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 10px;
+  margin-top: 12px;
+}
+
+.stage-grid section {
+  border-radius: 8px;
+  background: #f5f7f3;
+  padding: 10px;
+}
+
+.stage-grid b {
+  display: block;
+  margin-bottom: 5px;
+}
+
+.stage-accounts {
+  margin-top: 12px;
+}
+
+.flow-support-grid,
+.delivery-top,
+.handoff-grid {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 14px;
+  margin-top: 14px;
+}
+
+.decision-matrix,
+.rule-conflict-box,
+.audit-box,
+.field-config,
+.version-list {
+  padding: 14px;
+  display: grid;
+  gap: 10px;
+}
+
+.decision-matrix > div:not(.section-mini-head) {
+  display: grid;
+  grid-template-columns: 76px minmax(0, 1fr) 36px;
+  gap: 8px;
+  align-items: center;
+}
+
+.rule-conflict-box section,
+.audit-box section,
+.version-list section {
+  display: grid;
+  grid-template-columns: 40px minmax(0, 1fr);
+  gap: 10px;
+  border-top: 1px solid #edf1ee;
+  padding-top: 10px;
+}
+
+.rule-conflict-box em,
+.delivery-preview em {
+  align-self: start;
+  background: #fff0cf;
+  color: #89640e;
+}
+
+.audit-box span,
+.version-list span {
+  color: #4461a8;
+  font-size: 12px;
+  font-weight: 900;
+}
+
+.delivery-top {
+  align-items: stretch;
+}
+
+.delivery-top.no-version {
+  grid-template-columns: minmax(280px, 0.75fr) minmax(0, 1.25fr);
+}
+
+.delivery-readiness {
+  margin-top: 0;
+}
+
+.gap-list {
+  margin-top: 10px;
+}
+
+.gap-list span {
+  background: #fce1dc;
+  color: #9f3e2c;
+}
+
+.field-chip-grid {
+  align-content: start;
+}
+
+.field-chip-grid label {
+  border: 1px solid #d9dfd7;
+  border-radius: 999px;
+  background: #fff;
+  padding: 7px 10px;
+  display: flex;
+  gap: 7px;
+  align-items: center;
+  color: #4d5b56;
+  font-weight: 800;
+  font-size: 12px;
+}
+
+.field-chip-grid label.disabled {
+  opacity: 0.45;
+}
+
+.delivery-preview {
+  margin-top: 14px;
+  padding: 14px;
+}
+
+.delivery-preview .section-mini-head {
+  align-items: flex-start;
+}
+
+.delivery-table {
+  margin-top: 12px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.delivery-head,
+.delivery-table article {
+  display: grid;
+  grid-template-columns: 1fr 0.8fr 1.5fr 1.1fr 1.1fr;
+  gap: 12px;
+  align-items: start;
+  padding: 12px;
+}
+
+.delivery-head {
+  background: #edf1ee;
+  font-weight: 900;
+}
+
+.delivery-table article + article {
+  border-top: 1px solid #e4e8e1;
+}
+
+.delivery-table small {
+  display: block;
+  margin-top: 4px;
+  color: #6f7b76;
+}
+
+.handoff-grid article {
+  padding: 14px;
+}
+
+.handoff-grid strong {
+  display: block;
+  margin-bottom: 7px;
+}
+
+.task-status-grid,
+.resource-health-grid,
+.resource-impact-grid,
+.rule-layer-grid,
+.feedback-category-grid,
+.learning-chain,
+.template-preview-grid {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 12px;
+  margin-top: 14px;
+}
+
+.task-status-grid article,
+.resource-health-grid article,
+.resource-impact-grid article,
+.rule-layer-grid article,
+.feedback-category-grid article,
+.learning-chain article,
+.template-preview,
+.template-preview-grid article,
+.task-detail-band div {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 14px;
+}
+
+.task-status-grid span,
+.resource-health-grid span,
+.rule-layer-grid span,
+.feedback-category-grid span,
+.template-preview-grid span {
+  color: #4461a8;
+  font-size: 12px;
+  font-weight: 900;
+}
+
+.task-status-grid strong,
+.resource-health-grid strong,
+.rule-layer-grid strong,
+.feedback-category-grid strong,
+.template-preview-grid strong {
+  display: block;
+  margin: 5px 0;
+}
+
+.task-status-grid strong,
+.resource-health-grid strong {
+  font-size: 24px;
+  color: #1f8a70;
+}
+
+.task-status-grid small,
+.resource-health-grid small,
+.rule-layer-grid small,
+.feedback-category-grid small,
+.template-preview-grid p,
+.learning-chain p,
+.task-detail-band p,
+.resource-impact-grid p {
+  color: #6f7b76;
+  line-height: 1.5;
+}
+
+.task-board footer {
+  display: flex;
+  gap: 10px;
+  flex-wrap: wrap;
+  border-top: 1px solid #edf1ee;
+  padding-top: 8px;
+}
+
+.task-detail-band {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 12px;
+  margin-top: 14px;
+}
+
+.resource-impact-grid {
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+}
+
+.rule-conflict-strip {
+  display: grid;
+  gap: 10px;
+  margin: 14px 0;
+}
+
+.rule-conflict-strip article {
+  border: 1px solid #f0d6aa;
+  border-radius: 8px;
+  background: #fffaf0;
+  padding: 12px;
+  display: grid;
+  grid-template-columns: 42px minmax(0, 1fr);
+  gap: 10px;
+}
+
+.rule-conflict-strip em {
+  width: 30px;
+  height: 30px;
+  border-radius: 50%;
+  background: #fff0cf;
+  color: #89640e;
+  display: grid;
+  place-items: center;
+  font-style: normal;
+  font-weight: 900;
+}
+
+.rule-conflict-strip p {
+  color: #6f7b76;
+  line-height: 1.5;
+}
+
+.learning-chain {
+  margin-top: 16px;
+}
+
+.template-preview {
+  margin-top: 16px;
+}
+
+.template-preview-grid {
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
+.resource-grid article.active,
+.rule-management article.active,
+.task-board article.active {
+  border-color: #1f8a70;
+  background: #f1faf6;
+  box-shadow: 0 0 0 2px rgba(31, 138, 112, 0.1);
+}
+
+.resource-grid article,
+.rule-management article,
+.task-board article,
+.table-row.clickable {
+  cursor: pointer;
+}
+
+.resource-detail-panel,
+.rule-sandbox,
+.task-detail-panel {
+  margin-top: 16px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 14px;
+}
+
+.resource-detail-grid,
+.sandbox-grid,
+.task-detail-panel,
+.template-config-grid {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 12px;
+  margin-top: 12px;
+}
+
+.resource-file-list,
+.resource-issue-list,
+.resource-sample-list,
+.sandbox-main,
+.sandbox-tests,
+.task-profile,
+.task-timeline,
+.task-next-actions,
+.template-field-list,
+.template-table-preview {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 14px;
+}
+
+.resource-file-list,
+.resource-issue-list,
+.resource-sample-list,
+.sandbox-main,
+.sandbox-tests,
+.task-timeline,
+.task-next-actions,
+.template-field-list,
+.template-table-preview {
+  display: grid;
+  gap: 10px;
+}
+
+.resource-file-list section,
+.resource-issue-list section,
+.task-timeline section {
+  border-top: 1px solid #edf1ee;
+  padding-top: 10px;
+  display: grid;
+  gap: 6px;
+}
+
+.resource-file-list span,
+.resource-sample-list span,
+.sandbox-main > span,
+.sandbox-tests label span,
+.template-field-list label span {
+  color: #26312f;
+  font-weight: 900;
+}
+
+.resource-file-list small,
+.resource-issue-list small,
+.resource-sample-list small,
+.sandbox-tests small,
+.template-field-list small,
+.task-timeline time {
+  color: #6f7b76;
+  font-size: 12px;
+}
+
+.resource-file-list .tag-row em {
+  border: 1px solid #f0d6aa;
+  border-radius: 999px;
+  background: #fffaf0;
+  color: #89640e;
+  padding: 5px 8px;
+  font-style: normal;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.resource-issue-list header {
+  display: flex;
+  justify-content: space-between;
+  gap: 8px;
+  align-items: center;
+}
+
+.resource-issue-list header span,
+.task-profile .section-mini-head span {
+  border-radius: 999px;
+  padding: 5px 8px;
+  color: #89640e;
+  background: #fff0cf;
+  font-size: 12px;
+  font-weight: 900;
+}
+
+.resource-issue-list header span.danger {
+  color: #9f3e2c;
+  background: #fce1dc;
+}
+
+.resource-issue-list p,
+.sandbox-main p,
+.task-profile p,
+.task-timeline p,
+.template-table-preview span {
+  color: #4d5b56;
+  line-height: 1.5;
+}
+
+.resource-sample-list button,
+.task-next-actions button {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 10px;
+  text-align: left;
+  display: grid;
+  gap: 4px;
+}
+
+.resource-sample-list button:hover,
+.task-next-actions button:hover {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.mapping-grid article {
+  grid-template-columns: auto minmax(0, 1fr) auto auto;
+}
+
+.sandbox-main {
+  grid-column: span 2;
+}
+
+.sandbox-main label {
+  display: grid;
+  gap: 7px;
+  color: #6f7b76;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.sandbox-main textarea {
+  min-height: 96px;
+}
+
+.sandbox-main input[type='range'] {
+  width: 100%;
+}
+
+.sandbox-main em {
+  border-radius: 8px;
+  background: #f1faf6;
+  color: #176d59;
+  padding: 10px;
+  font-style: normal;
+  font-weight: 900;
+}
+
+.sandbox-tests label {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  padding: 10px;
+  display: grid;
+  grid-template-columns: auto minmax(0, 1fr);
+  gap: 9px;
+}
+
+.sandbox-tests label.active {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.sandbox-tests p {
+  color: #4461a8;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.task-detail-panel {
+  grid-template-columns: 0.9fr 1.2fr 0.7fr;
+}
+
+.task-profile {
+  display: grid;
+  gap: 12px;
+}
+
+.task-timeline section {
+  grid-template-columns: 104px minmax(0, 1fr);
+}
+
+.task-next-actions button {
+  font-weight: 800;
+}
+
+.template-config-grid {
+  grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr);
+}
+
+.template-field-list label {
+  display: grid;
+  grid-template-columns: auto minmax(0, 1fr) minmax(120px, 0.8fr) 64px;
+  gap: 8px;
+  align-items: center;
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  padding: 10px;
+}
+
+.template-field-list label.required {
+  border-color: #1f8a70;
+}
+
+.template-field-list label.off {
+  opacity: 0.62;
+}
+
+.template-field-list em {
+  justify-self: end;
+  border-radius: 999px;
+  padding: 4px 7px;
+  color: #4461a8;
+  background: #edf1ee;
+  font-style: normal;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.template-table-preview {
+  overflow-x: auto;
+}
+
+.template-column-row {
+  display: grid;
+  grid-auto-columns: minmax(110px, 1fr);
+  grid-auto-flow: column;
+  min-width: 720px;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.template-column-row + .template-column-row {
+  margin-top: 8px;
+}
+
+.template-column-row span {
+  min-height: 46px;
+  padding: 10px;
+  border-right: 1px solid #e4e8e1;
+}
+
+.template-column-row span:last-child {
+  border-right: 0;
+}
+
+.template-column-row.head {
+  background: #edf1ee;
+  font-weight: 900;
+}
+
+.flow-workbench {
+  display: grid;
+  gap: 16px;
+}
+
+.flow-hero {
+  position: relative;
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) auto;
+  gap: 18px;
+  align-items: center;
+  overflow: hidden;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 22px 22px 26px;
+}
+
+.flow-hero h2 {
+  margin: 4px 0 5px;
+  font-size: 32px;
+  line-height: 1.15;
+  color: #18211f;
+}
+
+.flow-hero small {
+  color: #60716b;
+}
+
+.flow-hero-copy {
+  min-width: 0;
+}
+
+.flow-guide {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-top: 14px;
+}
+
+.flow-guide span {
+  display: inline-flex;
+  align-items: center;
+  gap: 7px;
+  max-width: 100%;
+  border: 1px solid #dfe4dc;
+  border-radius: 999px;
+  background: #f9faf7;
+  color: #4d5b56;
+  padding: 7px 10px;
+  font-size: 12px;
+  font-weight: 700;
+}
+
+.flow-guide b {
+  color: #1f8a70;
+}
+
+.flow-hero-actions {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+}
+
+.flow-progress {
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  height: 5px;
+  background: #e3ece7;
+}
+
+.flow-progress i {
+  display: block;
+  height: 100%;
+  background: #1f8a70;
+  transition: width 0.2s ease;
+}
+
+.flow-nav {
+  display: grid;
+  grid-template-columns: repeat(6, minmax(0, 1fr));
+  gap: 0;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 10px;
+}
+
+.flow-nav button {
+  position: relative;
+  min-height: 72px;
+  border: 1px solid transparent;
+  border-radius: 8px;
+  background: transparent;
+  padding: 10px 12px;
+  text-align: center;
+  display: grid;
+  justify-items: center;
+  gap: 5px;
+}
+
+.flow-nav button:hover {
+  background: #f9faf7;
+}
+
+.flow-nav button.active {
+  border-color: #1f8a70;
+  background: #f1faf6;
+  box-shadow: 0 0 0 2px rgba(31, 138, 112, 0.12);
+}
+
+.flow-nav button.done {
+  background: transparent;
+}
+
+.flow-nav span {
+  width: 30px;
+  height: 30px;
+  border-radius: 50%;
+  display: grid;
+  place-items: center;
+  background: #edf1ee;
+  color: #6f7b76;
+  font-weight: 900;
+}
+
+.flow-nav button.done span,
+.flow-nav button.active span {
+  background: #1f8a70;
+  color: #fff;
+}
+
+.flow-nav strong {
+  color: #18211f;
+  font-size: 14px;
+}
+
+.flow-nav small {
+  color: #6f7b76;
+  font-size: 12px;
+}
+
+.flow-summary {
+  display: grid;
+  grid-template-columns: 1.25fr 0.75fr 0.75fr 1fr;
+  gap: 1px;
+  overflow: hidden;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #dfe4dc;
+}
+
+.flow-summary article {
+  background: #fff;
+  padding: 14px 16px;
+}
+
+.flow-summary span {
+  color: #6f7b76;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.flow-summary strong {
+  display: block;
+  margin-top: 4px;
+  color: #18211f;
+}
+
+.flow-body {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) 360px;
+  gap: 16px;
+  align-items: start;
+}
+
+.flow-stage,
+.flow-aside {
+  min-width: 0;
+}
+
+.stage-card,
+.assistant-card {
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+  padding: 18px;
+}
+
+.stage-card {
+  min-height: 520px;
+  display: grid;
+  align-content: start;
+  gap: 16px;
+}
+
+.stage-heading {
+  display: flex;
+  justify-content: space-between;
+  gap: 16px;
+  align-items: flex-start;
+  padding-bottom: 14px;
+  border-bottom: 1px solid #edf1ee;
+}
+
+.stage-heading h3 {
+  margin: 3px 0 5px;
+  font-size: 24px;
+}
+
+.stage-heading small {
+  color: #6f7b76;
+}
+
+.flow-upload {
+  min-height: 280px;
+}
+
+.flow-requirements {
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.flow-requirements .requirement-item {
+  min-height: 92px;
+}
+
+.rule-focus-grid {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 12px;
+}
+
+.rule-focus-grid .rule-card {
+  background: #fff;
+}
+
+.rule-focus-grid .rule-card.active {
+  border-color: #b8ded2;
+  background: #f6fbf8;
+}
+
+.engine-grid,
+.feedback-stage-grid {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+  gap: 14px;
+}
+
+.flow-aside {
+  display: grid;
+  gap: 12px;
+  position: sticky;
+  top: 18px;
+}
+
+.assistant-card {
+  display: grid;
+  gap: 10px;
+}
+
+.shortcut-grid.one-column {
+  grid-template-columns: 1fr;
+}
+
+.scenario-grid.compact {
+  grid-template-columns: 1fr;
+  margin-top: 0;
+}
+
+.scenario-grid.compact button {
+  min-height: auto;
+}
+
+.flow-recommendation {
+  margin-top: 0;
+}
+
+.flow-recommendation .recommendation-layout {
+  grid-template-columns: minmax(420px, 0.85fr) minmax(0, 1.15fr);
+}
+
+.ops-strip,
+.creator-decision-strip,
+.delivery-control-grid,
+.task-command-center,
+.rule-ops-panel,
+.template-ops-panel {
+  display: grid;
+  gap: 12px;
+  margin-bottom: 16px;
+}
+
+.ops-strip {
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+}
+
+.ops-strip article,
+.creator-decision-strip article,
+.delivery-checklist,
+.delivery-copy-panel,
+.delivery-review-queue,
+.task-focus-card,
+.task-action-queue,
+.resource-fix-board,
+.rule-ops-panel article,
+.learning-scope-panel,
+.template-ops-panel article {
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #fff;
+}
+
+.ops-strip article,
+.creator-decision-strip article,
+.rule-ops-panel article,
+.template-ops-panel article {
+  padding: 14px;
+  display: grid;
+  gap: 5px;
+}
+
+.ops-strip span,
+.creator-decision-strip span,
+.rule-ops-panel span,
+.template-ops-panel span {
+  color: #4461a8;
+  font-size: 12px;
+  font-weight: 900;
+}
+
+.ops-strip strong,
+.template-ops-panel strong {
+  color: #18211f;
+  font-size: 24px;
+}
+
+.ops-strip small,
+.creator-decision-strip small,
+.delivery-checklist small,
+.delivery-copy-panel p,
+.delivery-review-queue small,
+.task-focus-card p,
+.task-action-queue small,
+.resource-fix-list small,
+.resource-fix-list p,
+.rule-ops-panel small,
+.learning-scope-panel small,
+.template-ops-panel small,
+.mini-pipeline small,
+.creator-selection-tray small {
+  color: #6f7b76;
+  line-height: 1.45;
+}
+
+.mini-pipeline {
+  display: grid;
+  gap: 8px;
+}
+
+.mini-pipeline article {
+  display: grid;
+  grid-template-columns: 58px minmax(0, 1fr);
+  gap: 9px;
+  padding: 10px;
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+}
+
+.mini-pipeline span,
+.delivery-review-queue span,
+.resource-fix-list span {
+  width: fit-content;
+  height: fit-content;
+  border-radius: 999px;
+  padding: 4px 7px;
+  background: #edf1ee;
+  color: #4d5b56;
+  font-size: 12px;
+  font-weight: 900;
+}
+
+.mini-pipeline article.done span {
+  background: #dfeee9;
+  color: #176d59;
+}
+
+.mini-pipeline article.running span {
+  background: #fff0cf;
+  color: #89640e;
+}
+
+.creator-decision-strip {
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  margin-top: 14px;
+}
+
+.creator-decision-strip article {
+  cursor: pointer;
+}
+
+.creator-decision-strip article:hover,
+.creator-selection-tray button:hover,
+.delivery-review-queue button:hover,
+.task-action-queue button:hover,
+.resource-fix-list article:hover {
+  border-color: #1f8a70;
+  background: #f1faf6;
+}
+
+.creator-selection-tray {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  flex-wrap: wrap;
+  padding: 12px;
+  margin: 12px 0;
+  border: 1px solid #dfe4dc;
+  border-radius: 8px;
+  background: #f9faf7;
+}
+
+.creator-selection-tray > div {
+  min-width: 180px;
+  margin-right: auto;
+}
+
+.creator-selection-tray button {
+  border: 1px solid #dfe4dc;
+  border-radius: 999px;
+  background: #fff;
+  color: #26312f;
+  min-height: 32px;
+  padding: 0 10px;
+  font-weight: 800;
+}
+
+.delivery-control-grid {
+  grid-template-columns: minmax(280px, 0.95fr) minmax(260px, 0.9fr) minmax(300px, 1.15fr);
+  margin-top: 14px;
+}
+
+.delivery-checklist,
+.delivery-copy-panel,
+.delivery-review-queue,
+.task-focus-card,
+.task-action-queue,
+.resource-fix-board,
+.learning-scope-panel {
+  padding: 14px;
+}
+
+.delivery-checklist,
+.delivery-review-queue,
+.task-action-queue {
+  display: grid;
+  gap: 10px;
+  align-content: start;
+}
+
+.delivery-checklist button,
+.delivery-review-queue button,
+.task-action-queue button {
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  background: #fff;
+  padding: 10px;
+  display: grid;
+  gap: 9px;
+  text-align: left;
+  align-items: center;
+}
+
+.delivery-checklist button {
+  grid-template-columns: 26px minmax(0, 1fr);
+}
+
+.delivery-checklist button > span {
+  width: 24px;
+  height: 24px;
+  border-radius: 50%;
+  display: grid;
+  place-items: center;
+  background: #edf1ee;
+  color: #6f7b76;
+  font-weight: 900;
+}
+
+.delivery-checklist button.done {
+  border-color: #b8ded2;
+  background: #f6fbf8;
+}
+
+.delivery-checklist button.done > span {
+  background: #1f8a70;
+  color: #fff;
+}
+
+.delivery-copy-panel {
+  display: grid;
+  gap: 12px;
+  align-content: start;
+}
+
+.delivery-review-queue button {
+  grid-template-columns: 62px minmax(0, 1fr);
+}
+
+.delivery-row-actions {
+  grid-column: 1 / -1;
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  border-top: 1px solid #edf1ee;
+  padding-top: 8px;
+}
+
+.task-command-center {
+  grid-template-columns: minmax(320px, 0.9fr) minmax(0, 1.1fr);
+  margin-top: 14px;
+}
+
+.task-focus-card {
+  display: grid;
+  gap: 12px;
+}
+
+.task-mini-metrics {
+  display: flex;
+  gap: 8px;
+  flex-wrap: wrap;
+}
+
+.task-mini-metrics span {
+  border-radius: 999px;
+  background: #f5f7f3;
+  color: #4d5b56;
+  padding: 6px 9px;
+  font-size: 12px;
+  font-weight: 800;
+}
+
+.task-action-queue button {
+  grid-template-columns: minmax(0, 1fr) auto;
+}
+
+.task-action-queue button > span {
+  color: #1f8a70;
+  font-weight: 900;
+}
+
+.resource-fix-board {
+  margin: 16px 0;
+}
+
+.resource-fix-list {
+  display: grid;
+  gap: 10px;
+  margin-top: 12px;
+}
+
+.resource-fix-list article {
+  display: grid;
+  grid-template-columns: 44px minmax(0, 1fr) auto;
+  gap: 10px;
+  align-items: start;
+  border: 1px solid #e0e5dd;
+  border-radius: 8px;
+  padding: 12px;
+}
+
+.resource-fix-list span.danger,
+.delivery-review-queue span.danger {
+  color: #9f3e2c;
+  background: #fce1dc;
+}
+
+.rule-ops-panel,
+.template-ops-panel {
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  margin-top: 14px;
+}
+
+.rule-ops-panel strong {
+  color: #18211f;
+}
+
+.learning-scope-panel {
+  display: flex;
+  justify-content: space-between;
+  gap: 16px;
+  align-items: center;
+  margin: 14px 0;
+}
+
+.learning-scope-panel h3 {
+  margin: 3px 0 5px;
+  font-size: 22px;
+}
+
+@media (max-width: 1180px) {
+  .app-shell {
+    grid-template-columns: 220px minmax(0, 1fr);
+  }
+
+  .stepper,
+  .summary-band,
+  .flow-nav,
+  .flow-summary,
+  .flow-body,
+  .flow-requirements,
+  .rule-focus-grid,
+  .engine-grid,
+  .feedback-stage-grid,
+  .review-strip,
+  .workspace-grid,
+  .recommendation-grid,
+  .learning-grid,
+  .resource-grid,
+  .template-grid,
+  .recommendation-layout,
+  .filter-bar,
+  .notes-drilldown,
+  .mapping-grid,
+  .task-board {
+    grid-template-columns: 1fr;
+  }
+
+  .interaction-lab,
+  .business-assistant,
+  .scenario-grid,
+  .compare-panel,
+  .evidence-grid,
+  .feedback-presets,
+  .creator-command,
+  .creator-layout,
+  .creator-stats,
+  .flow-overview,
+  .stage-grid,
+  .flow-support-grid,
+  .delivery-top,
+  .handoff-grid,
+  .task-status-grid,
+  .resource-health-grid,
+  .resource-impact-grid,
+  .rule-layer-grid,
+  .resource-detail-grid,
+  .sandbox-grid,
+  .task-detail-panel,
+  .template-config-grid,
+  .feedback-category-grid,
+  .learning-chain,
+  .template-preview-grid,
+  .task-detail-band,
+  .ops-strip,
+  .creator-decision-strip,
+  .delivery-control-grid,
+  .task-command-center,
+  .rule-ops-panel,
+  .template-ops-panel {
+    grid-template-columns: 1fr;
+  }
+
+  .filter-panel,
+  .creator-explain,
+  .flow-aside {
+    position: static;
+  }
+}
+
+@media (max-width: 760px) {
+  .app-shell {
+    display: block;
+  }
+
+  .sidebar {
+    position: static;
+    height: auto;
+  }
+
+  .main {
+    padding: 16px;
+  }
+
+  .topbar,
+  .section-heading,
+  .panel-heading,
+  .stage-heading,
+  .flow-hero,
+  .page-hero {
+    align-items: flex-start;
+    flex-direction: column;
+  }
+
+  .topbar-actions,
+  .page-actions {
+    width: 100%;
+  }
+
+  .utility-topbar {
+    margin: -16px -16px 16px;
+    padding: 12px 16px;
+  }
+
+  .topbar-status {
+    justify-content: flex-start;
+  }
+
+  .topbar-actions button,
+  .page-actions button,
+  .flow-hero-actions,
+  .flow-hero-actions button {
+    flex: 1;
+    width: 100%;
+  }
+
+  .candidate-card header,
+  .candidate-row,
+  .table-head,
+  .table-row,
+  .rule-management article,
+  .wide-table .table-head,
+  .wide-table .table-row,
+  .resource-fix-list article,
+  .delivery-review-queue button,
+  .task-action-queue button {
+    grid-template-columns: 1fr;
+  }
+
+  .metric-row,
+  .score-panel,
+  .detail-metrics,
+  .note-stat-grid,
+  .detail-actions,
+  .note-verdict-actions,
+  .temp-rule-box,
+  .temp-rule-box.full,
+  .creator-data-grid,
+  .delivery-head,
+  .delivery-table article {
+    grid-template-columns: 1fr;
+  }
+
+  .sandbox-main,
+  .task-profile,
+  .task-timeline,
+  .task-next-actions {
+    grid-column: auto;
+  }
+
+  .template-field-list label,
+  .task-timeline section,
+  .mapping-grid article {
+    grid-template-columns: 1fr;
+  }
+
+  .creator-main header,
+  .creator-bottom,
+  .learning-scope-panel {
+    display: grid;
+  }
+
+  .next-action-card,
+  .business-checklist button {
+    grid-template-columns: 1fr;
+  }
+
+  .shortcut-grid {
+    grid-template-columns: 1fr;
+  }
+}

+ 23 - 0
src/app/app.spec.ts

@@ -0,0 +1,23 @@
+import { TestBed } from '@angular/core/testing';
+import { App } from './app';
+
+describe('App', () => {
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [App],
+    }).compileComponents();
+  });
+
+  it('should create the app', () => {
+    const fixture = TestBed.createComponent(App);
+    const app = fixture.componentInstance;
+    expect(app).toBeTruthy();
+  });
+
+  it('should render title', () => {
+    const fixture = TestBed.createComponent(App);
+    fixture.detectChanges();
+    const compiled = fixture.nativeElement as HTMLElement;
+    expect(compiled.querySelector('h1')?.textContent).toContain('提号AI');
+  });
+});

+ 32 - 0
src/app/app.ts

@@ -0,0 +1,32 @@
+import { CommonModule } from '@angular/common';
+import { Component, ViewEncapsulation } from '@angular/core';
+import { DemoStateService } from './demo-state.service';
+import { CreatorSearchPageComponent } from './pages/creator-search-page.component';
+import { DeliveryPageComponent } from './pages/delivery-page.component';
+import { LearningPageComponent } from './pages/learning-page.component';
+import { ResourcesPageComponent } from './pages/resources-page.component';
+import { RulesPageComponent } from './pages/rules-page.component';
+import { TasksPageComponent } from './pages/tasks-page.component';
+import { TemplatesPageComponent } from './pages/templates-page.component';
+import { WorkspacePageComponent } from './pages/workspace-page.component';
+
+@Component({
+  selector: 'app-root',
+  imports: [
+    CommonModule,
+    WorkspacePageComponent,
+    CreatorSearchPageComponent,
+    DeliveryPageComponent,
+    TasksPageComponent,
+    ResourcesPageComponent,
+    RulesPageComponent,
+    LearningPageComponent,
+    TemplatesPageComponent
+  ],
+  templateUrl: './app.html',
+  styleUrl: './app.scss',
+  encapsulation: ViewEncapsulation.None
+})
+export class App {
+  constructor(public state: DemoStateService) {}
+}

+ 168 - 0
src/app/components/account-detail.component.html

@@ -0,0 +1,168 @@
+<section class="account-detail">
+  <div class="detail-head">
+    <div>
+      <p class="eyebrow">账号详情</p>
+      <h3>{{ state.selectedCandidate.name }}</h3>
+      <small>{{ state.selectedCandidate.platform }} · {{ state.selectedCandidate.fans }}粉丝 · {{ state.selectedCandidate.owner }}</small>
+    </div>
+    <em
+      [class.good]="state.selectedCandidate.status === '强推荐'"
+      [class.warn]="state.selectedCandidate.status === '备选'"
+      [class.danger]="state.selectedCandidate.status === '需复核' || state.selectedCandidate.status === '已剔除'"
+    >
+      {{ state.selectedCandidate.status }}
+    </em>
+  </div>
+
+  <div class="detail-actions">
+    <button
+      type="button"
+      *ngFor="let status of statuses"
+      [class.active]="state.selectedCandidate.status === status"
+      (click)="state.updateCandidateStatus(state.selectedCandidate, status)"
+    >
+      {{ status }}
+    </button>
+  </div>
+
+  <div class="detail-metrics">
+    <div>
+      <span>综合分</span>
+      <strong>{{ state.selectedCandidate.score }}</strong>
+    </div>
+    <div>
+      <span>风格匹配</span>
+      <strong>{{ state.selectedCandidate.styleMatch }}%</strong>
+    </div>
+    <div>
+      <span>报价</span>
+      <strong>{{ state.selectedCandidate.price | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }}</strong>
+    </div>
+    <div>
+      <span>数据新鲜度</span>
+      <strong>{{ state.selectedCandidate.dataFreshness }}%</strong>
+    </div>
+  </div>
+
+  <div class="detail-block">
+    <strong>推荐理由</strong>
+    <p>{{ state.selectedCandidate.reason }}</p>
+    <small class="risk">{{ state.selectedCandidate.risk }}</small>
+  </div>
+
+  <div class="quick-review">
+    <button type="button" (click)="state.addCandidateReview('保留为主推,理由是风格和真实体验匹配度高。')">
+      记为主推理由
+    </button>
+    <button type="button" (click)="state.addCandidateReview('报价需要媒介二次确认,先放备选。')">
+      记录报价复核
+    </button>
+    <button type="button" (click)="state.addCandidateReview('内容有硬广或资讯感,建议从客户版隐藏。')">
+      记录排除原因
+    </button>
+  </div>
+
+  <div class="detail-block">
+    <strong>命中规则</strong>
+    <div class="tag-row">
+      <span *ngFor="let hit of state.selectedCandidate.ruleHits">{{ hit }}</span>
+    </div>
+  </div>
+
+  <div class="detail-block">
+    <strong>评分拆解</strong>
+    <div class="breakdown-list">
+      <div *ngFor="let item of state.selectedCandidate.scoreBreakdown">
+        <span>{{ item.label }}</span>
+        <div class="progress"><i [style.width.%]="item.value"></i></div>
+        <em>{{ item.value }}</em>
+      </div>
+    </div>
+  </div>
+
+  <div class="notes-drilldown">
+    <div class="note-list">
+      <div class="section-mini-head">
+        <div>
+          <strong>最近10条笔记</strong>
+          <small>点击查看单条内容证据</small>
+        </div>
+      </div>
+      <div class="note-filter">
+        <button
+          type="button"
+          *ngFor="let verdict of state.noteVerdicts"
+          [class.active]="state.noteVerdictFilter === verdict"
+          (click)="state.setNoteVerdictFilter(verdict)"
+        >
+          {{ verdict }}
+        </button>
+      </div>
+      <button
+        type="button"
+        *ngFor="let note of state.filteredNotes; let index = index"
+        [class.active]="state.selectedNote.id === note.id"
+        (click)="state.selectNote(note)"
+      >
+        <span>{{ index + 1 }}</span>
+        <div>
+          <strong>{{ note.title }}</strong>
+          <small>{{ note.publishTime }} · {{ note.format }} · {{ note.style }}</small>
+        </div>
+        <em>{{ note.match }}%</em>
+        <mark
+          [class.good]="note.verdict === '正向样本'"
+          [class.warn]="note.verdict === '需复核'"
+          [class.danger]="note.verdict === '负向样本'"
+        >
+          {{ note.verdict }}
+        </mark>
+      </button>
+      <p class="empty-state" *ngIf="state.filteredNotes.length === 0">当前筛选下暂无样本,可切回全部查看。</p>
+    </div>
+
+    <article class="note-detail">
+      <p class="eyebrow">笔记详情</p>
+      <h4>{{ state.selectedNote.title }}</h4>
+      <div class="note-meta">
+        <span>{{ state.selectedNote.publishTime }}</span>
+        <span>{{ state.selectedNote.format }}</span>
+        <span>{{ state.selectedNote.style }}</span>
+        <strong>{{ state.selectedNote.match }}% 匹配</strong>
+      </div>
+      <p>{{ state.selectedNote.summary }}</p>
+      <div class="evidence-grid">
+        <div>
+          <span>画面证据</span>
+          <strong>{{ state.selectedNote.visualCue }}</strong>
+        </div>
+        <div>
+          <span>文案证据</span>
+          <strong>{{ state.selectedNote.textCue }}</strong>
+        </div>
+        <div>
+          <span>冲突点</span>
+          <strong>{{ state.selectedNote.mismatch }}</strong>
+        </div>
+      </div>
+      <div class="tag-row">
+        <span *ngFor="let keyword of state.selectedNote.keywords">{{ keyword }}</span>
+      </div>
+      <div class="note-stat-grid">
+        <div><span>阅读/播放</span><strong>{{ state.selectedNote.metrics.read }}</strong></div>
+        <div><span>点赞</span><strong>{{ state.selectedNote.metrics.like }}</strong></div>
+        <div><span>收藏</span><strong>{{ state.selectedNote.metrics.collect }}</strong></div>
+        <div><span>评论</span><strong>{{ state.selectedNote.metrics.comment }}</strong></div>
+      </div>
+      <div class="ai-reason">
+        <strong>AI 判断</strong>
+        <p>{{ state.selectedNote.aiReason }}</p>
+      </div>
+      <div class="note-verdict-actions">
+        <button type="button" (click)="state.markNote(state.selectedNote, '正向样本')">标为正向样本</button>
+        <button type="button" (click)="state.markNote(state.selectedNote, '需复核')">标为需复核</button>
+        <button type="button" (click)="state.markNote(state.selectedNote, '负向样本')">标为负向样本</button>
+      </div>
+    </article>
+  </div>
+</section>

+ 15 - 0
src/app/components/account-detail.component.ts

@@ -0,0 +1,15 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { DemoStateService } from '../demo-state.service';
+import { CandidateStatus } from '../models';
+
+@Component({
+  selector: 'app-account-detail',
+  imports: [CommonModule],
+  templateUrl: './account-detail.component.html'
+})
+export class AccountDetailComponent {
+  statuses: CandidateStatus[] = ['强推荐', '备选', '需复核', '已剔除'];
+
+  constructor(public state: DemoStateService) {}
+}

+ 2461 - 0
src/app/demo-state.service.ts

@@ -0,0 +1,2461 @@
+import { Injectable } from '@angular/core';
+import {
+  AiSelectionStage,
+  Activity,
+  BriefScenario,
+  Candidate,
+  CandidateStatus,
+  DeliveryVersion,
+  FieldMapping,
+  GapItem,
+  InteractionLog,
+  LearnedRule,
+  NavItem,
+  NoteDetail,
+  NoteVerdict,
+  Requirement,
+  ResourceSummary,
+  ResourceFile,
+  ResourceIssue,
+  Rule,
+  RuleTestCase,
+  SamplingTask,
+  Step,
+  TaskTimelineItem,
+  TaskRecord,
+  TemplateField,
+  TemplateItem,
+  ViewKey
+} from './models';
+
+function buildNotes(account: string, styles: string[], startMatch: number): NoteDetail[] {
+  return Array.from({ length: 10 }, (_, index) => {
+    const style = styles[index % styles.length];
+    const match = Math.max(58, startMatch - index * 2 + (index % 3));
+    return {
+      id: `${account}-${index + 1}`,
+      title: [
+        '用了三周的空瓶真实复盘',
+        '通勤包里的急救护肤三件套',
+        '成分党也会喜欢的轻乳霜',
+        '换季敏感肌别再乱叠加',
+        '早八人的极简护肤流程',
+        '这支面霜到底适合谁',
+        '出差三天我只带这几样',
+        '热门配方横评和真实感受',
+        '编辑部最近在用什么',
+        '本周值得看的护肤趋势'
+      ][index],
+      publishTime: `2026-04-${String(28 - index).padStart(2, '0')}`,
+      format: index % 3 === 0 ? '视频' : '图文',
+      style,
+      match,
+      verdict: match >= 82 ? '正向样本' : match >= 76 ? '需复核' : '负向样本',
+      summary: `${account} 近10条内容样本之一,AI 用标题、正文关键词、图片场景和互动反馈判断是否贴合 Brief 的内容风格。`,
+      visualCue:
+        index % 3 === 0
+          ? '封面为真人出镜或产品实拍,画面信息完整。'
+          : '图片以生活场景和局部细节为主,弱化广告感。',
+      textCue:
+        match >= 80
+          ? '正文中出现使用周期、肤感、场景、优缺点等真实体验词。'
+          : '正文偏资讯清单或功效罗列,缺少连续使用体验。',
+      mismatch: match >= 80 ? '暂无明显冲突' : '真实体验占比不足,可能和 Brief 的“不要硬广”要求冲突。',
+      keywords: ['真实体验', style, index % 2 === 0 ? '通勤' : '成分', '非硬广'],
+      metrics: {
+        read: `${8 + index * 2}.${index}万`,
+        like: `${1200 + index * 180}`,
+        collect: `${620 + index * 90}`,
+        comment: `${86 + index * 11}`
+      },
+      aiReason:
+        match >= 80
+          ? '内容表达自然,场景和产品体验占比高,可作为风格匹配证据。'
+          : '资讯或清单感偏重,真实体验表达不足,建议进入人工复核。'
+    };
+  });
+}
+
+function inferFanTier(fans: string): string {
+  const value = Number.parseFloat(fans);
+  if (fans.includes('万') && value >= 50) {
+    return '50万以上';
+  }
+  if (fans.includes('万') && value >= 10) {
+    return '10万-50万';
+  }
+  if (fans.includes('万') && value >= 1) {
+    return '1万-10万';
+  }
+  return '1万以下';
+}
+
+function buildCandidate(input: {
+  id: string;
+  platform: string;
+  name: string;
+  category: string;
+  fans: string;
+  price: number;
+  score: number;
+  styleMatch: number;
+  status: CandidateStatus;
+  tags: string[];
+  reason: string;
+  risk: string;
+  owner: string;
+  supplier: string;
+  dataFreshness: number;
+  priceExpire: string;
+  styles: string[];
+  startMatch: number;
+  readMedian: string;
+  interactionMedian: string;
+  viralRate: number;
+  replyRate: number;
+  fulfillmentRate: number;
+  naturalTrafficRatio: number;
+  cooperationNoteRatio: number;
+  estimatedCpm: number;
+  audienceProfile: string;
+  contentForms: string[];
+  recallSources: string[];
+  serviceLevel: string;
+  brandFit: string;
+  selected?: boolean;
+}): Candidate {
+  return {
+    id: input.id,
+    platform: input.platform,
+    name: input.name,
+    category: input.category,
+    contentForms: input.contentForms,
+    fanTier: inferFanTier(input.fans),
+    fans: input.fans,
+    price: input.price,
+    score: input.score,
+    styleMatch: input.styleMatch,
+    status: input.status,
+    tags: input.tags,
+    reason: input.reason,
+    risk: input.risk,
+    quota: `${input.platform} 扩展池`,
+    selected: input.selected ?? false,
+    link: `https://demo.tihao.ai/${input.platform}/${input.id}`,
+    owner: input.owner,
+    supplier: input.supplier,
+    dataFreshness: input.dataFreshness,
+    priceExpire: input.priceExpire,
+    audienceProfile: input.audienceProfile,
+    readMedian: input.readMedian,
+    interactionMedian: input.interactionMedian,
+    viralRate: input.viralRate,
+    replyRate: input.replyRate,
+    fulfillmentRate: input.fulfillmentRate,
+    naturalTrafficRatio: input.naturalTrafficRatio,
+    cooperationNoteRatio: input.cooperationNoteRatio,
+    estimatedCpm: input.estimatedCpm,
+    cooperationHistory: '近 12 个月有 2-5 次同类客户合作记录',
+    serviceLevel: input.serviceLevel,
+    brandFit: input.brandFit,
+    recallSources: input.recallSources,
+    ruleHits: ['资源库召回', '内容标签匹配', input.serviceLevel, input.brandFit],
+    scoreBreakdown: [
+      { label: '需求匹配', value: Math.min(99, input.score + 1) },
+      { label: '内容表现', value: Math.min(99, input.styleMatch + 2) },
+      { label: '预算健康', value: input.price <= 8000 ? 92 : input.price <= 15000 ? 82 : 72 },
+      { label: '服务履约', value: input.fulfillmentRate }
+    ],
+    recentNotes: buildNotes(input.name, input.styles, input.startMatch)
+  };
+}
+
+@Injectable({ providedIn: 'root' })
+export class DemoStateService {
+  activeView: ViewKey = 'workspace';
+  currentStep = 1;
+  simpleMode = true;
+  showAdvancedWorkspace = false;
+  uploadedFileName = '某品牌种草合作Brief.docx';
+  resourcePath = 'D:\\公司优秀媒体资源库\\4月份资源库';
+  feedbackText =
+    '客户反馈:小红书希望减少泛美妆号,优先生活方式、通勤穿搭、真实测评风格;抖音达人预算再压低15%,保留爆文率高的账号。';
+  exportState = '待生成';
+  apiState = '前端演示数据';
+  tempRuleTitle = '母婴/护肤场景中,近30天评论含“真实有用”的账号加权';
+  tempRuleImpact = '预计强推荐增加 6 个,需复核减少 2 个';
+  selectedPlatform = '全部';
+  selectedStatus: CandidateStatus | '全部' = '全部';
+  budgetMax = 18000;
+  creatorQuery = '护肤 真实测评 通勤生活';
+  creatorPlatform = '全部';
+  creatorCategory = '全部';
+  creatorContentForm = '全部';
+  creatorFanTier = '全部';
+  creatorRisk = '全部';
+  creatorBudgetMax = 15000;
+  sortMode: '综合分' | '风格匹配' | '报价升序' = '综合分';
+  selectedCandidateId = 'M-1087';
+  selectedNoteId = '梨涡测评室-1';
+  noteVerdictFilter: NoteVerdict | '全部' = '全部';
+  compareOpen = false;
+  previewAudience: '客户版' | '内部复核版' = '客户版';
+  selectedResourcePlatform = '小红书';
+  selectedTaskId = 'TH-202605-001';
+  selectedRuleId = 'R-003';
+  ruleSandboxText = '客户要求:真实体验、通勤生活,不要硬广,预算尽量控制在 1 万以内。';
+  ruleSandboxWeight = 80;
+  ruleSimulationState = '尚未试算';
+  templatePreviewMode: '客户版' | '内部复核版' | '复盘版' = '客户版';
+  briefingNote =
+    '目标客户想看的是“工具能不能把经验留下来”,所以 Demo 里要突出可确认、可追溯、可学习,而不是只展示一张漂亮名单。';
+  selectedLearningScope: '本任务' | '单客户' | '行业' | '长期规则' = '本任务';
+  templateUploadState = '等待上传,当前使用系统内置推荐表模板';
+
+  deliveryChecklist = [
+    { label: '客户版隐藏供应商与内部风险', detail: '对客只展示平台、账号、报价、推荐理由和内容证据', done: true },
+    { label: '需复核账号已处理', detail: '导出前强推荐和备选账号不能含未解释风险', done: false },
+    { label: '报价与档期已由媒介确认', detail: '价格过期或未绑定供应商的账号只能进内部版', done: false },
+    { label: '反馈学习入口已准备', detail: '客户驳回原因可回流到规则库,不丢失原文', done: true }
+  ];
+
+  learningScopes: Array<'本任务' | '单客户' | '行业' | '长期规则'> = ['本任务', '单客户', '行业', '长期规则'];
+
+  noteVerdicts: Array<NoteVerdict | '全部'> = ['全部', '正向样本', '需复核', '负向样本'];
+
+  feedbackPresets = [
+    '客户临时要求:小红书主推生活方式,不要泛美妆资讯号。',
+    '商务复核:报价超过预算上限的账号先放备选,除非爆文率明显高。',
+    '媒介反馈:近期未更新价格的账号需要先联系供应商确认档期。',
+    '客户偏好:保留真实空瓶、通勤场景、素人感强的内容样本。'
+  ];
+
+  creatorQuickPrompts = [
+    '找小红书护肤生活方式博主,2k-8k,真实测评,不要硬广',
+    '保留 B站专业背书,补 3 个长视频成分科普账号',
+    '抖音预算压低 15%,只保留爆文率高且报价健康的账号',
+    '参考梨涡测评室,扩展 10 个相似风格中腰部博主'
+  ];
+
+  aiSelectionStages: AiSelectionStage[] = [
+    {
+      title: '需求理解',
+      subtitle: '从 Brief 和临时反馈抽取可执行条件',
+      input: '客户、品牌、平台数量、预算、内容风格、排除项、参考博主',
+      aiJudgement: '识别出“小红书主推真实测评/通勤生活,预算 2k-18k,硬广降级”。',
+      humanControl: '商务可编辑需求点、关闭低置信度推断、追加临时需求。',
+      output: '6 个确认需求点,2 个待复核推断',
+      status: '完成',
+      accounts: ['客户A / 新锐护肤品牌']
+    },
+    {
+      title: '候选召回',
+      subtitle: '像蒲公英一样从多入口找博主',
+      input: '资源库、关键词、相似博主、历史采纳、平台筛选',
+      aiJudgement: '合并 5 类召回来源,去重后形成 324 个候选账号。',
+      humanControl: '媒介可指定参考账号、锁定平台比例、加入手工收藏账号。',
+      output: '小红书 182、抖音 72、B站 28、微信 18、微博 24',
+      status: '完成',
+      accounts: ['梨涡测评室', '晚间护肤手账', '通勤包里有什么']
+    },
+    {
+      title: '硬性过滤',
+      subtitle: '先处理不能推荐或必须降级的账号',
+      input: '黑名单、报价、供应商绑定、报价有效期、近期活跃、合作禁区',
+      aiJudgement: '剔除黑名单和低活跃账号 31 个,报价过期账号进入备选。',
+      humanControl: '媒介可临时放行,但必须填写放行理由。',
+      output: '293 个账号进入评分池',
+      status: '完成',
+      accounts: ['美妆情报局', '护肤趋势观察']
+    },
+    {
+      title: '内容采样',
+      subtitle: '抽取近 10 条内容做风格和硬广判断',
+      input: '标题、正文关键词、图片/视频场景、互动质量、评论反馈',
+      aiJudgement: '真实体验、通勤、成分拆解命中率高的账号加权,资讯/硬广感降权。',
+      humanControl: '单条笔记可标为正向、需复核或负向样本。',
+      output: '已完成 14 个账号采样,4 个仍待媒介确认',
+      status: '进行中',
+      accounts: ['梨涡测评室', '敏感肌自救记录', '阿森护肤实验室']
+    },
+    {
+      title: '多目标评分',
+      subtitle: '把单账号质量变成可解释分数',
+      input: '需求匹配、内容表现、粉丝画像、预算健康、数据新鲜度、服务履约、风险扣分',
+      aiJudgement: '晚间护肤手账因风格和粉丝画像高匹配进入强推荐,微博资讯号降级。',
+      humanControl: '可调整权重并记录为本次任务规则。',
+      output: 'Top 20 推荐池和 Top 60 备选池',
+      status: '进行中',
+      accounts: ['晚间护肤手账', '配方师小简', '打工人变美清单']
+    },
+    {
+      title: '组合配比',
+      subtitle: '避免整份名单同质化',
+      input: '平台比例、头腰尾比例、内容类目、价格带、主推/备选数量',
+      aiJudgement: '控制小红书生活方式占比,保留 B站专业背书和低预算补充位。',
+      humanControl: '可锁定账号、换一批、批量强推/备选/剔除。',
+      output: '客户版 16 个主推 + 12 个备选',
+      status: '待执行',
+      accounts: ['通勤包里有什么', '配方师小简', '周末家居护肤']
+    },
+    {
+      title: '交付与学习',
+      subtitle: '输出客户版,并把反馈变成待确认规则',
+      input: '最终名单、推荐理由、风险说明、客户反馈',
+      aiJudgement: '客户反馈只生成待确认规则,不自动污染长期规则库。',
+      humanControl: '商务确认后入库,可限制规则只对单客户生效。',
+      output: '名单 v1.0 + 待确认规则 3 条',
+      status: '待执行',
+      accounts: ['反馈学习规则']
+    }
+  ];
+
+  deliveryVersions: DeliveryVersion[] = [
+    {
+      version: 'v0.1',
+      title: 'AI 初稿',
+      owner: '系统',
+      time: '2026-05-12 01:20',
+      summary: '按 Brief 生成 104 个候选,输出 Top 20 初稿。',
+      status: '已生成'
+    },
+    {
+      version: 'v0.3',
+      title: '媒介复核版',
+      owner: '媒介-阿敏',
+      time: '2026-05-12 02:05',
+      summary: '剔除 4 个硬广风险账号,补入 B站专业背书账号。',
+      status: '复核中'
+    },
+    {
+      version: 'v1.0',
+      title: '客户交付版',
+      owner: '商务-王一',
+      time: '待导出',
+      summary: '隐藏内部风险字段,只保留推荐理由、报价、内容样本和排期建议。',
+      status: '待交付'
+    }
+  ];
+
+  deliveryFields = [
+    { label: '平台', customer: true, internal: true, selected: true },
+    { label: '账号昵称', customer: true, internal: true, selected: true },
+    { label: '粉丝量', customer: true, internal: true, selected: true },
+    { label: '报价', customer: true, internal: true, selected: true },
+    { label: '推荐理由', customer: true, internal: true, selected: true },
+    { label: '内容样本', customer: true, internal: true, selected: true },
+    { label: '供应商', customer: false, internal: true, selected: this.previewAudience === '内部复核版' },
+    { label: '风险提示', customer: false, internal: true, selected: this.previewAudience === '内部复核版' },
+    { label: '规则命中', customer: false, internal: true, selected: this.previewAudience === '内部复核版' }
+  ];
+
+  resourceHealthItems = [
+    { label: '报价有效率', value: 82, detail: '报价未过期且供应商可确认' },
+    { label: '字段完整率', value: 78, detail: '昵称、链接、报价、互动、供应商字段齐全' },
+    { label: '近30天更新率', value: 69, detail: '本地资源表最近一次更新时间' },
+    { label: '可联系比例', value: 88, detail: '已绑定媒介负责人或供应商联系人' }
+  ];
+
+  resourceFiles: ResourceFile[] = [
+    {
+      platform: '小红书',
+      name: '小红书4月优质种草资源.xlsx',
+      updateTime: '2026-05-10 18:20',
+      rows: 4286,
+      owner: '媒介-阿敏',
+      missingFields: ['报价有效期']
+    },
+    {
+      platform: '抖音',
+      name: '抖音星图护肤达人池.xlsx',
+      updateTime: '2026-05-09 21:10',
+      rows: 2130,
+      owner: '媒介-阿宁',
+      missingFields: ['供应商联系人', '档期']
+    },
+    {
+      platform: 'B站',
+      name: 'B站长视频评测UP主.xlsx',
+      updateTime: '2026-05-08 11:30',
+      rows: 684,
+      owner: '媒介-六月',
+      missingFields: ['近30天播放中位数']
+    },
+    {
+      platform: '微信',
+      name: '公众号图文资源库.xlsx',
+      updateTime: '2026-04-29 16:45',
+      rows: 516,
+      owner: '媒介-小七',
+      missingFields: ['主页链接', '供应商联系人']
+    },
+    {
+      platform: '微博',
+      name: '微博话题扩散账号.xlsx',
+      updateTime: '2026-05-06 14:05',
+      rows: 902,
+      owner: '媒介-小满',
+      missingFields: ['报价有效期', '历史配合度']
+    }
+  ];
+
+  resourceIssues: ResourceIssue[] = [
+    {
+      id: 'RI-001',
+      platform: '小红书',
+      level: '中',
+      title: '报价有效期缺失',
+      detail: '部分资源只有图文报价,缺少报价有效期,导出前需要媒介确认。',
+      action: '批量标为备选并提醒媒介确认',
+      resolved: false
+    },
+    {
+      id: 'RI-002',
+      platform: '抖音',
+      level: '高',
+      title: '高报价账号需要预算复核',
+      detail: '客户压预算后,部分抖音账号仍接近预算上限。',
+      action: '进入预算沙盘,优先保留爆文率高账号',
+      resolved: false
+    },
+    {
+      id: 'RI-003',
+      platform: '微信',
+      level: '高',
+      title: '主页链接不完整',
+      detail: '缺主页链接会影响近10条图文采样和风格比对。',
+      action: '要求资源库补齐链接后再进入强推荐',
+      resolved: false
+    }
+  ];
+
+  ruleConflicts = [
+    {
+      title: '低预算优先 vs 保留头部背书',
+      detail: '客户压预算后,B站专业背书账号报价偏高,需要保留为备选并标注价值。',
+      level: '中'
+    },
+    {
+      title: '真实体验优先 vs 话题扩散',
+      detail: '微博资讯号适合扩散,但和“不要硬广”存在冲突,客户版建议隐藏。',
+      level: '高'
+    }
+  ];
+
+  ruleTestCases: RuleTestCase[] = [
+    {
+      id: 'RTC-001',
+      label: '命中真实体验',
+      condition: '标题/正文出现空瓶、用了三周、真实反馈等词',
+      action: '风格分 +8,推荐理由补充真实体验证据',
+      enabled: true
+    },
+    {
+      id: 'RTC-002',
+      label: '命中硬广表达',
+      condition: '正文偏优惠、强卖点、购买引导,缺少使用过程',
+      action: '降级为需复核,客户版隐藏',
+      enabled: true
+    },
+    {
+      id: 'RTC-003',
+      label: '预算保护',
+      condition: '报价低于预算上限 60%,且互动中位数高于同价位',
+      action: '综合分 +5,进入性价比候选',
+      enabled: false
+    }
+  ];
+
+  briefScenarios: BriefScenario[] = [
+    {
+      id: 'budget-down',
+      label: '客户压预算 15%',
+      description: '报价接近上限的账号降级,低预算高匹配账号加权。',
+      selected: false,
+      impact: '抖音高报价账号转备选,小红书中腰部账号上浮'
+    },
+    {
+      id: 'life-style',
+      label: '小红书偏生活方式',
+      description: '通勤、生活方式、真实分享类账号优先。',
+      selected: false,
+      impact: '通勤/生活方式标签加权,泛美妆资讯降权'
+    },
+    {
+      id: 'strict-style',
+      label: '严格排除硬广',
+      description: '近10条内容匹配低于80%的账号进入复核池。',
+      selected: false,
+      impact: '资讯感强、清单感强的账号不进入强推荐'
+    },
+    {
+      id: 'keep-bilibili',
+      label: '保留 B站专业背书',
+      description: '即使数量少,也保留长视频成分科普账号。',
+      selected: false,
+      impact: 'B站成分科普账号进入备选或强推荐候选'
+    }
+  ];
+
+  interactionLogs: InteractionLog[] = [
+    { time: '10:12', action: 'Brief 解析', detail: '已识别平台、数量、预算和内容风格 6 个需求点。' },
+    { time: '10:18', action: '规则确认', detail: '启用 5 条经验规则,保留 1 条同质化限制待确认。' },
+    { time: '10:24', action: '账号复核', detail: '梨涡测评室被标记为强推荐,近10条样本 9 条符合。' }
+  ];
+
+  navItems: NavItem[] = [
+    { key: 'workspace', label: '提号工作台', note: 'Brief 到推荐名单' },
+    { key: 'creatorSearch', label: '找博主', note: '像蒲公英一样筛人' },
+    { key: 'delivery', label: '名单交付', note: '客户版与内部版' },
+    { key: 'tasks', label: '任务记录', note: '客户需求与版本' },
+    { key: 'resources', label: '资源库', note: '本地媒体表管理' },
+    { key: 'rules', label: '规则库', note: '经验与提炼规则' },
+    { key: 'learning', label: '反馈学习', note: '复盘与自我提升' },
+    { key: 'templates', label: '模板中心', note: 'Brief 与推荐表' }
+  ];
+
+  simpleNavKeys: ViewKey[] = ['workspace', 'creatorSearch', 'delivery', 'tasks'];
+
+  businessShortcuts = [
+    {
+      id: 'fast-list',
+      title: '一键生成可看名单',
+      detail: '自动确认需求、运行规则、完成采样,先拿到可讨论的名单。'
+    },
+    {
+      id: 'review-risk',
+      title: '只看待处理问题',
+      detail: '跳到资源缺口和需复核账号,适合媒介补信息。'
+    },
+    {
+      id: 'client-preview',
+      title: '客户版预览',
+      detail: '隐藏内部风险字段,查看对客话术和推荐理由。'
+    },
+    {
+      id: 'learn-feedback',
+      title: '反馈变规则',
+      detail: '把客户反馈转成待确认规则,保留人工审核。'
+    }
+  ];
+
+  businessChecklist = [
+    { key: 'brief', label: 'Brief 已解析', detail: '客户、平台、预算、风格已抽取' },
+    { key: 'demand', label: '需求已确认', detail: '低置信度内容可编辑' },
+    { key: 'rule', label: '规则已选好', detail: '默认启用核心经验规则' },
+    { key: 'sample', label: '内容已采样', detail: '近10条笔记用于风格比对' },
+    { key: 'export', label: '名单可导出', detail: '客户版和内部版分开输出' }
+  ];
+
+  stepGuides = [
+    {
+      objective: '把客户 Brief 变成可解析任务',
+      operator: '上传或替换 Brief 文件',
+      output: '客户、平台、预算、风格字段'
+    },
+    {
+      objective: '确认 AI 抽取是否准确',
+      operator: '勾选、编辑、补充需求点',
+      output: '可执行需求清单'
+    },
+    {
+      objective: '决定本次提号怎么筛',
+      operator: '启用经验规则或补临时规则',
+      output: '本次任务规则组合'
+    },
+    {
+      objective: '从资源库召回并评分',
+      operator: '运行提号和近10条内容采样',
+      output: '带证据的候选池'
+    },
+    {
+      objective: '复核账号并形成名单',
+      operator: '筛选、标记、查看账号详情',
+      output: '客户版推荐名单'
+    },
+    {
+      objective: '把反馈沉淀成能力',
+      operator: '提炼、确认或驳回规则',
+      output: '可复用规则与记忆'
+    }
+  ];
+
+  steps: Step[] = [
+    { label: '上传 Brief', status: 'active' },
+    { label: '确认需求', status: 'todo' },
+    { label: '选择规则', status: 'todo' },
+    { label: '生成推荐', status: 'todo' },
+    { label: '导出推荐表', status: 'todo' },
+    { label: '反馈学习', status: 'todo' }
+  ];
+
+  templates: TemplateItem[] = [
+    { name: '达人Brief.xlsx', type: 'Brief模板', useCase: '客户标准化需求录入', selected: false },
+    { name: '某品牌种草合作Brief.docx', type: 'Brief模板', useCase: '非结构化需求解析', selected: false },
+    { name: '某品牌达人推广规划.xlsx', type: '规划模板', useCase: '多平台组合拆解', selected: false },
+    { name: '【机构名称】客户+品牌-需求推荐名单.xlsx', type: '推荐表模板', useCase: '对客输出名单', selected: true },
+    { name: '内部复核名单-含风险字段.xlsx', type: '复核模板', useCase: '媒介确认报价、供应商、风险和档期', selected: false },
+    { name: '客户反馈复盘表.xlsx', type: '复盘模板', useCase: '沉淀客户偏好、排除项和长期规则', selected: false }
+  ];
+
+  requirements: Requirement[] = [
+    {
+      label: '客户/品牌',
+      value: '客户A / 新锐护肤品牌',
+      confidence: 96,
+      selected: true,
+      editable: false,
+      evidence: 'Brief 标题:新锐护肤品牌种草合作需求'
+    },
+    {
+      label: '投放目标',
+      value: '新品种草、真实测评、站内转化蓄水',
+      confidence: 92,
+      selected: true,
+      editable: false,
+      evidence: 'Brief 目标:新品首发,希望突出真实使用体验'
+    },
+    {
+      label: '平台需求',
+      value: '小红书 20人、抖音 8人、B站 4人',
+      confidence: 90,
+      selected: true,
+      editable: false,
+      evidence: '达人推广规划 Sheet:平台配比'
+    },
+    {
+      label: '预算边界',
+      value: '单号 2,000-18,000,优先性价比',
+      confidence: 84,
+      selected: true,
+      editable: false,
+      evidence: '预算列存在多个空值,AI 按已填区间推断'
+    },
+    {
+      label: '内容风格',
+      value: '真实体验、通勤生活、轻专业成分党',
+      confidence: 88,
+      selected: true,
+      editable: false,
+      evidence: 'Brief 原文:不要硬广,要像真实分享'
+    },
+    {
+      label: '排除项',
+      value: '硬广感强、近30天低活跃、黑名单供应商',
+      confidence: 82,
+      selected: true,
+      editable: false,
+      evidence: '规则库默认风控项 + Brief 排除描述'
+    }
+  ];
+
+  rules: Rule[] = [
+    {
+      id: 'R-001',
+      title: '按 Brief 平台优先提号',
+      description: '先满足 Brief 明确指定的平台,再用相邻平台补足备选池。',
+      category: '平台响应',
+      source: '经验规则',
+      selected: true,
+      impact: '确保客户要求不被泛化'
+    },
+    {
+      id: 'R-002',
+      title: '默认推荐数量不少于需求 3 倍',
+      description: '当 Brief 写明数量时,候选池按需求数量的 3 倍以上生成,便于商务二次筛选。',
+      category: '数量策略',
+      source: '经验规则',
+      selected: true,
+      impact: '小红书候选池 60 个,抖音 24 个,B站 12 个'
+    },
+    {
+      id: 'R-003',
+      title: '风格匹配低于 80% 自动降级',
+      description: '需要风格比对时,采样账号近 10 篇内容,图文/标题/标签综合匹配不足 80% 标记为需复核。',
+      category: '内容风格',
+      source: '经验规则',
+      selected: true,
+      impact: '减少客户返工'
+    },
+    {
+      id: 'R-004',
+      title: '黑名单与低配合度剔除',
+      description: '历史拉黑、配合度低、供应商关系未绑定的媒体默认不进入强推荐。',
+      category: '风险控制',
+      source: '经验规则',
+      selected: true,
+      impact: '降低执行风险'
+    },
+    {
+      id: 'R-005',
+      title: '优先近期采集有效价格',
+      description: '报价有效期已过或采集超过 45 天的资源进入备选,并提示媒介复核。',
+      category: '价格有效性',
+      source: 'AI提炼',
+      selected: true,
+      impact: '避免报价失真'
+    },
+    {
+      id: 'R-006',
+      title: '同质化账号限额',
+      description: '同一平台同一内容类目强推荐不超过 40%,避免名单看起来重复。',
+      category: '组合均衡',
+      source: '用户反馈',
+      selected: false,
+      impact: '提升名单丰富度'
+    }
+  ];
+
+  candidates: Candidate[] = [
+    {
+      id: 'M-1087',
+      platform: '小红书',
+      name: '梨涡测评室',
+      fans: '18.6万',
+      price: 6800,
+      score: 94,
+      styleMatch: 91,
+      status: '强推荐',
+      tags: ['真实测评', '成分党', '图文强'],
+      reason: '近10篇中 9 篇为真实体验或成分拆解,互动中位数高于同价位账号 28%。',
+      risk: '视频内容偏少,可作为图文主推。',
+      quota: '小红书 1/60',
+      selected: true,
+      link: 'https://www.xiaohongshu.com/user/profile/demo1087',
+      owner: '媒介-阿敏',
+      supplier: '杭州某MCN',
+      dataFreshness: 92,
+      priceExpire: '2026-05-31',
+      ruleHits: ['平台优先', '风格>80%', '报价有效', '供应商已绑定'],
+      scoreBreakdown: [
+        { label: '需求匹配', value: 95 },
+        { label: '历史表现', value: 89 },
+        { label: '风险健康', value: 96 }
+      ],
+      recentNotes: buildNotes('梨涡测评室', ['真实测评', '通勤生活', '成分拆解'], 94)
+    },
+    {
+      id: 'M-2214',
+      platform: '小红书',
+      name: '通勤包里有什么',
+      fans: '9.4万',
+      price: 3600,
+      score: 89,
+      styleMatch: 86,
+      status: '强推荐',
+      tags: ['生活方式', '通勤', '性价比'],
+      reason: '内容场景和 Brief 的通勤生活需求贴合,历史合作反馈为配合度高。',
+      risk: '粉丝量中腰部,需要搭配高粉账号。',
+      quota: '小红书 2/60',
+      selected: true,
+      link: 'https://www.xiaohongshu.com/user/profile/demo2214',
+      owner: '媒介-小徐',
+      supplier: '上海生活方式MCN',
+      dataFreshness: 87,
+      priceExpire: '2026-05-25',
+      ruleHits: ['数量池补足', '生活方式加权', '低预算友好'],
+      scoreBreakdown: [
+        { label: '需求匹配', value: 88 },
+        { label: '历史表现', value: 82 },
+        { label: '风险健康', value: 92 }
+      ],
+      recentNotes: buildNotes('通勤包里有什么', ['通勤生活', '真实分享', '生活方式'], 90)
+    },
+    {
+      id: 'M-3309',
+      platform: '抖音',
+      name: '林小林认真护肤',
+      fans: '42.1万',
+      price: 12800,
+      score: 87,
+      styleMatch: 82,
+      status: '备选',
+      tags: ['口播', '测评', '转化'],
+      reason: '爆文率和完播率表现稳定,预算接近上限,建议作为抖音头部备选。',
+      risk: '单条报价较高,需确认档期。',
+      quota: '抖音 1/24',
+      selected: true,
+      link: 'https://www.douyin.com/user/demo3309',
+      owner: '媒介-阿宁',
+      supplier: '星图服务商',
+      dataFreshness: 78,
+      priceExpire: '2026-05-18',
+      ruleHits: ['平台优先', '爆文率保护', '预算接近上限'],
+      scoreBreakdown: [
+        { label: '需求匹配', value: 84 },
+        { label: '历史表现', value: 91 },
+        { label: '风险健康', value: 78 }
+      ],
+      recentNotes: buildNotes('林小林认真护肤', ['口播测评', '真实测评', '科普'], 84)
+    },
+    {
+      id: 'M-4402',
+      platform: 'B站',
+      name: '阿澈的成分笔记',
+      fans: '13.2万',
+      price: 9800,
+      score: 84,
+      styleMatch: 88,
+      status: '备选',
+      tags: ['长视频', '成分科普', '深度测评'],
+      reason: '长视频讲解能力强,适合承接品牌专业背书。',
+      risk: '制作周期较长。',
+      quota: 'B站 1/12',
+      selected: true,
+      link: 'https://space.bilibili.com/demo4402',
+      owner: '媒介-六月',
+      supplier: '独立UP主',
+      dataFreshness: 74,
+      priceExpire: '2026-06-05',
+      ruleHits: ['B站补充背书', '成分党加权', '制作周期提示'],
+      scoreBreakdown: [
+        { label: '需求匹配', value: 85 },
+        { label: '历史表现', value: 80 },
+        { label: '风险健康', value: 84 }
+      ],
+      recentNotes: buildNotes('阿澈的成分笔记', ['成分科普', '深度测评', '科普'], 91)
+    },
+    {
+      id: 'M-5520',
+      platform: '微信',
+      name: '美妆情报局',
+      fans: '7.8万',
+      price: 5200,
+      score: 78,
+      styleMatch: 73,
+      status: '需复核',
+      tags: ['图文', '资讯', '价格友好'],
+      reason: '预算友好,但近10篇资讯感较重,和真实测评风格存在偏差。',
+      risk: '风格匹配不足 80%,需人工确认。',
+      quota: '补充平台',
+      selected: false,
+      link: 'https://mp.weixin.qq.com/demo5520',
+      owner: '媒介-小七',
+      supplier: '公众号资源组',
+      dataFreshness: 61,
+      priceExpire: '2026-05-12',
+      ruleHits: ['价格友好', '风格不足80%', '需复核'],
+      scoreBreakdown: [
+        { label: '需求匹配', value: 72 },
+        { label: '历史表现', value: 76 },
+        { label: '风险健康', value: 69 }
+      ],
+      recentNotes: buildNotes('美妆情报局', ['资讯', '清单', '趋势'], 73)
+    },
+    buildCandidate({
+      id: 'M-6101',
+      platform: '小红书',
+      name: '晚间护肤手账',
+      category: '护肤',
+      fans: '26.3万',
+      price: 8200,
+      score: 91,
+      styleMatch: 93,
+      status: '强推荐',
+      tags: ['空瓶', '真实体验', '生活方式'],
+      reason: '长期做空瓶和敏感肌日记,内容语气自然,适合新品真实种草。',
+      risk: '档期较满,需要提前 10 天锁定。',
+      owner: '媒介-小乔',
+      supplier: '华东生活方式资源组',
+      dataFreshness: 91,
+      priceExpire: '2026-06-08',
+      styles: ['空瓶复盘', '真实测评', '生活方式'],
+      startMatch: 93,
+      readMedian: '9.8万',
+      interactionMedian: '4860',
+      viralRate: 18,
+      replyRate: 94,
+      fulfillmentRate: 96,
+      naturalTrafficRatio: 82,
+      cooperationNoteRatio: 22,
+      estimatedCpm: 84,
+      audienceProfile: '女性 25-34 岁,一二线城市占比 58%,护肤消费兴趣高',
+      contentForms: ['图文', '视频'],
+      recallSources: ['关键词召回', '相似博主召回', '历史采纳召回'],
+      serviceLevel: '高配合度',
+      brandFit: '护肤新品高匹配',
+      selected: true
+    }),
+    buildCandidate({
+      id: 'M-6102',
+      platform: '小红书',
+      name: '打工人变美清单',
+      category: '美妆',
+      fans: '11.7万',
+      price: 4800,
+      score: 88,
+      styleMatch: 87,
+      status: '强推荐',
+      tags: ['通勤', '清单', '性价比'],
+      reason: '通勤场景稳定,报价健康,可补足中腰部生活方式账号。',
+      risk: '清单型内容较多,需要脚本里强化单品体验。',
+      owner: '媒介-小徐',
+      supplier: '上海通勤内容组',
+      dataFreshness: 89,
+      priceExpire: '2026-06-01',
+      styles: ['通勤生活', '清单', '真实分享'],
+      startMatch: 88,
+      readMedian: '6.2万',
+      interactionMedian: '2510',
+      viralRate: 14,
+      replyRate: 91,
+      fulfillmentRate: 94,
+      naturalTrafficRatio: 76,
+      cooperationNoteRatio: 28,
+      estimatedCpm: 77,
+      audienceProfile: '女性 22-30 岁,新一线/二线城市白领占比高',
+      contentForms: ['图文'],
+      recallSources: ['条件筛选召回', '关键词召回'],
+      serviceLevel: '高配合度',
+      brandFit: '预算友好'
+    }),
+    buildCandidate({
+      id: 'M-6103',
+      platform: '小红书',
+      name: '敏感肌自救记录',
+      category: '护肤',
+      fans: '7.2万',
+      price: 3900,
+      score: 86,
+      styleMatch: 90,
+      status: '备选',
+      tags: ['敏感肌', '真实测评', '素人感'],
+      reason: '素人感强,评论区真实问题多,适合作为可信样本补充。',
+      risk: '粉丝规模偏小,建议搭配高互动账号。',
+      owner: '媒介-阿敏',
+      supplier: '独立博主',
+      dataFreshness: 84,
+      priceExpire: '2026-05-29',
+      styles: ['敏感肌', '真实测评', '素人分享'],
+      startMatch: 89,
+      readMedian: '4.1万',
+      interactionMedian: '1790',
+      viralRate: 12,
+      replyRate: 86,
+      fulfillmentRate: 88,
+      naturalTrafficRatio: 88,
+      cooperationNoteRatio: 12,
+      estimatedCpm: 69,
+      audienceProfile: '女性 20-32 岁,敏感肌与成分党标签集中',
+      contentForms: ['图文', '视频'],
+      recallSources: ['关键词召回', '内容样本召回'],
+      serviceLevel: '稳定履约',
+      brandFit: '风格高匹配'
+    }),
+    buildCandidate({
+      id: 'M-6201',
+      platform: '抖音',
+      name: '七七成分开麦',
+      category: '护肤',
+      fans: '68.5万',
+      price: 18500,
+      score: 83,
+      styleMatch: 85,
+      status: '备选',
+      tags: ['口播', '成分科普', '爆文率高'],
+      reason: '完播和爆文率强,适合作为抖音声量位,但预算压力较大。',
+      risk: '报价超过当前建议上限,需谈价或只保留备选。',
+      owner: '媒介-阿宁',
+      supplier: '星图服务商',
+      dataFreshness: 86,
+      priceExpire: '2026-05-26',
+      styles: ['成分科普', '口播测评', '转化'],
+      startMatch: 86,
+      readMedian: '46万',
+      interactionMedian: '1.8万',
+      viralRate: 22,
+      replyRate: 82,
+      fulfillmentRate: 89,
+      naturalTrafficRatio: 63,
+      cooperationNoteRatio: 41,
+      estimatedCpm: 146,
+      audienceProfile: '女性 24-35 岁,护肤功效兴趣强,三线以上城市占比 64%',
+      contentForms: ['视频'],
+      recallSources: ['平台筛选召回', '历史表现召回'],
+      serviceLevel: '稳定履约',
+      brandFit: '专业背书'
+    }),
+    buildCandidate({
+      id: 'M-6202',
+      platform: '抖音',
+      name: '小麦真实开箱',
+      category: '美妆',
+      fans: '23.9万',
+      price: 7600,
+      score: 85,
+      styleMatch: 81,
+      status: '备选',
+      tags: ['开箱', '测评', '转化'],
+      reason: '开箱测评节奏好,价格在预算中段,适合补转化素材。',
+      risk: '护肤深度不足,需要提供产品体验脚本。',
+      owner: '媒介-南南',
+      supplier: '短视频资源组',
+      dataFreshness: 79,
+      priceExpire: '2026-05-20',
+      styles: ['开箱', '口播测评', '真实分享'],
+      startMatch: 82,
+      readMedian: '18万',
+      interactionMedian: '6900',
+      viralRate: 16,
+      replyRate: 84,
+      fulfillmentRate: 91,
+      naturalTrafficRatio: 68,
+      cooperationNoteRatio: 35,
+      estimatedCpm: 96,
+      audienceProfile: '女性 18-28 岁,彩妆/护肤兴趣重叠',
+      contentForms: ['视频'],
+      recallSources: ['条件筛选召回', '预算策略召回'],
+      serviceLevel: '稳定履约',
+      brandFit: '转化补充'
+    }),
+    buildCandidate({
+      id: 'M-6203',
+      platform: '抖音',
+      name: '阿森护肤实验室',
+      category: '护肤',
+      fans: '15.8万',
+      price: 6800,
+      score: 82,
+      styleMatch: 78,
+      status: '需复核',
+      tags: ['实验', '功效', '男性视角'],
+      reason: '专业表达强,但画面偏实验室感,和生活方式 Brief 有偏差。',
+      risk: '风格匹配低于 80%,客户版需谨慎呈现。',
+      owner: '媒介-六月',
+      supplier: '独立达人',
+      dataFreshness: 72,
+      priceExpire: '2026-05-19',
+      styles: ['实验测评', '成分科普', '功效'],
+      startMatch: 79,
+      readMedian: '11万',
+      interactionMedian: '4200',
+      viralRate: 11,
+      replyRate: 78,
+      fulfillmentRate: 86,
+      naturalTrafficRatio: 71,
+      cooperationNoteRatio: 32,
+      estimatedCpm: 91,
+      audienceProfile: '男女比例接近,功效护肤兴趣高',
+      contentForms: ['视频'],
+      recallSources: ['内容标签召回'],
+      serviceLevel: '需沟通确认',
+      brandFit: '需风格复核'
+    }),
+    buildCandidate({
+      id: 'M-6301',
+      platform: 'B站',
+      name: '配方师小简',
+      category: '护肤',
+      fans: '31.4万',
+      price: 16800,
+      score: 90,
+      styleMatch: 92,
+      status: '强推荐',
+      tags: ['长视频', '成分科普', '专业背书'],
+      reason: '长视频解释能力强,适合承担品牌专业背书和搜索留存。',
+      risk: '制作周期 14 天,需先锁定脚本窗口。',
+      owner: '媒介-六月',
+      supplier: '独立UP主',
+      dataFreshness: 82,
+      priceExpire: '2026-06-12',
+      styles: ['成分科普', '长视频测评', '专业拆解'],
+      startMatch: 92,
+      readMedian: '13万',
+      interactionMedian: '5300',
+      viralRate: 13,
+      replyRate: 88,
+      fulfillmentRate: 92,
+      naturalTrafficRatio: 79,
+      cooperationNoteRatio: 24,
+      estimatedCpm: 126,
+      audienceProfile: '女性 23-35 岁,成分党、学生党与白领混合',
+      contentForms: ['长视频', '图文'],
+      recallSources: ['相似博主召回', '历史采纳召回'],
+      serviceLevel: '稳定履约',
+      brandFit: '专业背书高匹配',
+      selected: true
+    }),
+    buildCandidate({
+      id: 'M-6302',
+      platform: 'B站',
+      name: '护肤避坑研究员',
+      category: '护肤',
+      fans: '8.9万',
+      price: 7200,
+      score: 81,
+      styleMatch: 84,
+      status: '备选',
+      tags: ['避坑', '深度测评', '学生党'],
+      reason: '评论区信任度高,适合做备选口碑内容。',
+      risk: '更新频率一般,需要确认排期。',
+      owner: '媒介-小七',
+      supplier: '独立UP主',
+      dataFreshness: 69,
+      priceExpire: '2026-05-30',
+      styles: ['避坑', '深度测评', '成分科普'],
+      startMatch: 85,
+      readMedian: '5.7万',
+      interactionMedian: '2100',
+      viralRate: 9,
+      replyRate: 80,
+      fulfillmentRate: 84,
+      naturalTrafficRatio: 83,
+      cooperationNoteRatio: 18,
+      estimatedCpm: 102,
+      audienceProfile: '女性 18-26 岁,学生党与初入职场占比较高',
+      contentForms: ['长视频'],
+      recallSources: ['关键词召回', '平台策略召回'],
+      serviceLevel: '需沟通确认',
+      brandFit: '备选口碑'
+    }),
+    buildCandidate({
+      id: 'M-6401',
+      platform: '微信',
+      name: '成分慢读',
+      category: '护肤',
+      fans: '12.5万',
+      price: 9600,
+      score: 79,
+      styleMatch: 80,
+      status: '备选',
+      tags: ['公众号', '深度图文', '专业'],
+      reason: '适合承接长图文解释,补足私域和搜索沉淀。',
+      risk: '平台不在主需求中,需要客户确认是否保留。',
+      owner: '媒介-小七',
+      supplier: '公众号资源组',
+      dataFreshness: 65,
+      priceExpire: '2026-05-22',
+      styles: ['深度图文', '成分科普', '趋势'],
+      startMatch: 81,
+      readMedian: '3.4万',
+      interactionMedian: '980',
+      viralRate: 6,
+      replyRate: 76,
+      fulfillmentRate: 87,
+      naturalTrafficRatio: 74,
+      cooperationNoteRatio: 29,
+      estimatedCpm: 132,
+      audienceProfile: '女性 28-40 岁,高线城市和高消费力用户偏多',
+      contentForms: ['图文'],
+      recallSources: ['资源库召回'],
+      serviceLevel: '稳定履约',
+      brandFit: '补充平台'
+    }),
+    buildCandidate({
+      id: 'M-6501',
+      platform: '微博',
+      name: '护肤趋势观察',
+      category: '美妆',
+      fans: '54.6万',
+      price: 11800,
+      score: 76,
+      styleMatch: 72,
+      status: '需复核',
+      tags: ['趋势', '话题扩散', '资讯'],
+      reason: '适合话题扩散,但内容资讯感强,不适合作为主推真实测评。',
+      risk: '硬广和资讯感风险,需要从客户版隐藏或降级。',
+      owner: '媒介-阿宁',
+      supplier: '微博资源组',
+      dataFreshness: 70,
+      priceExpire: '2026-06-02',
+      styles: ['趋势', '资讯', '话题'],
+      startMatch: 74,
+      readMedian: '22万',
+      interactionMedian: '3600',
+      viralRate: 10,
+      replyRate: 73,
+      fulfillmentRate: 82,
+      naturalTrafficRatio: 58,
+      cooperationNoteRatio: 44,
+      estimatedCpm: 112,
+      audienceProfile: '泛美妆兴趣人群,话题扩散强但转化弱',
+      contentForms: ['图文', '短内容'],
+      recallSources: ['平台补充召回'],
+      serviceLevel: '需沟通确认',
+      brandFit: '话题扩散'
+    }),
+    buildCandidate({
+      id: 'M-6601',
+      platform: '小红书',
+      name: '妈妈的浴室柜',
+      category: '母婴',
+      fans: '16.9万',
+      price: 6200,
+      score: 84,
+      styleMatch: 83,
+      status: '备选',
+      tags: ['母婴', '家庭场景', '温和护肤'],
+      reason: '家庭和温和护肤场景自然,适合敏感肌线索扩展。',
+      risk: '主目标不是母婴,需要确认是否纳入多场景名单。',
+      owner: '媒介-小乔',
+      supplier: '母婴生活资源组',
+      dataFreshness: 88,
+      priceExpire: '2026-06-04',
+      styles: ['家庭场景', '温和护肤', '真实分享'],
+      startMatch: 84,
+      readMedian: '7.3万',
+      interactionMedian: '2900',
+      viralRate: 13,
+      replyRate: 89,
+      fulfillmentRate: 93,
+      naturalTrafficRatio: 81,
+      cooperationNoteRatio: 19,
+      estimatedCpm: 86,
+      audienceProfile: '女性 25-38 岁,妈妈人群和敏感肌标签重叠',
+      contentForms: ['图文', '视频'],
+      recallSources: ['场景扩展召回'],
+      serviceLevel: '高配合度',
+      brandFit: '场景扩展'
+    }),
+    buildCandidate({
+      id: 'M-6701',
+      platform: '小红书',
+      name: '周末家居护肤',
+      category: '家居',
+      fans: '6.4万',
+      price: 3100,
+      score: 80,
+      styleMatch: 82,
+      status: '备选',
+      tags: ['家居', '生活方式', '低预算'],
+      reason: '生活方式感强,价格友好,可作为低预算补充。',
+      risk: '护肤内容占比不足,需要限定选题。',
+      owner: '媒介-小徐',
+      supplier: '生活方式资源组',
+      dataFreshness: 83,
+      priceExpire: '2026-05-28',
+      styles: ['家居生活', '生活方式', '真实分享'],
+      startMatch: 83,
+      readMedian: '3.6万',
+      interactionMedian: '1320',
+      viralRate: 8,
+      replyRate: 87,
+      fulfillmentRate: 90,
+      naturalTrafficRatio: 84,
+      cooperationNoteRatio: 15,
+      estimatedCpm: 72,
+      audienceProfile: '女性 23-34 岁,家居和通勤生活兴趣高',
+      contentForms: ['图文'],
+      recallSources: ['相似场景召回'],
+      serviceLevel: '稳定履约',
+      brandFit: '低预算补充'
+    })
+  ];
+
+  private candidateBaseline = new Map(
+    this.candidates.map((candidate) => [
+      candidate.id,
+      {
+        score: candidate.score,
+        styleMatch: candidate.styleMatch,
+        status: candidate.status,
+        selected: candidate.selected,
+        risk: candidate.risk,
+        reason: candidate.reason,
+        ruleHits: [...candidate.ruleHits]
+      }
+    ])
+  );
+
+  resources: ResourceSummary[] = [
+    { platform: '小红书', total: 4286, fresh: 86, matched: 182, status: '主力平台' },
+    { platform: '抖音', total: 2130, fresh: 79, matched: 72, status: '预算复核' },
+    { platform: 'B站', total: 684, fresh: 73, matched: 28, status: '补充背书' },
+    { platform: '微信', total: 516, fresh: 61, matched: 18, status: '待人工确认' },
+    { platform: '微博', total: 902, fresh: 69, matched: 24, status: '话题扩散' }
+  ];
+
+  fieldMappings: FieldMapping[] = [
+    { source: '达人昵称', target: 'accountName', confidence: 98, confirmed: true },
+    { source: '平台ID/主页链接', target: 'platformId / link', confidence: 94, confirmed: true },
+    { source: '报价-图文', target: 'imagePrice', confidence: 91, confirmed: true },
+    { source: '近30天互动中位数', target: 'interactionMedian', confidence: 88, confirmed: false },
+    { source: '供应商联系人', target: 'supplierContact', confidence: 84, confirmed: false },
+    { source: '备注/特殊要求', target: 'riskNote', confidence: 71, confirmed: false }
+  ];
+
+  activities: Activity[] = [
+    { title: '解析 Brief 表格/文档', detail: '识别客户、品牌、平台、数量、预算、内容风格与排除项', status: '完成' },
+    { title: '读取本地媒体资源库', detail: '模拟扫描 D 盘资源库,多平台字段完成统一映射', status: '完成' },
+    { title: '执行规则与评分', detail: '数量、价格、风格、风险、供应商关系进入综合评分', status: '进行中' },
+    { title: '后台实时采样', detail: '需要登录平台采集近10篇内容时进入异步任务队列', status: '待执行' }
+  ];
+
+  samplingTasks: SamplingTask[] = [
+    { account: '梨涡测评室', platform: '小红书', progress: 100, status: '完成', result: '9/10 篇符合真实测评或成分拆解' },
+    { account: '通勤包里有什么', platform: '小红书', progress: 100, status: '完成', result: '8/10 篇符合通勤生活场景' },
+    { account: '林小林认真护肤', platform: '抖音', progress: 70, status: '进行中', result: '已采样 7 条视频,风格暂定 82%' },
+    { account: '美妆情报局', platform: '微信', progress: 40, status: '待执行', result: '等待公众号图文采样' }
+  ];
+
+  learnedRules: LearnedRule[] = [
+    {
+      title: '客户反馈中的明确偏好要先转成排除和加分项',
+      description: '当反馈出现“减少/不要/优先/保留”等词时,提炼为可确认规则,不直接静默生效。',
+      confidence: 91,
+      action: '生成待确认规则',
+      approved: false
+    }
+  ];
+
+  gapItems: GapItem[] = [
+    { title: '需求点需要可编辑和可追溯', current: '原 Demo 只有勾选,缺少原文证据和修正入口。', suggestion: '补充编辑状态、证据来源、手动新增需求。', done: true },
+    { title: '资源库需要展示字段映射', current: '只展示各平台数量,客户看不到本地表如何被 AI 理解。', suggestion: '增加字段映射确认、资源目录检测和同步动作。', done: true },
+    { title: '风格比对需要有过程', current: '只展示结果分,缺少近10篇内容采样的可解释过程。', suggestion: '增加后台采样队列、样本标题、风格命中率。', done: true },
+    { title: '推荐名单需要二次筛选', current: '只展示卡片,缺少平台/状态/预算过滤和账号详情。', suggestion: '增加筛选、排序、详情侧栏、状态调整。', done: true },
+    { title: '自我提升需要审核机制', current: '反馈提炼后直接加入规则,容易让客户担心 AI 乱学。', suggestion: '保留“待确认-入库”的人工审核链路。', done: true }
+  ];
+
+  taskRecords: TaskRecord[] = [
+    { id: 'TH-202605-001', brand: '客户A / 新锐护肤品牌', status: '提号中', owner: '商务-王一', version: '名单 v0.3', lastAction: '已生成候选池,等待商务复核' },
+    { id: 'TH-202604-028', brand: '客户B / 食饮新品', status: '已交付', owner: '商务-李想', version: '名单 v1.2', lastAction: '客户反馈已提炼 2 条规则' },
+    { id: 'TH-202604-019', brand: '客户C / 家清系列', status: '待确认', owner: '商务-陈晨', version: '需求 v0.1', lastAction: '等待确认平台数量' },
+    { id: 'TH-202604-033', brand: '客户D / 母婴洗护', status: '待复盘', owner: '商务-周周', version: '反馈 v0.2', lastAction: '客户要求减少硬广达人,规则待确认入库' },
+    { id: 'TH-202605-006', brand: '客户E / 家居香氛', status: '资源同步', owner: '商务-林夕', version: '资源 v0.1', lastAction: '正在映射小红书和微信资源字段' },
+    { id: 'TH-202605-009', brand: '客户F / 数码配件', status: '待采样', owner: '商务-阿树', version: '名单 v0.1', lastAction: 'B站长视频账号等待近10条内容采样' },
+    { id: 'TH-202605-012', brand: '客户G / 轻食新品', status: '已交付', owner: '商务-小满', version: '名单 v1.0', lastAction: '客户版名单已导出,等待投放结果回填' }
+  ];
+
+  taskTimeline: TaskTimelineItem[] = [
+    {
+      taskId: 'TH-202605-001',
+      time: '2026-05-12 09:18',
+      title: 'Brief 上传并解析',
+      detail: '识别客户、品牌、平台数量、预算和内容风格。'
+    },
+    {
+      taskId: 'TH-202605-001',
+      time: '2026-05-12 09:31',
+      title: '生成候选池',
+      detail: '从资源库召回 324 个账号,去重后 293 个进入评分池。'
+    },
+    {
+      taskId: 'TH-202605-001',
+      time: '2026-05-12 10:05',
+      title: '媒介复核',
+      detail: '剔除硬广风险账号 4 个,补入 B站专业背书账号。'
+    },
+    {
+      taskId: 'TH-202604-028',
+      time: '2026-04-28 16:40',
+      title: '客户反馈回收',
+      detail: '客户要求减少泛美食资讯号,已提炼 2 条行业偏好规则。'
+    },
+    {
+      taskId: 'TH-202605-006',
+      time: '2026-05-12 08:55',
+      title: '资源同步',
+      detail: '正在映射小红书和微信资源字段,等待供应商联系人补齐。'
+    }
+  ];
+
+  templateFields: TemplateField[] = [
+    { label: '平台', source: '资源库/Brief', customer: true, internal: true, required: true, selected: true },
+    { label: '账号昵称', source: '资源库', customer: true, internal: true, required: true, selected: true },
+    { label: '主页链接', source: '资源库', customer: true, internal: true, required: true, selected: true },
+    { label: '粉丝量', source: '资源库', customer: true, internal: true, required: true, selected: true },
+    { label: '图文/视频报价', source: '资源库', customer: true, internal: true, required: true, selected: true },
+    { label: '推荐理由', source: 'AI生成+人工复核', customer: true, internal: true, required: true, selected: true },
+    { label: '近10条样本', source: '后台采样', customer: true, internal: true, required: false, selected: true },
+    { label: '供应商/联系人', source: '资源库', customer: false, internal: true, required: true, selected: true },
+    { label: '风险提示', source: '规则库', customer: false, internal: true, required: false, selected: true },
+    { label: '客户采纳结果', source: '复盘回填', customer: false, internal: true, required: false, selected: false }
+  ];
+
+  get selectedRulesCount(): number {
+    return this.rules.filter((rule) => rule.selected).length;
+  }
+
+  get selectedCandidatesCount(): number {
+    return this.filteredCandidates.filter((candidate) => candidate.selected).length;
+  }
+
+  get visibleNavItems(): NavItem[] {
+    if (!this.simpleMode) {
+      return this.navItems;
+    }
+    const simpleKeys = new Set<ViewKey>([...this.simpleNavKeys, this.activeView]);
+    return this.navItems.filter((item) => simpleKeys.has(item.key));
+  }
+
+  get activeNavItem(): NavItem {
+    return this.navItems.find((item) => item.key === this.activeView) ?? this.navItems[0];
+  }
+
+  get taskDisplayName(): string {
+    return '客户A / 新锐护肤品牌种草合作';
+  }
+
+  get deliveryStatusLabel(): string {
+    if (this.currentStep < 4) {
+      return '名单待生成';
+    }
+    if (this.currentStep === 4) {
+      return '推荐生成中';
+    }
+    return `交付准备度 ${this.exportReadiness}%`;
+  }
+
+  get nextAction(): { title: string; detail: string } {
+    if (this.currentStep <= 1) {
+      return { title: '解析 Brief', detail: '识别客户、平台、数量、预算、内容风格和排除项。' };
+    }
+    if (this.currentStep === 2) {
+      return { title: '确认需求', detail: '保留已勾选需求,进入规则选择和提号。' };
+    }
+    if (this.currentStep === 3) {
+      return { title: '生成推荐池', detail: '按已选规则从资源库召回账号,进入采样和评分。' };
+    }
+    if (this.currentStep === 4 && this.samplingTasks.some((task) => task.status !== '完成')) {
+      return { title: '完成近10条采样', detail: '把风格比对证据补齐,降低客户返工风险。' };
+    }
+    if (this.currentStep === 4) {
+      return { title: '查看推荐名单', detail: '进入账号复核和最近10条内容证据。' };
+    }
+    if (this.currentStep === 5) {
+      return { title: '进入客户版交付', detail: '隐藏内部风险字段,预览对客版本并准备导出。' };
+    }
+    return { title: '提炼反馈规则', detail: '把客户反馈生成待确认规则,人工确认后入库。' };
+  }
+
+  get currentStepGuide(): { objective: string; operator: string; output: string } {
+    return this.stepGuides[this.currentStep - 1] ?? this.stepGuides[0];
+  }
+
+  get checklistDoneCount(): number {
+    return this.businessChecklist.filter((item) => this.isChecklistDone(item.key)).length;
+  }
+
+  get selectedCandidateList(): Candidate[] {
+    return this.candidates.filter((candidate) => candidate.selected && candidate.status !== '已剔除');
+  }
+
+  get reviewQueueCandidates(): Candidate[] {
+    return this.candidates.filter((candidate) => candidate.status === '需复核' || candidate.status === '已剔除').slice(0, 5);
+  }
+
+  get creatorShortlistCandidates(): Candidate[] {
+    return this.creatorFilteredCandidates.slice(0, 8);
+  }
+
+  get compareCandidates(): Candidate[] {
+    return this.selectedCandidateList.slice(0, 4);
+  }
+
+  get activeScenarioCount(): number {
+    return this.briefScenarios.filter((scenario) => scenario.selected).length;
+  }
+
+  get exportReadiness(): number {
+    const mapping = (this.confirmedMappingsCount / this.fieldMappings.length) * 25;
+    const rules = (this.selectedRulesCount / this.rules.length) * 25;
+    const candidates = Math.min(1, this.selectedCandidateList.length / 4) * 25;
+    const sampling = (this.samplingTasks.filter((task) => task.status === '完成').length / this.samplingTasks.length) * 25;
+    return Math.round(mapping + rules + candidates + sampling);
+  }
+
+  get strongRecommendationCount(): number {
+    return this.candidates.filter((candidate) => candidate.status === '强推荐').length;
+  }
+
+  get totalMatchedCandidates(): number {
+    return this.resources.reduce((sum, resource) => sum + resource.matched, 0);
+  }
+
+  get workspacePipelineStages(): AiSelectionStage[] {
+    return this.aiSelectionStages.slice(1, 6);
+  }
+
+  get platforms(): string[] {
+    return ['全部', ...Array.from(new Set(this.candidates.map((candidate) => candidate.platform)))];
+  }
+
+  get categories(): string[] {
+    return ['全部', ...Array.from(new Set(this.candidates.map((candidate) => candidate.category ?? candidate.tags[0] ?? '未分类')))];
+  }
+
+  get contentForms(): string[] {
+    const forms = this.candidates.flatMap((candidate) => candidate.contentForms ?? [candidate.platform === 'B站' ? '长视频' : '图文']);
+    return ['全部', ...Array.from(new Set(forms))];
+  }
+
+  get fanTiers(): string[] {
+    return ['全部', '1万以下', '1万-10万', '10万-50万', '50万以上'];
+  }
+
+  get creatorFilteredCandidates(): Candidate[] {
+    const queryTokens = this.creatorQuery
+      .split(/\s+/)
+      .map((token) => token.trim())
+      .filter(Boolean);
+
+    return this.candidates
+      .filter((candidate) => this.creatorPlatform === '全部' || candidate.platform === this.creatorPlatform)
+      .filter((candidate) => this.creatorCategory === '全部' || candidate.category === this.creatorCategory || candidate.tags.includes(this.creatorCategory))
+      .filter((candidate) => this.creatorContentForm === '全部' || (candidate.contentForms ?? []).includes(this.creatorContentForm))
+      .filter((candidate) => this.creatorFanTier === '全部' || (candidate.fanTier ?? inferFanTier(candidate.fans)) === this.creatorFanTier)
+      .filter((candidate) => candidate.price <= this.creatorBudgetMax)
+      .filter((candidate) => {
+        if (this.creatorRisk === '只看安全') {
+          return candidate.status !== '需复核' && candidate.status !== '已剔除';
+        }
+        if (this.creatorRisk === '只看需复核') {
+          return candidate.status === '需复核';
+        }
+        return true;
+      })
+      .filter((candidate) => {
+        if (queryTokens.length === 0) {
+          return true;
+        }
+        const haystack = [
+          candidate.name,
+          candidate.platform,
+          candidate.category ?? '',
+          candidate.reason,
+          candidate.risk,
+          candidate.audienceProfile ?? '',
+          ...(candidate.tags ?? []),
+          ...(candidate.recallSources ?? [])
+        ].join(' ');
+        return queryTokens.some((token) => haystack.includes(token));
+      })
+      .sort((a, b) => b.score - a.score);
+  }
+
+  get creatorAiSummary(): string {
+    const count = this.creatorFilteredCandidates.length;
+    const strong = this.creatorFilteredCandidates.filter((candidate) => candidate.status === '强推荐').length;
+    const review = this.creatorFilteredCandidates.filter((candidate) => candidate.status === '需复核').length;
+    return `命中 ${count} 个博主,其中强推荐 ${strong} 个、需复核 ${review} 个;AI 会优先保留风格匹配高、报价健康、服务履约稳定的账号。`;
+  }
+
+  get deliveryChecklistDoneCount(): number {
+    return this.deliveryChecklist.filter((item) => item.done).length;
+  }
+
+  get selectedDeliveryFields(): string[] {
+    return this.deliveryFields
+      .filter((field) => field.selected)
+      .filter((field) => this.previewAudience === '内部复核版' || field.customer)
+      .map((field) => field.label);
+  }
+
+  get deliveryGaps(): string[] {
+    const gaps: string[] = [];
+    if (this.confirmedMappingsCount < this.fieldMappings.length) {
+      gaps.push('还有字段映射未确认');
+    }
+    if (this.samplingTasks.some((task) => task.status !== '完成')) {
+      gaps.push('近10条内容采样未全部完成');
+    }
+    if (this.selectedCandidateList.some((candidate) => candidate.status === '需复核')) {
+      gaps.push('名单里仍有需复核账号');
+    }
+    if (this.selectedCandidateList.length < 8) {
+      gaps.push('客户版主推账号数量偏少');
+    }
+    return gaps;
+  }
+
+  get resourceFixQueue(): ResourceIssue[] {
+    return this.resourceIssues.filter((issue) => !issue.resolved).slice(0, 4);
+  }
+
+  get taskAttentionItems(): Array<{ title: string; detail: string; action: string; view: ViewKey }> {
+    return [
+      {
+        title: '补齐微信主页链接',
+        detail: '影响近10条内容采样,建议先到资源库处理高风险字段。',
+        action: '去资源库',
+        view: 'resources'
+      },
+      {
+        title: '确认需复核账号',
+        detail: `${this.reviewQueueCandidates.length} 个账号仍有风险或剔除原因,需要业务确认。`,
+        action: '打开名单',
+        view: 'workspace'
+      },
+      {
+        title: '客户反馈待学习',
+        detail: '把本次驳回原因转成待确认规则,后续同类客户可复用。',
+        action: '去学习',
+        view: 'learning'
+      }
+    ];
+  }
+
+  get learningScopeEffect(): string {
+    if (this.selectedLearningScope === '本任务') {
+      return '只影响当前推荐名单,适合临时口径或单次活动偏好。';
+    }
+    if (this.selectedLearningScope === '单客户') {
+      return '后续同一客户 Brief 会默认带入,但仍保留人工确认。';
+    }
+    if (this.selectedLearningScope === '行业') {
+      return '同品类客户会获得弱加权,避免把单个客户口味过度放大。';
+    }
+    return '进入全局规则库前需要二次确认,命中后会影响所有新任务。';
+  }
+
+  get filteredCandidates(): Candidate[] {
+    return this.candidates
+      .filter((candidate) => this.selectedPlatform === '全部' || candidate.platform === this.selectedPlatform)
+      .filter((candidate) => this.selectedStatus === '全部' || candidate.status === this.selectedStatus)
+      .filter((candidate) => candidate.price <= this.budgetMax)
+      .sort((a, b) => {
+        if (this.sortMode === '风格匹配') {
+          return b.styleMatch - a.styleMatch;
+        }
+        if (this.sortMode === '报价升序') {
+          return a.price - b.price;
+        }
+        return b.score - a.score;
+      });
+  }
+
+  get selectedCandidate(): Candidate {
+    return this.candidates.find((candidate) => candidate.id === this.selectedCandidateId) ?? this.candidates[0];
+  }
+
+  get selectedNote(): NoteDetail {
+    return (
+      this.selectedCandidate.recentNotes.find((note) => note.id === this.selectedNoteId) ??
+      this.selectedCandidate.recentNotes[0]
+    );
+  }
+
+  get filteredNotes(): NoteDetail[] {
+    return this.selectedCandidate.recentNotes.filter(
+      (note) => this.noteVerdictFilter === '全部' || note.verdict === this.noteVerdictFilter
+    );
+  }
+
+  get confirmedMappingsCount(): number {
+    return this.fieldMappings.filter((mapping) => mapping.confirmed).length;
+  }
+
+  get selectedResource(): ResourceSummary {
+    return this.resources.find((resource) => resource.platform === this.selectedResourcePlatform) ?? this.resources[0];
+  }
+
+  get selectedResourceFiles(): ResourceFile[] {
+    return this.resourceFiles.filter((file) => file.platform === this.selectedResourcePlatform);
+  }
+
+  get selectedResourceIssues(): ResourceIssue[] {
+    return this.resourceIssues.filter((issue) => issue.platform === this.selectedResourcePlatform);
+  }
+
+  get selectedResourceCandidates(): Candidate[] {
+    return this.candidates.filter((candidate) => candidate.platform === this.selectedResourcePlatform).slice(0, 6);
+  }
+
+  get selectedRule(): Rule {
+    return this.rules.find((rule) => rule.id === this.selectedRuleId) ?? this.rules[0];
+  }
+
+  get enabledRuleTestCases(): RuleTestCase[] {
+    return this.ruleTestCases.filter((item) => item.enabled);
+  }
+
+  get selectedTask(): TaskRecord {
+    return this.taskRecords.find((task) => task.id === this.selectedTaskId) ?? this.taskRecords[0];
+  }
+
+  get selectedTaskTimeline(): TaskTimelineItem[] {
+    const timeline = this.taskTimeline.filter((item) => item.taskId === this.selectedTaskId);
+    if (timeline.length > 0) {
+      return timeline;
+    }
+    return [
+      {
+        taskId: this.selectedTaskId,
+        time: '待补充',
+        title: '暂无详细时间线',
+        detail: '正式版会记录 Brief、资源同步、规则调整、名单导出和客户反馈。'
+      }
+    ];
+  }
+
+  get selectedTemplate(): TemplateItem {
+    return this.templates.find((template) => template.selected) ?? this.templates[0];
+  }
+
+  get visibleTemplateFields(): TemplateField[] {
+    return this.templateFields.filter((field) => {
+      if (this.templatePreviewMode === '客户版') {
+        return field.customer && field.selected;
+      }
+      if (this.templatePreviewMode === '复盘版') {
+        return field.selected || field.label.includes('采纳') || field.source.includes('复盘');
+      }
+      return field.internal && field.selected;
+    });
+  }
+
+  isChecklistDone(key: string): boolean {
+    if (key === 'brief') {
+      return this.currentStep > 1;
+    }
+    if (key === 'demand') {
+      return this.currentStep > 2 && this.requirements.some((item) => item.selected);
+    }
+    if (key === 'rule') {
+      return this.currentStep > 3 && this.selectedRulesCount >= 3;
+    }
+    if (key === 'sample') {
+      return this.currentStep > 4 && this.samplingTasks.every((task) => task.status === '完成');
+    }
+    if (key === 'export') {
+      return this.currentStep >= 5 && (this.exportReadiness >= 80 || this.exportState.includes('导出'));
+    }
+    return false;
+  }
+
+  toggleSimpleMode(): void {
+    this.simpleMode = !this.simpleMode;
+    if (this.simpleMode && !this.simpleNavKeys.includes(this.activeView)) {
+      this.activeView = 'workspace';
+    }
+    this.appendLog('视图模式', this.simpleMode ? '已切换为商务简洁模式。' : '已切换为完整业务模式。');
+  }
+
+  toggleAdvancedWorkspace(): void {
+    this.showAdvancedWorkspace = !this.showAdvancedWorkspace;
+    this.appendLog('工作台细节', this.showAdvancedWorkspace ? '已展开规则、采样和试算细节。' : '已收起高级业务细节。');
+  }
+
+  backToWorkflow(): void {
+    this.activeView = 'workspace';
+    this.appendLog('导航', `已返回提号流程 Step ${this.currentStep}。`);
+  }
+
+  runNextAction(): void {
+    if (this.currentStep <= 1) {
+      this.analyzeBrief();
+      this.appendLog('下一步', '已解析 Brief。');
+      return;
+    }
+    if (this.currentStep === 2) {
+      this.confirmDemand();
+      this.appendLog('下一步', '已确认需求。');
+      return;
+    }
+    if (this.currentStep === 3) {
+      this.generateRecommendations();
+      this.appendLog('下一步', '已生成推荐名单。');
+      return;
+    }
+    if (this.currentStep === 4 && this.samplingTasks.some((task) => task.status !== '完成')) {
+      this.runSampling();
+      this.currentStep = 5;
+      this.updateSteps();
+      this.appendLog('下一步', '已完成近10条内容采样。');
+      return;
+    }
+    if (this.currentStep === 4) {
+      this.currentStep = 5;
+      this.updateSteps();
+      this.appendLog('下一步', '已进入推荐名单复核。');
+      return;
+    }
+    if (this.currentStep === 5) {
+      this.previewAudience = '客户版';
+      this.activeView = 'delivery';
+      this.updateSteps();
+      this.appendLog('下一步', '已进入客户版交付预览。');
+      return;
+    }
+    this.extractRules();
+    this.appendLog('下一步', '已从反馈中提炼待确认规则。');
+  }
+
+  runBusinessShortcut(id: string): void {
+    if (id === 'fast-list') {
+      this.analyzeBrief();
+      this.confirmDemand();
+      this.generateRecommendations();
+      this.runSampling();
+      this.currentStep = 5;
+      this.previewAudience = '客户版';
+      this.exportState = '已生成可讨论名单,等待客户版预览';
+      this.showAdvancedWorkspace = false;
+      this.updateSteps();
+      this.appendLog('快捷操作', '已一键生成可看名单。');
+      return;
+    }
+
+    if (id === 'review-risk') {
+      this.selectedStatus = '需复核';
+      this.selectedResourcePlatform = '微信';
+      this.activeView = 'resources';
+      this.appendLog('快捷操作', '已切到待处理问题和需复核账号。');
+      return;
+    }
+
+    if (id === 'client-preview') {
+      this.previewAudience = '客户版';
+      this.templatePreviewMode = '客户版';
+      this.currentStep = 5;
+      this.activeView = 'delivery';
+      this.updateSteps();
+      this.appendLog('快捷操作', '已进入客户版名单预览。');
+      return;
+    }
+
+    if (id === 'learn-feedback') {
+      this.extractRules();
+      this.activeView = 'learning';
+      this.appendLog('快捷操作', '已进入反馈学习并提炼规则。');
+    }
+  }
+
+  addVisibleCreatorsToPool(): void {
+    const visibleIds = new Set(this.creatorShortlistCandidates.map((candidate) => candidate.id));
+    this.candidates = this.candidates.map((candidate) =>
+      visibleIds.has(candidate.id)
+        ? {
+            ...candidate,
+            selected: true,
+            status: candidate.status === '已剔除' ? '备选' : candidate.status
+          }
+        : candidate
+    );
+    this.exportState = `已将 ${visibleIds.size} 个当前筛选博主加入候选池`;
+    this.appendLog('找博主', `已批量加入 ${visibleIds.size} 个当前筛选账号。`);
+  }
+
+  openRecommendationReview(candidate?: Candidate): void {
+    if (candidate) {
+      this.openCandidate(candidate);
+    }
+    this.currentStep = 5;
+    this.activeView = 'workspace';
+    this.updateSteps();
+    this.appendLog('名单复核', candidate ? `已打开 ${candidate.name} 的内容证据。` : '已打开推荐名单复核视图。');
+  }
+
+  toggleDeliveryChecklist(item: { done: boolean; label: string }): void {
+    item.done = !item.done;
+    this.appendLog('交付检查', `${item.label} 已标记为${item.done ? '完成' : '待处理'}。`);
+  }
+
+  setLearningScope(scope: '本任务' | '单客户' | '行业' | '长期规则'): void {
+    this.selectedLearningScope = scope;
+    this.appendLog('学习范围', `反馈规则生效范围已设为${scope}。`);
+  }
+
+  uploadTemplateMock(): void {
+    this.templateUploadState = '已上传《客户A-推荐名单字段模板.xlsx》,字段预览已刷新';
+    this.templates = [
+      {
+        name: '客户A-推荐名单字段模板.xlsx',
+        type: '推荐表模板',
+        useCase: '客户A 专属字段顺序和对客话术',
+        selected: true
+      },
+      ...this.templates.map((template) => ({ ...template, selected: false }))
+    ];
+    this.appendLog('模板上传', '已模拟上传客户A专属推荐表模板。');
+  }
+
+  useCreatorPrompt(prompt: string): void {
+    this.creatorQuery = prompt;
+    this.appendLog('找博主', `已按提示词更新搜索:${prompt}`);
+  }
+
+  setCreatorFilters(platform: string, category = '全部'): void {
+    this.creatorPlatform = platform;
+    this.creatorCategory = category;
+    this.appendLog('找博主筛选', `平台 ${platform},类目 ${category}。`);
+  }
+
+  addCreatorToPool(candidate: Candidate): void {
+    candidate.selected = true;
+    candidate.status = candidate.status === '已剔除' ? '备选' : candidate.status;
+    this.selectedCandidateId = candidate.id;
+    this.selectedNoteId = candidate.recentNotes[0]?.id ?? '';
+    this.exportState = `${candidate.name} 已加入候选池`;
+    this.appendLog('候选池', `${candidate.name} 从找博主页加入本次名单。`);
+  }
+
+  toggleScenario(scenario: BriefScenario): void {
+    scenario.selected = !scenario.selected;
+    this.recalculateScenario();
+    this.appendLog('情景试算', `${scenario.label}:${scenario.selected ? '已启用' : '已关闭'}。`);
+  }
+
+  selectVisibleCandidates(): void {
+    const visibleIds = new Set(this.filteredCandidates.map((candidate) => candidate.id));
+    this.candidates = this.candidates.map((candidate) => ({
+      ...candidate,
+      selected: visibleIds.has(candidate.id) ? true : candidate.selected
+    }));
+    this.appendLog('名单筛选', `已勾选当前筛选下的 ${visibleIds.size} 个账号。`);
+  }
+
+  clearSelectedCandidates(): void {
+    this.candidates = this.candidates.map((candidate) => ({ ...candidate, selected: false }));
+    this.appendLog('名单筛选', '已清空当前推荐名单勾选。');
+  }
+
+  bulkStatus(status: CandidateStatus): void {
+    const count = this.selectedCandidateList.length;
+    this.candidates = this.candidates.map((candidate) =>
+      candidate.selected ? { ...candidate, status, selected: status !== '已剔除' } : candidate
+    );
+    this.appendLog('批量复核', `已将 ${count} 个勾选账号标记为${status}。`);
+  }
+
+  toggleCompare(): void {
+    this.compareOpen = !this.compareOpen;
+    this.appendLog('对比视图', this.compareOpen ? '已打开账号横向对比。' : '已收起账号横向对比。');
+  }
+
+  switchPreviewAudience(): void {
+    this.previewAudience = this.previewAudience === '客户版' ? '内部复核版' : '客户版';
+    this.appendLog('预览模式', `已切换为${this.previewAudience}。`);
+  }
+
+  setPreviewAudience(audience: '客户版' | '内部复核版'): void {
+    if (this.previewAudience === audience) {
+      return;
+    }
+    this.previewAudience = audience;
+    this.appendLog('预览模式', `已切换为${this.previewAudience}。`);
+  }
+
+  setNoteVerdictFilter(verdict: NoteVerdict | '全部'): void {
+    this.noteVerdictFilter = verdict;
+    const nextNote = this.filteredNotes[0] ?? this.selectedCandidate.recentNotes[0];
+    this.selectedNoteId = nextNote.id;
+  }
+
+  markNote(note: NoteDetail, verdict: NoteVerdict): void {
+    note.verdict = verdict;
+    if (verdict === '正向样本') {
+      note.match = Math.min(99, note.match + 3);
+      this.selectedCandidate.styleMatch = Math.min(99, this.selectedCandidate.styleMatch + 1);
+    }
+    if (verdict === '负向样本') {
+      note.match = Math.max(45, note.match - 5);
+      this.selectedCandidate.styleMatch = Math.max(50, this.selectedCandidate.styleMatch - 2);
+      this.selectedCandidate.status = '需复核';
+    }
+    this.appendLog('笔记标注', `${this.selectedCandidate.name}《${note.title}》被标记为${verdict}。`);
+  }
+
+  addCandidateReview(text: string): void {
+    this.feedbackText = `${this.feedbackText}\n商务复核:${this.selectedCandidate.name} - ${text}`;
+    this.appendLog('复核意见', `${this.selectedCandidate.name}:${text}`);
+  }
+
+  appendFeedbackPreset(text: string): void {
+    this.feedbackText = `${this.feedbackText}\n${text}`;
+    this.appendLog('反馈补充', text);
+  }
+
+  selectResourcePlatform(platform: string): void {
+    this.selectedResourcePlatform = platform;
+    this.appendLog('资源库', `已查看 ${platform} 资源详情。`);
+  }
+
+  rescanSelectedResource(): void {
+    this.resources = this.resources.map((resource) =>
+      resource.platform === this.selectedResourcePlatform
+        ? {
+            ...resource,
+            fresh: Math.min(99, resource.fresh + 6),
+            matched: resource.matched + 9,
+            status: '刚刚同步'
+          }
+        : resource
+    );
+    this.resourceHealthItems = this.resourceHealthItems.map((item, index) => ({
+      ...item,
+      value: Math.min(98, item.value + (index === 1 ? 5 : 3))
+    }));
+    this.appendLog('资源同步', `${this.selectedResourcePlatform} 已重新扫描,匹配数和字段完整率已更新。`);
+  }
+
+  resolveResourceIssue(issue: ResourceIssue): void {
+    issue.resolved = true;
+    this.appendLog('资源问题', `${issue.platform}:${issue.title} 已标记处理。`);
+  }
+
+  confirmMapping(mapping: FieldMapping): void {
+    mapping.confirmed = true;
+    mapping.confidence = Math.min(99, mapping.confidence + 4);
+    this.appendLog('字段映射', `${mapping.source} -> ${mapping.target} 已确认。`);
+  }
+
+  selectRule(rule: Rule): void {
+    this.selectedRuleId = rule.id;
+    this.appendLog('规则沙盘', `已选中 ${rule.title}。`);
+  }
+
+  toggleRuleTestCase(item: RuleTestCase): void {
+    item.enabled = !item.enabled;
+  }
+
+  runRuleSandbox(): void {
+    const enabledCount = this.enabledRuleTestCases.length;
+    const rule = this.selectedRule;
+    const impact = Math.round((this.ruleSandboxWeight / 100) * (enabledCount + 1) * 3);
+    this.ruleSimulationState = `${rule.title} 试算完成:预计强推荐 +${Math.max(1, impact)},需复核 -${Math.max(1, enabledCount)}。`;
+    this.candidates = this.candidates.map((candidate, index) =>
+      index < 4
+        ? {
+            ...candidate,
+            score: Math.min(99, candidate.score + Math.max(1, enabledCount)),
+            ruleHits: Array.from(new Set([...candidate.ruleHits, rule.category]))
+          }
+        : candidate
+    );
+    this.appendLog('规则试算', this.ruleSimulationState);
+  }
+
+  selectTask(task: TaskRecord): void {
+    this.selectedTaskId = task.id;
+    this.appendLog('任务查看', `已打开 ${task.id}:${task.brand}。`);
+  }
+
+  copyTask(task: TaskRecord): void {
+    const nextId = `TH-202605-${String(this.taskRecords.length + 20).padStart(3, '0')}`;
+    const copied: TaskRecord = {
+      ...task,
+      id: nextId,
+      status: '待确认',
+      owner: '商务-王一',
+      version: '需求 v0.1',
+      lastAction: `从 ${task.id} 复制行业规则和模板,等待上传新 Brief`
+    };
+    this.taskRecords = [copied, ...this.taskRecords];
+    this.selectedTaskId = nextId;
+    this.taskTimeline = [
+      {
+        taskId: nextId,
+        time: '刚刚',
+        title: '复制为新任务',
+        detail: `复用 ${task.brand} 的规则组合、导出模板和复盘偏好。`
+      },
+      ...this.taskTimeline
+    ];
+    this.appendLog('任务复制', `${task.id} 已复制为 ${nextId}。`);
+  }
+
+  sendTaskFeedbackToLearning(): void {
+    const text = `${this.selectedTask.brand}:${this.selectedTask.lastAction}`;
+    this.feedbackText = `${this.feedbackText}\n任务复盘:${text}`;
+    this.activeView = 'learning';
+    this.appendLog('任务复盘', `${this.selectedTask.id} 的最近动作已加入反馈学习。`);
+  }
+
+  setTemplatePreviewMode(mode: '客户版' | '内部复核版' | '复盘版'): void {
+    this.templatePreviewMode = mode;
+    this.appendLog('模板预览', `已切换为${mode}。`);
+  }
+
+  toggleTemplateField(field: TemplateField): void {
+    if (field.required) {
+      field.selected = true;
+      return;
+    }
+    field.selected = !field.selected;
+  }
+
+  applyTemplateFieldsToDelivery(): void {
+    const active = new Set(this.templateFields.filter((field) => field.selected).map((field) => field.label));
+    this.deliveryFields = this.deliveryFields.map((field) => ({
+      ...field,
+      selected: active.has(field.label) || field.selected
+    }));
+    this.exportState = `已应用 ${this.visibleTemplateFields.length} 个模板字段到导出配置`;
+    this.appendLog('模板应用', `${this.selectedTemplate.name} 的字段配置已同步到名单交付。`);
+  }
+
+  setView(view: ViewKey): void {
+    this.activeView = view;
+  }
+
+  goStep(step: number): void {
+    this.currentStep = step;
+    this.updateSteps();
+  }
+
+  onFileSelected(event: Event): void {
+    const input = event.target as HTMLInputElement;
+    const file = input.files?.[0];
+    if (!file) {
+      return;
+    }
+    this.uploadedFileName = file.name;
+    this.currentStep = 1;
+    this.exportState = 'Brief 已上传,等待解析';
+    this.updateSteps();
+  }
+
+  analyzeBrief(): void {
+    this.currentStep = 2;
+    this.requirements = this.requirements.map((item, index) => ({
+      ...item,
+      confidence: Math.min(99, item.confidence + (index % 2 === 0 ? 2 : 1))
+    }));
+    this.activities[0] = { ...this.activities[0], status: '完成' };
+    this.exportState = '已抽取 6 个关键需求点';
+    this.updateSteps();
+  }
+
+  confirmDemand(): void {
+    this.currentStep = 3;
+    this.exportState = '需求已确认,等待规则选择';
+    this.updateSteps();
+  }
+
+  toggleRequirementEdit(item: Requirement): void {
+    item.editable = !item.editable;
+  }
+
+  addRequirement(): void {
+    this.requirements = [
+      ...this.requirements,
+      {
+        label: '临时补充',
+        value: '优先选择历史合作中客户反馈好、执行配合度高的账号',
+        confidence: 100,
+        selected: true,
+        editable: true,
+        evidence: '商务手动补充'
+      }
+    ];
+  }
+
+  addTemporaryRule(): void {
+    const next = String(this.rules.length + 1).padStart(3, '0');
+    this.rules = [
+      ...this.rules,
+      {
+        id: `R-${next}`,
+        title: this.tempRuleTitle,
+        description: '本次任务临时生效,可在复盘后保存为长期规则。',
+        category: '临时策略',
+        source: '临时补充',
+        selected: true,
+        impact: this.tempRuleImpact
+      }
+    ];
+    this.exportState = '临时规则已加入本次提号';
+  }
+
+  runResourceSync(): void {
+    this.resources = this.resources.map((resource, index) => ({
+      ...resource,
+      fresh: Math.min(96, resource.fresh + 4 + index),
+      matched: resource.matched + 6 + index
+    }));
+    this.fieldMappings = this.fieldMappings.map((mapping, index) => ({
+      ...mapping,
+      confidence: Math.min(99, mapping.confidence + 3),
+      confirmed: index < 4 ? true : mapping.confirmed
+    }));
+    this.activities[1] = { ...this.activities[1], status: '完成' };
+    this.exportState = '资源库已重新同步并更新字段映射';
+  }
+
+  confirmAllMappings(): void {
+    this.fieldMappings = this.fieldMappings.map((mapping) => ({ ...mapping, confirmed: true }));
+  }
+
+  generateRecommendations(): void {
+    this.currentStep = 4;
+    this.exportState = `已生成 ${this.totalMatchedCandidates} 个候选,当前展示 Top ${Math.min(12, this.candidates.length)}`;
+    this.activities = this.activities.map((activity, index) => ({
+      ...activity,
+      status: index < 3 ? '完成' : '进行中'
+    }));
+    this.candidates = this.candidates.map((candidate, index) => ({
+      ...candidate,
+      score: Math.min(97, candidate.score + (index < 2 ? 2 : 0)),
+      selected: index < 4,
+      status: candidate.status === '已剔除' ? '备选' : candidate.status
+    }));
+    this.updateSteps();
+  }
+
+  runSampling(): void {
+    this.currentStep = 4;
+    this.samplingTasks = this.samplingTasks.map((task) => ({
+      ...task,
+      progress: 100,
+      status: '完成',
+      result: task.result.includes('等待') ? '已完成近10篇内容采样,等待商务复核' : task.result
+    }));
+    this.activities[3] = { ...this.activities[3], status: '完成' };
+    this.candidates = this.candidates.map((candidate) => ({
+      ...candidate,
+      styleMatch: candidate.status === '需复核' ? Math.min(79, candidate.styleMatch + 4) : Math.min(96, candidate.styleMatch + 2)
+    }));
+    this.exportState = '近10篇内容采样已完成';
+    this.updateSteps();
+  }
+
+  toggleRule(rule: Rule): void {
+    rule.selected = !rule.selected;
+  }
+
+  toggleCandidate(candidate: Candidate): void {
+    candidate.selected = !candidate.selected;
+  }
+
+  openCandidate(candidate: Candidate): void {
+    this.selectedCandidateId = candidate.id;
+    this.selectedNoteId = candidate.recentNotes[0]?.id ?? '';
+  }
+
+  selectNote(note: NoteDetail): void {
+    this.selectedNoteId = note.id;
+  }
+
+  updateCandidateStatus(candidate: Candidate, status: CandidateStatus): void {
+    candidate.status = status;
+    candidate.selected = status !== '已剔除';
+  }
+
+  rotateCandidate(): void {
+    this.candidates = this.candidates.map((candidate, index) => {
+      if (candidate.status === '需复核') {
+        return { ...candidate, status: '备选', score: candidate.score + 5, selected: true };
+      }
+      return index === 0 ? { ...candidate, score: Math.min(99, candidate.score + 1) } : candidate;
+    });
+    this.exportState = '已按当前规则换一批并补足备选';
+  }
+
+  extractRules(): void {
+    const suggestions: LearnedRule[] = [
+      {
+        title: '小红书减少泛美妆号,优先生活方式和通勤场景',
+        description: '当 Brief 或反馈中出现“真实测评、通勤、生活方式”时,生活方式标签加权 +12,泛美妆标签降权 -10。',
+        confidence: 93,
+        action: '建议加入长期规则',
+        approved: false
+      },
+      {
+        title: '抖音预算压低时保留爆文率高账号',
+        description: '抖音预算下调时,先按报价降序剔除,但爆文率、完播率进入保护分。',
+        confidence: 87,
+        action: '建议加入预算策略',
+        approved: false
+      },
+      {
+        title: '客户明确不要硬广时,营销资讯类账号自动进入复核池',
+        description: '当反馈出现“硬广、资讯感、种草不自然”等表述时,资讯类账号风格分扣 8 分。',
+        confidence: 82,
+        action: '建议加入风格风控',
+        approved: false
+      }
+    ];
+    this.learnedRules = suggestions;
+    this.currentStep = 6;
+    this.updateSteps();
+  }
+
+  approveLearnedRule(item: LearnedRule): void {
+    item.approved = true;
+    this.rules = [
+      ...this.rules,
+      {
+        id: `R-${String(this.rules.length + 1).padStart(3, '0')}`,
+        title: item.title,
+        description: item.description,
+        category: '反馈学习',
+        source: 'AI提炼',
+        selected: true,
+        impact: `置信度 ${item.confidence}%`
+      }
+    ];
+    this.exportState = '反馈规则已确认入库';
+  }
+
+  rejectLearnedRule(item: LearnedRule): void {
+    this.learnedRules = this.learnedRules.filter((rule) => rule.title !== item.title);
+  }
+
+  selectTemplate(template: TemplateItem): void {
+    this.templates = this.templates.map((item) => ({
+      ...item,
+      selected: item.name === template.name
+    }));
+    this.exportState = `已选择模板:${template.name}`;
+  }
+
+  async exportRecommendations(): Promise<void> {
+    this.currentStep = 5;
+    this.updateSteps();
+    const selected = this.candidates.filter((candidate) => candidate.selected && candidate.status !== '已剔除');
+
+    try {
+      const response = await fetch('http://localhost:4300/api/recommendations/export', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify({ candidates: selected })
+      });
+
+      if (!response.ok) {
+        throw new Error('API unavailable');
+      }
+
+      const blob = await response.blob();
+      this.triggerDownload(blob, '客户A-新锐护肤品牌-需求推荐名单.xls');
+      this.apiState = 'Node API 已生成导出文件';
+      this.exportState = '推荐名单已导出';
+      return;
+    } catch {
+      const html = this.buildExcelHtml(selected);
+      const blob = new Blob([html], { type: 'application/vnd.ms-excel;charset=utf-8' });
+      this.triggerDownload(blob, '客户A-新锐护肤品牌-需求推荐名单.xls');
+      this.apiState = '前端兜底生成导出文件';
+      this.exportState = '推荐名单已导出';
+    }
+  }
+
+  private recalculateScenario(): void {
+    const activeIds = new Set(this.briefScenarios.filter((scenario) => scenario.selected).map((scenario) => scenario.id));
+
+    this.candidates = this.candidates.map((candidate) => {
+      const base = this.candidateBaseline.get(candidate.id);
+      if (!base) {
+        return candidate;
+      }
+
+      let score = base.score;
+      let styleMatch = base.styleMatch;
+      let status = base.status;
+      const ruleHits = [...base.ruleHits];
+      let risk = base.risk;
+      let reason = base.reason;
+      let selected = candidate.selected;
+
+      if (activeIds.has('budget-down')) {
+        if (candidate.price > 12000) {
+          score -= 6;
+          status = '备选';
+          risk = `${base.risk} 客户压预算后需谈价或替换。`;
+        } else if (candidate.price <= 7000) {
+          score += 4;
+          ruleHits.push('预算压缩保护');
+        }
+      }
+
+      if (activeIds.has('life-style')) {
+        const lifestyleHit = candidate.tags.some((tag) => ['生活方式', '通勤', '真实测评'].includes(tag));
+        if (lifestyleHit) {
+          score += 5;
+          styleMatch += 4;
+          ruleHits.push('生活方式加权');
+        } else if (candidate.platform === '微信') {
+          score -= 5;
+          status = '需复核';
+          risk = '客户偏生活方式后,资讯号需人工复核。';
+        }
+      }
+
+      if (activeIds.has('strict-style')) {
+        if (styleMatch < 80) {
+          score -= 8;
+          status = '需复核';
+          ruleHits.push('硬广风格复核');
+        } else {
+          score += 2;
+        }
+      }
+
+      if (activeIds.has('keep-bilibili') && candidate.platform === 'B站') {
+        score += 5;
+        selected = true;
+        status = status === '已剔除' ? '备选' : status;
+        reason = `${base.reason} 当前情景要求保留专业背书账号。`;
+        ruleHits.push('B站背书保留');
+      }
+
+      return {
+        ...candidate,
+        score: Math.max(50, Math.min(99, score)),
+        styleMatch: Math.max(45, Math.min(99, styleMatch)),
+        status,
+        selected,
+        risk,
+        reason,
+        ruleHits: Array.from(new Set(ruleHits))
+      };
+    });
+
+    this.exportState =
+      this.activeScenarioCount > 0
+        ? `已按 ${this.activeScenarioCount} 个客户情景试算名单`
+        : '已恢复默认提号策略';
+  }
+
+  private appendLog(action: string, detail: string): void {
+    const now = new Date();
+    const time = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
+    this.interactionLogs = [{ time, action, detail }, ...this.interactionLogs].slice(0, 6);
+  }
+
+  private updateSteps(): void {
+    this.steps = this.steps.map((step, index) => {
+      const position = index + 1;
+      if (position < this.currentStep) {
+        return { ...step, status: 'done' };
+      }
+      if (position === this.currentStep) {
+        return { ...step, status: 'active' };
+      }
+      return { ...step, status: 'todo' };
+    });
+  }
+
+  private triggerDownload(blob: Blob, filename: string): void {
+    const url = URL.createObjectURL(blob);
+    const link = document.createElement('a');
+    link.href = url;
+    link.download = filename;
+    link.click();
+    URL.revokeObjectURL(url);
+  }
+
+  private buildExcelHtml(candidates: Candidate[]): string {
+    const rows = candidates
+      .map(
+        (candidate) => `
+          <tr>
+            <td>${candidate.platform}</td>
+            <td>${candidate.name}</td>
+            <td>${candidate.fans}</td>
+            <td>${candidate.price}</td>
+            <td>${candidate.score}</td>
+            <td>${candidate.styleMatch}%</td>
+            <td>${candidate.status}</td>
+            <td>${candidate.owner}</td>
+            <td>${candidate.supplier}</td>
+            <td>${candidate.reason}</td>
+            <td>${candidate.risk}</td>
+          </tr>`
+      )
+      .join('');
+
+    return `
+      <html>
+        <head><meta charset="UTF-8"></head>
+        <body>
+          <table border="1">
+            <tr style="background:#1f8a70;color:#ffffff;font-weight:bold">
+              <th>平台</th><th>账号</th><th>粉丝量</th><th>报价</th><th>综合分</th><th>风格匹配</th><th>推荐状态</th><th>责任媒介</th><th>供应商</th><th>推荐理由</th><th>风险提示</th>
+            </tr>
+            ${rows}
+          </table>
+        </body>
+      </html>`;
+  }
+}

+ 244 - 0
src/app/models.ts

@@ -0,0 +1,244 @@
+export type ViewKey =
+  | 'workspace'
+  | 'creatorSearch'
+  | 'delivery'
+  | 'tasks'
+  | 'resources'
+  | 'rules'
+  | 'learning'
+  | 'templates';
+export type StepStatus = 'done' | 'active' | 'todo';
+export type ActivityStatus = '完成' | '进行中' | '待执行';
+export type CandidateStatus = '强推荐' | '备选' | '需复核' | '已剔除';
+export type NoteVerdict = '正向样本' | '需复核' | '负向样本';
+export type RuleSource = '经验规则' | '用户反馈' | 'AI提炼' | '临时补充';
+
+export interface NavItem {
+  key: ViewKey;
+  label: string;
+  note: string;
+}
+
+export interface Step {
+  label: string;
+  status: StepStatus;
+}
+
+export interface TemplateItem {
+  name: string;
+  type: string;
+  useCase: string;
+  selected: boolean;
+}
+
+export interface Requirement {
+  label: string;
+  value: string;
+  confidence: number;
+  selected: boolean;
+  editable: boolean;
+  evidence: string;
+}
+
+export interface Rule {
+  id: string;
+  title: string;
+  description: string;
+  category: string;
+  source: RuleSource;
+  selected: boolean;
+  impact: string;
+}
+
+export interface NoteDetail {
+  id: string;
+  title: string;
+  publishTime: string;
+  format: string;
+  style: string;
+  match: number;
+  verdict: NoteVerdict;
+  summary: string;
+  visualCue: string;
+  textCue: string;
+  mismatch: string;
+  keywords: string[];
+  metrics: {
+    read: string;
+    like: string;
+    collect: string;
+    comment: string;
+  };
+  aiReason: string;
+}
+
+export interface Candidate {
+  id: string;
+  platform: string;
+  name: string;
+  category?: string;
+  contentForms?: string[];
+  fanTier?: string;
+  fans: string;
+  price: number;
+  score: number;
+  styleMatch: number;
+  status: CandidateStatus;
+  tags: string[];
+  reason: string;
+  risk: string;
+  quota: string;
+  selected: boolean;
+  link: string;
+  owner: string;
+  supplier: string;
+  dataFreshness: number;
+  priceExpire: string;
+  audienceProfile?: string;
+  readMedian?: string;
+  interactionMedian?: string;
+  viralRate?: number;
+  replyRate?: number;
+  fulfillmentRate?: number;
+  naturalTrafficRatio?: number;
+  cooperationNoteRatio?: number;
+  estimatedCpm?: number;
+  cooperationHistory?: string;
+  serviceLevel?: string;
+  brandFit?: string;
+  recallSources?: string[];
+  rejectReason?: string;
+  ruleHits: string[];
+  scoreBreakdown: Array<{ label: string; value: number }>;
+  recentNotes: NoteDetail[];
+}
+
+export interface AiSelectionStage {
+  title: string;
+  subtitle: string;
+  input: string;
+  aiJudgement: string;
+  humanControl: string;
+  output: string;
+  status: ActivityStatus;
+  accounts: string[];
+}
+
+export interface DeliveryVersion {
+  version: string;
+  title: string;
+  owner: string;
+  time: string;
+  summary: string;
+  status: string;
+}
+
+export interface ResourceSummary {
+  platform: string;
+  total: number;
+  fresh: number;
+  matched: number;
+  status: string;
+}
+
+export interface FieldMapping {
+  source: string;
+  target: string;
+  confidence: number;
+  confirmed: boolean;
+}
+
+export interface Activity {
+  title: string;
+  detail: string;
+  status: ActivityStatus;
+}
+
+export interface SamplingTask {
+  account: string;
+  platform: string;
+  progress: number;
+  status: ActivityStatus;
+  result: string;
+}
+
+export interface LearnedRule {
+  title: string;
+  description: string;
+  confidence: number;
+  action: string;
+  approved: boolean;
+}
+
+export interface GapItem {
+  title: string;
+  current: string;
+  suggestion: string;
+  done: boolean;
+}
+
+export interface TaskRecord {
+  id: string;
+  brand: string;
+  status: string;
+  owner: string;
+  version: string;
+  lastAction: string;
+}
+
+export interface BriefScenario {
+  id: string;
+  label: string;
+  description: string;
+  selected: boolean;
+  impact: string;
+}
+
+export interface InteractionLog {
+  time: string;
+  action: string;
+  detail: string;
+}
+
+export interface ResourceFile {
+  platform: string;
+  name: string;
+  updateTime: string;
+  rows: number;
+  owner: string;
+  missingFields: string[];
+}
+
+export interface ResourceIssue {
+  id: string;
+  platform: string;
+  level: '高' | '中' | '低';
+  title: string;
+  detail: string;
+  action: string;
+  resolved: boolean;
+}
+
+export interface RuleTestCase {
+  id: string;
+  label: string;
+  condition: string;
+  action: string;
+  enabled: boolean;
+}
+
+export interface TaskTimelineItem {
+  taskId: string;
+  time: string;
+  title: string;
+  detail: string;
+}
+
+export interface TemplateField {
+  label: string;
+  source: string;
+  customer: boolean;
+  internal: boolean;
+  required: boolean;
+  selected: boolean;
+}

+ 214 - 0
src/app/pages/creator-search-page.component.html

@@ -0,0 +1,214 @@
+<section class="plain-view creator-search-view">
+  <header class="page-hero">
+    <div class="page-hero-copy">
+      <p class="eyebrow">找博主</p>
+      <h2>搜索、入池、复核放在同一张工作面板</h2>
+      <small>媒介可以按平台、预算、内容风格快速找人,商务也可以用一句话搜索并直接进入名单复核。</small>
+      <div class="page-guide">
+        <span><b>目标</b>找到可进入本次名单的账号</span>
+        <span><b>操作</b>搜索、筛选、加入候选池</span>
+        <span><b>产出</b>可复核候选账号</span>
+      </div>
+    </div>
+    <div class="page-actions">
+      <button type="button" class="ghost-button" (click)="state.toggleAdvancedWorkspace()">
+        {{ state.showAdvancedWorkspace ? '收起说明' : '展开说明' }}
+      </button>
+      <button type="button" class="ghost-button" (click)="state.addVisibleCreatorsToPool()">批量加入当前筛选</button>
+      <button type="button" class="ghost-button" (click)="state.openRecommendationReview()">名单复核</button>
+      <button type="button" class="primary-button compact" (click)="state.generateRecommendations()">生成推荐池</button>
+    </div>
+  </header>
+
+  <section class="creator-command">
+    <div class="creator-search-box">
+      <label>
+        博主/笔记/品牌/参考账号搜索
+        <input [(ngModel)]="state.creatorQuery" placeholder="例如:护肤 真实测评 通勤生活" />
+      </label>
+      <div class="quick-prompts">
+        <button type="button" *ngFor="let prompt of state.creatorQuickPrompts" (click)="state.useCreatorPrompt(prompt)">
+          {{ prompt }}
+        </button>
+      </div>
+    </div>
+    <aside class="ai-side-note">
+      <strong>AI 当前判断</strong>
+      <p>{{ state.creatorAiSummary }}</p>
+      <small>召回来源会合并资源库、关键词、相似博主、历史采纳和平台筛选结果。</small>
+    </aside>
+  </section>
+
+  <section class="creator-decision-strip">
+    <article *ngFor="let candidate of state.creatorShortlistCandidates.slice(0, 4)" (click)="state.openCandidate(candidate)">
+      <span>{{ candidate.platform }}</span>
+      <strong>{{ candidate.name }}</strong>
+      <small>{{ candidate.score }} 分 · {{ candidate.styleMatch }}% 风格 · {{ candidate.price | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }}</small>
+    </article>
+  </section>
+
+  <section class="creator-layout" [class.no-explain]="state.simpleMode && !state.showAdvancedWorkspace">
+    <aside class="filter-panel">
+      <div class="section-mini-head">
+        <strong>筛选条件</strong>
+        <small>条件筛选 + 内容语义搜索</small>
+      </div>
+      <label>
+        平台
+        <select [(ngModel)]="state.creatorPlatform">
+          <option *ngFor="let platform of state.platforms" [ngValue]="platform">{{ platform }}</option>
+        </select>
+      </label>
+      <label>
+        内容类目
+        <select [(ngModel)]="state.creatorCategory">
+          <option *ngFor="let category of state.categories" [ngValue]="category">{{ category }}</option>
+        </select>
+      </label>
+      <label>
+        内容形态
+        <select [(ngModel)]="state.creatorContentForm">
+          <option *ngFor="let form of state.contentForms" [ngValue]="form">{{ form }}</option>
+        </select>
+      </label>
+      <label>
+        粉丝量级
+        <select [(ngModel)]="state.creatorFanTier">
+          <option *ngFor="let tier of state.fanTiers" [ngValue]="tier">{{ tier }}</option>
+        </select>
+      </label>
+      <label>
+        风险
+        <select [(ngModel)]="state.creatorRisk">
+          <option *ngFor="let option of riskOptions" [ngValue]="option">{{ option }}</option>
+        </select>
+      </label>
+      <label>
+        最高报价
+        <input type="range" min="3000" max="22000" step="1000" [(ngModel)]="state.creatorBudgetMax" />
+        <strong>{{ state.creatorBudgetMax | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }}</strong>
+      </label>
+      <div class="filter-presets">
+        <button type="button" (click)="state.setCreatorFilters('小红书', '护肤')">小红书护肤</button>
+        <button type="button" (click)="state.setCreatorFilters('抖音', '护肤')">抖音转化</button>
+        <button type="button" (click)="state.setCreatorFilters('B站', '护肤')">B站背书</button>
+      </div>
+    </aside>
+
+    <div class="creator-results">
+      <div class="creator-stats">
+        <article>
+          <span>命中博主</span>
+          <strong>{{ state.creatorFilteredCandidates.length }}</strong>
+        </article>
+        <article>
+          <span>已入候选池</span>
+          <strong>{{ state.selectedCandidateList.length }}</strong>
+        </article>
+        <article>
+          <span>强推荐</span>
+          <strong>{{ state.strongRecommendationCount }}</strong>
+        </article>
+        <article>
+          <span>交付准备度</span>
+          <strong>{{ state.exportReadiness }}%</strong>
+        </article>
+      </div>
+
+      <div class="creator-selection-tray">
+        <div>
+          <strong>候选池</strong>
+          <small>已选账号可直接进入工作台 Step 5 复核</small>
+        </div>
+        <button type="button" *ngFor="let candidate of state.selectedCandidateList.slice(0, 6)" (click)="state.openRecommendationReview(candidate)">
+          {{ candidate.name }}
+        </button>
+        <button type="button" class="text-button" (click)="state.openRecommendationReview()">查看全部</button>
+      </div>
+
+      <div class="creator-list">
+        <article
+          class="creator-card"
+          *ngFor="let candidate of state.creatorFilteredCandidates"
+          [class.active]="candidate.selected"
+          (click)="state.openCandidate(candidate)"
+        >
+          <div class="creator-avatar">{{ candidate.platform.slice(0, 1) }}</div>
+          <div class="creator-main">
+            <header>
+              <div>
+                <strong>{{ candidate.name }}</strong>
+                <small>{{ candidate.platform }} · {{ candidate.category || candidate.tags[0] }} · {{ candidate.fans }}粉丝</small>
+              </div>
+              <em
+                [class.good]="candidate.status === '强推荐'"
+                [class.warn]="candidate.status === '备选'"
+                [class.danger]="candidate.status === '需复核' || candidate.status === '已剔除'"
+              >
+                {{ candidate.status }}
+              </em>
+            </header>
+            <p>{{ candidate.reason }}</p>
+            <div class="creator-tags">
+              <span *ngFor="let tag of candidate.tags">{{ tag }}</span>
+            </div>
+            <div class="creator-data-grid">
+              <span>报价 <b>{{ candidate.price | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }}</b></span>
+              <span>综合 <b>{{ candidate.score }}</b></span>
+              <span>风格 <b>{{ candidate.styleMatch }}%</b></span>
+              <span>阅读中位 <b>{{ candidate.readMedian || '待补' }}</b></span>
+              <span>互动中位 <b>{{ candidate.interactionMedian || '待补' }}</b></span>
+              <span>回复率 <b>{{ candidate.replyRate || 80 }}%</b></span>
+            </div>
+            <div class="creator-bottom">
+              <small>{{ candidate.audienceProfile || '粉丝画像待资源库补充' }}</small>
+              <div class="panel-actions">
+                <button type="button" class="ghost-button compact" (click)="state.openRecommendationReview(candidate); $event.stopPropagation()">
+                  看证据
+                </button>
+                <button type="button" class="primary-button compact" (click)="state.addCreatorToPool(candidate); $event.stopPropagation()">
+                  加入候选池
+                </button>
+              </div>
+            </div>
+          </div>
+        </article>
+      </div>
+    </div>
+
+    <aside class="creator-explain" *ngIf="!state.simpleMode || state.showAdvancedWorkspace">
+      <div class="section-mini-head">
+        <strong>AI 选择考虑</strong>
+        <small>当前筛选下的解释</small>
+      </div>
+      <article>
+        <span>1</span>
+        <div>
+          <strong>召回</strong>
+          <p>先从本地资源库、关键词、参考博主、参考笔记和历史采纳里找相似账号。</p>
+        </div>
+      </article>
+      <article>
+        <span>2</span>
+        <div>
+          <strong>过滤</strong>
+          <p>预算、黑名单、近期活跃、供应商绑定、报价有效期先决定剔除或降级。</p>
+        </div>
+      </article>
+      <article>
+        <span>3</span>
+        <div>
+          <strong>排序</strong>
+          <p>综合考虑风格、粉丝画像、自然流量、服务履约和组合多样性。</p>
+        </div>
+      </article>
+      <article>
+        <span>4</span>
+        <div>
+          <strong>交付</strong>
+          <p>客户版突出推荐理由,内部版保留风险、供应商和规则命中。</p>
+        </div>
+      </article>
+    </aside>
+  </section>
+</section>

+ 15 - 0
src/app/pages/creator-search-page.component.ts

@@ -0,0 +1,15 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { DemoStateService } from '../demo-state.service';
+
+@Component({
+  selector: 'app-creator-search-page',
+  imports: [CommonModule, FormsModule],
+  templateUrl: './creator-search-page.component.html'
+})
+export class CreatorSearchPageComponent {
+  riskOptions = ['全部', '只看安全', '只看需复核'];
+
+  constructor(public state: DemoStateService) {}
+}

+ 175 - 0
src/app/pages/delivery-page.component.html

@@ -0,0 +1,175 @@
+<section class="plain-view delivery-view">
+  <header class="page-hero">
+    <div class="page-hero-copy">
+      <p class="eyebrow">名单交付</p>
+      <h2>对客输出讲价值,内部复核看风险</h2>
+      <small>同一份名单分客户版和内部复核版,避免把供应商、风险和规则细节直接暴露给客户。</small>
+      <div class="page-guide">
+        <span><b>目标</b>生成可发客户的推荐表</span>
+        <span><b>操作</b>切换版本、检查字段、导出名单</span>
+        <span><b>产出</b>客户版 / 内部版 Excel</span>
+      </div>
+    </div>
+    <div class="page-actions segmented-actions">
+      <button type="button" class="ghost-button" [class.active]="state.previewAudience === '内部复核版'" (click)="state.setPreviewAudience('内部复核版')">内部复核版</button>
+      <button type="button" class="ghost-button" [class.active]="state.previewAudience === '客户版'" (click)="state.setPreviewAudience('客户版')">客户版</button>
+      <button type="button" class="ghost-button" (click)="state.toggleAdvancedWorkspace()">
+        {{ state.showAdvancedWorkspace ? '收起细节' : '展开细节' }}
+      </button>
+      <button type="button" class="primary-button compact" (click)="state.exportRecommendations()">导出名单</button>
+    </div>
+  </header>
+
+  <section class="delivery-top" [class.no-version]="state.simpleMode && !state.showAdvancedWorkspace">
+    <article class="readiness-panel delivery-readiness">
+      <div class="section-mini-head">
+        <div>
+          <strong>交付准备度</strong>
+          <small>字段映射、规则、候选和采样共同计算</small>
+        </div>
+        <b>{{ state.exportReadiness }}%</b>
+      </div>
+      <div class="progress large"><i [style.width.%]="state.exportReadiness"></i></div>
+      <div class="gap-list" *ngIf="state.deliveryGaps.length > 0; else ready">
+        <span *ngFor="let gap of state.deliveryGaps">{{ gap }}</span>
+      </div>
+      <ng-template #ready>
+        <p class="empty-state">当前名单已经可以作为客户版导出。</p>
+      </ng-template>
+    </article>
+
+    <article class="field-config">
+      <div class="section-mini-head">
+        <strong>导出字段</strong>
+        <small>{{ state.previewAudience }} · {{ state.selectedDeliveryFields.length }} 个字段</small>
+      </div>
+      <div class="field-chip-grid">
+        <label *ngFor="let field of state.deliveryFields" [class.disabled]="state.previewAudience === '客户版' && !field.customer">
+          <input type="checkbox" [(ngModel)]="field.selected" [disabled]="state.previewAudience === '客户版' && !field.customer" />
+          <span>{{ field.label }}</span>
+        </label>
+      </div>
+    </article>
+
+    <article class="version-list" *ngIf="!state.simpleMode || state.showAdvancedWorkspace">
+      <div class="section-mini-head">
+        <strong>版本历史</strong>
+        <small>需求、名单、反馈可追溯</small>
+      </div>
+      <section *ngFor="let version of state.deliveryVersions">
+        <span>{{ version.version }}</span>
+        <div>
+          <strong>{{ version.title }}</strong>
+          <p>{{ version.summary }}</p>
+          <small>{{ version.owner }} · {{ version.time }} · {{ version.status }}</small>
+        </div>
+      </section>
+    </article>
+  </section>
+
+  <section class="delivery-control-grid">
+    <article class="delivery-checklist">
+      <div class="section-mini-head">
+        <div>
+          <strong>交付检查清单</strong>
+          <small>{{ state.deliveryChecklistDoneCount }}/{{ state.deliveryChecklist.length }} 已完成</small>
+        </div>
+      </div>
+      <button
+        type="button"
+        *ngFor="let item of state.deliveryChecklist"
+        [class.done]="item.done"
+        (click)="state.toggleDeliveryChecklist(item)"
+      >
+        <span>{{ item.done ? '✓' : '·' }}</span>
+        <div>
+          <strong>{{ item.label }}</strong>
+          <small>{{ item.detail }}</small>
+        </div>
+      </button>
+    </article>
+
+    <article class="delivery-copy-panel">
+      <div class="section-mini-head">
+        <strong>客户版摘要</strong>
+        <small>可直接用于导出前口径确认</small>
+      </div>
+      <p>
+        本次名单保留 {{ state.selectedCandidateList.length }} 个账号,主推 {{ state.strongRecommendationCount }} 个;
+        推荐理由聚焦真实测评、通勤生活和轻专业成分表达。
+      </p>
+      <div class="tag-row">
+        <span *ngFor="let field of state.selectedDeliveryFields.slice(0, 6)">{{ field }}</span>
+      </div>
+    </article>
+
+    <article class="delivery-review-queue">
+      <div class="section-mini-head">
+        <strong>内部待处理</strong>
+        <small>{{ state.reviewQueueCandidates.length }} 个账号</small>
+      </div>
+      <button type="button" *ngFor="let candidate of state.reviewQueueCandidates" (click)="state.openRecommendationReview(candidate)">
+        <span>{{ candidate.status }}</span>
+        <div>
+          <strong>{{ candidate.name }}</strong>
+          <small>{{ candidate.risk }}</small>
+        </div>
+      </button>
+    </article>
+  </section>
+
+  <section class="delivery-preview">
+    <div class="section-mini-head">
+      <div>
+        <strong>{{ state.previewAudience }}预览</strong>
+        <small>展示当前已选账号,客户版隐藏内部风险字段</small>
+      </div>
+      <em>{{ state.selectedCandidateList.length }} 个账号</em>
+    </div>
+
+    <div class="delivery-table">
+      <div class="delivery-head">
+        <span>账号</span>
+        <span>报价/粉丝</span>
+        <span>推荐理由</span>
+        <span>内容证据</span>
+        <span *ngIf="state.previewAudience === '内部复核版'">内部风险</span>
+      </div>
+      <article *ngFor="let candidate of state.selectedCandidateList">
+        <div>
+          <strong>{{ candidate.name }}</strong>
+          <small>{{ candidate.platform }} · {{ candidate.category || candidate.tags[0] }}</small>
+        </div>
+        <div>
+          <strong>{{ candidate.price | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }}</strong>
+          <small>{{ candidate.fans }}粉丝</small>
+        </div>
+        <p>{{ candidate.reason }}</p>
+        <div>
+          <strong>{{ candidate.styleMatch }}% 风格匹配</strong>
+          <small>{{ candidate.recentNotes[0].title }} · {{ candidate.recentNotes[0].match }}%</small>
+        </div>
+        <p *ngIf="state.previewAudience === '内部复核版'" class="risk">{{ candidate.risk }}</p>
+        <div class="delivery-row-actions" *ngIf="state.previewAudience === '内部复核版'">
+          <button type="button" class="text-button" (click)="state.updateCandidateStatus(candidate, '备选')">转备选</button>
+          <button type="button" class="text-button" (click)="state.openRecommendationReview(candidate)">看证据</button>
+        </div>
+      </article>
+    </div>
+  </section>
+
+  <section class="handoff-grid" *ngIf="!state.simpleMode || state.showAdvancedWorkspace">
+    <article>
+      <strong>客户版话术</strong>
+      <p>推荐理由聚焦“为什么适合品牌”,使用真实测评、通勤生活、成分科普等可理解证据,不展示内部剔除逻辑。</p>
+    </article>
+    <article>
+      <strong>内部复核动作</strong>
+      <p>媒介在导出前确认报价、档期、供应商、风险和近 10 条内容样本,所有修改进入决策日志。</p>
+    </article>
+    <article>
+      <strong>复盘沉淀</strong>
+      <p>客户反馈进入反馈学习页,先生成待确认规则,再决定是本次任务生效、单客户生效还是长期入库。</p>
+    </article>
+  </section>
+</section>

+ 13 - 0
src/app/pages/delivery-page.component.ts

@@ -0,0 +1,13 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { DemoStateService } from '../demo-state.service';
+
+@Component({
+  selector: 'app-delivery-page',
+  imports: [CommonModule, FormsModule],
+  templateUrl: './delivery-page.component.html'
+})
+export class DeliveryPageComponent {
+  constructor(public state: DemoStateService) {}
+}

+ 105 - 0
src/app/pages/learning-page.component.html

@@ -0,0 +1,105 @@
+<section class="plain-view">
+  <header class="page-hero">
+    <div class="page-hero-copy">
+      <p class="eyebrow">反馈学习</p>
+      <h2>客户反馈先变成待确认规则,再入库</h2>
+      <small>AI 负责提炼,业务人员负责确认,避免反馈被错误学习。</small>
+      <div class="page-guide">
+        <span><b>目标</b>沉淀客户偏好</span>
+        <span><b>操作</b>粘贴反馈、提炼规则、确认入库</span>
+        <span><b>产出</b>可复用经验规则</span>
+      </div>
+    </div>
+    <div class="page-actions">
+      <button type="button" class="primary-button compact" (click)="state.extractRules()">重新提炼</button>
+    </div>
+  </header>
+
+  <section class="feedback-category-grid">
+    <article>
+      <span>偏好</span>
+      <strong>优先/喜欢/保留</strong>
+      <small>转成加权规则</small>
+    </article>
+    <article>
+      <span>排除</span>
+      <strong>不要/减少/不接受</strong>
+      <small>转成降级或剔除规则</small>
+    </article>
+    <article>
+      <span>预算</span>
+      <strong>压价/超预算/性价比</strong>
+      <small>影响报价和价格带配比</small>
+    </article>
+    <article>
+      <span>执行风险</span>
+      <strong>档期/配合/供应商</strong>
+      <small>进入内部复核字段</small>
+    </article>
+  </section>
+
+  <section class="learning-scope-panel">
+    <div>
+      <p class="eyebrow">规则生效范围</p>
+      <h3>{{ state.selectedLearningScope }}</h3>
+      <small>{{ state.learningScopeEffect }}</small>
+    </div>
+    <div class="segmented-actions">
+      <button
+        type="button"
+        class="ghost-button"
+        *ngFor="let scope of state.learningScopes"
+        [class.active]="state.selectedLearningScope === scope"
+        (click)="state.setLearningScope(scope)"
+      >
+        {{ scope }}
+      </button>
+    </div>
+  </section>
+
+  <div class="learning-grid standalone">
+    <div class="feedback-box">
+      <textarea [(ngModel)]="state.feedbackText" aria-label="客户反馈"></textarea>
+      <div class="feedback-presets">
+        <button type="button" *ngFor="let preset of state.feedbackPresets" (click)="state.appendFeedbackPreset(preset)">
+          {{ preset }}
+        </button>
+      </div>
+    </div>
+    <div class="learned-list">
+      <article *ngFor="let item of state.learnedRules" [class.approved]="item.approved">
+        <header>
+          <strong>{{ item.title }}</strong>
+          <em>{{ item.confidence }}%</em>
+        </header>
+        <p>{{ item.description }}</p>
+        <small>{{ item.action }}</small>
+        <div class="panel-actions">
+          <button type="button" class="text-button" (click)="state.approveLearnedRule(item)" [disabled]="item.approved">
+            {{ item.approved ? '已入库' : '确认入库' }}
+          </button>
+          <button type="button" class="text-button danger-text" (click)="state.rejectLearnedRule(item)">驳回</button>
+        </div>
+      </article>
+    </div>
+  </div>
+
+  <section class="learning-chain">
+    <article>
+      <strong>1. 客户反馈</strong>
+      <p>原文保留,避免 AI 只存摘要导致业务语义丢失。</p>
+    </article>
+    <article>
+      <strong>2. 待确认规则</strong>
+      <p>AI 只提出规则建议,并展示置信度和生效影响。</p>
+    </article>
+    <article>
+      <strong>3. 生效范围</strong>
+      <p>可选择本任务、单客户、单行业或长期规则库。</p>
+    </article>
+    <article>
+      <strong>4. 影响名单</strong>
+      <p>确认后回算账号分数、状态和推荐理由。</p>
+    </article>
+  </section>
+</section>

+ 13 - 0
src/app/pages/learning-page.component.ts

@@ -0,0 +1,13 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { DemoStateService } from '../demo-state.service';
+
+@Component({
+  selector: 'app-learning-page',
+  imports: [CommonModule, FormsModule],
+  templateUrl: './learning-page.component.html'
+})
+export class LearningPageComponent {
+  constructor(public state: DemoStateService) {}
+}

+ 154 - 0
src/app/pages/resources-page.component.html

@@ -0,0 +1,154 @@
+<section class="plain-view">
+  <header class="page-hero">
+    <div class="page-hero-copy">
+      <p class="eyebrow">资源库</p>
+      <h2>把本地媒体表变成 AI 能读懂的资源池</h2>
+      <small>媒介维护表格,AI 负责识别平台、字段、报价、缺失项和可用账号。</small>
+      <div class="page-guide">
+        <span><b>目标</b>检查资源是否可用</span>
+        <span><b>操作</b>同步、确认映射、处理缺口</span>
+        <span><b>产出</b>可召回账号资源池</span>
+      </div>
+    </div>
+    <div class="page-actions">
+      <button type="button" class="ghost-button" (click)="state.confirmAllMappings()">确认全部映射</button>
+      <button type="button" class="primary-button compact" (click)="state.runResourceSync()">同步资源库</button>
+    </div>
+  </header>
+
+  <div class="path-box">
+    <span>本地资源目录</span>
+    <strong>{{ state.resourcePath }}</strong>
+    <small>若目录不存在,Demo 使用内置样例;正式版会扫描《4月份媒体推荐资源表.xlsx》并自动做字段映射。</small>
+  </div>
+
+  <section class="resource-health-grid">
+    <article *ngFor="let item of state.resourceHealthItems">
+      <span>{{ item.label }}</span>
+      <strong>{{ item.value }}%</strong>
+      <div class="progress"><i [style.width.%]="item.value"></i></div>
+      <small>{{ item.detail }}</small>
+    </article>
+  </section>
+
+  <div class="resource-grid">
+    <article
+      *ngFor="let resource of state.resources"
+      [class.active]="state.selectedResourcePlatform === resource.platform"
+      (click)="state.selectResourcePlatform(resource.platform)"
+    >
+      <strong>{{ resource.platform }}</strong>
+      <span>{{ resource.status }}</span>
+      <div class="progress"><i [style.width.%]="resource.fresh"></i></div>
+      <small>资源 {{ resource.total }} 条 · 匹配 {{ resource.matched }} 条 · 新鲜度 {{ resource.fresh }}%</small>
+    </article>
+  </div>
+
+  <section class="resource-detail-panel">
+    <div class="section-mini-head">
+      <div>
+        <strong>{{ state.selectedResource.platform }} 平台详情</strong>
+        <small>资源文件、样例账号和字段缺口联动展示</small>
+      </div>
+      <button type="button" class="ghost-button compact" (click)="state.rescanSelectedResource()">重新扫描该平台</button>
+    </div>
+
+    <div class="resource-detail-grid">
+      <article class="resource-file-list">
+        <strong>资源文件</strong>
+        <section *ngFor="let file of state.selectedResourceFiles">
+          <span>{{ file.name }}</span>
+          <small>{{ file.owner }} · {{ file.updateTime }} · {{ file.rows }} 行</small>
+          <div class="tag-row">
+            <em *ngFor="let missing of file.missingFields">{{ missing }}</em>
+          </div>
+        </section>
+      </article>
+
+      <article class="resource-issue-list">
+        <strong>待处理问题</strong>
+        <section *ngFor="let issue of state.selectedResourceIssues">
+          <header>
+            <span [class.danger]="issue.level === '高'">{{ issue.level }}</span>
+            <button type="button" class="text-button" (click)="state.resolveResourceIssue(issue)" [disabled]="issue.resolved">
+              {{ issue.resolved ? '已处理' : '标记处理' }}
+            </button>
+          </header>
+          <h4>{{ issue.title }}</h4>
+          <p>{{ issue.detail }}</p>
+          <small>{{ issue.action }}</small>
+        </section>
+        <p class="empty-state" *ngIf="state.selectedResourceIssues.length === 0">当前平台暂无待处理问题。</p>
+      </article>
+
+      <article class="resource-sample-list">
+        <strong>匹配样例账号</strong>
+        <button type="button" *ngFor="let candidate of state.selectedResourceCandidates" (click)="state.openCandidate(candidate); state.setView('workspace')">
+          <span>{{ candidate.name }}</span>
+          <small>{{ candidate.fans }}粉丝 · {{ candidate.price | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }} · {{ candidate.styleMatch }}% 风格</small>
+        </button>
+      </article>
+    </div>
+  </section>
+
+  <section class="resource-fix-board">
+    <div class="section-mini-head">
+      <div>
+        <strong>资源修复队列</strong>
+        <small>优先处理会阻断推荐和导出的字段问题</small>
+      </div>
+      <button type="button" class="ghost-button compact" (click)="state.runBusinessShortcut('review-risk')">只看风险</button>
+    </div>
+    <div class="resource-fix-list">
+      <article *ngFor="let issue of state.resourceFixQueue">
+        <span [class.danger]="issue.level === '高'">{{ issue.level }}</span>
+        <div>
+          <strong>{{ issue.platform }} · {{ issue.title }}</strong>
+          <p>{{ issue.detail }}</p>
+          <small>{{ issue.action }}</small>
+        </div>
+        <button type="button" class="text-button" (click)="state.resolveResourceIssue(issue)">标记处理</button>
+      </article>
+    </div>
+  </section>
+
+  <section class="mapping-area">
+    <div class="section-mini-head">
+      <strong>字段映射确认</strong>
+      <small>{{ state.confirmedMappingsCount }}/{{ state.fieldMappings.length }} 已确认</small>
+    </div>
+    <div class="mapping-grid">
+      <article *ngFor="let mapping of state.fieldMappings" [class.confirmed]="mapping.confirmed">
+        <label>
+          <input type="checkbox" [(ngModel)]="mapping.confirmed" />
+          <span></span>
+        </label>
+        <div>
+          <strong>{{ mapping.source }}</strong>
+          <small>映射到 {{ mapping.target }}</small>
+        </div>
+        <em>{{ mapping.confidence }}%</em>
+        <button type="button" class="text-button" (click)="state.confirmMapping(mapping)">确认</button>
+      </article>
+    </div>
+  </section>
+
+  <section class="resource-impact-grid">
+    <article>
+      <strong>缺报价</strong>
+      <p>账号不能进入客户版主推,只能作为待询价备选。</p>
+    </article>
+    <article>
+      <strong>缺主页链接</strong>
+      <p>无法做近10条内容采样,风格匹配分需要人工复核。</p>
+    </article>
+    <article>
+      <strong>缺互动数据</strong>
+      <p>爆文率、阅读单价和历史表现分会降权。</p>
+    </article>
+    <article>
+      <strong>缺供应商</strong>
+      <p>履约风险升高,导出前必须绑定媒介负责人。</p>
+    </article>
+  </section>
+</section>

+ 13 - 0
src/app/pages/resources-page.component.ts

@@ -0,0 +1,13 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { DemoStateService } from '../demo-state.service';
+
+@Component({
+  selector: 'app-resources-page',
+  imports: [CommonModule, FormsModule],
+  templateUrl: './resources-page.component.html'
+})
+export class ResourcesPageComponent {
+  constructor(public state: DemoStateService) {}
+}

+ 138 - 0
src/app/pages/rules-page.component.html

@@ -0,0 +1,138 @@
+<section class="plain-view">
+  <header class="page-hero">
+    <div class="page-hero-copy">
+      <p class="eyebrow">规则库</p>
+      <h2>把商务和媒介经验沉淀成可复用规则</h2>
+      <small>规则不会神秘生效,所有临时规则、AI 提炼规则都能看到来源和影响。</small>
+      <div class="page-guide">
+        <span><b>目标</b>管理提号判断依据</span>
+        <span><b>操作</b>启停规则、试算影响、补临时规则</span>
+        <span><b>产出</b>本次规则组合</span>
+      </div>
+    </div>
+    <div class="page-actions">
+      <button type="button" class="primary-button compact" (click)="state.addTemporaryRule()">+ 新增临时规则</button>
+    </div>
+  </header>
+
+  <div class="temp-rule-box full">
+    <label>
+      规则标题
+      <input [(ngModel)]="state.tempRuleTitle" />
+    </label>
+    <label>
+      影响预估
+      <input [(ngModel)]="state.tempRuleImpact" />
+    </label>
+  </div>
+
+  <section class="rule-layer-grid">
+    <article>
+      <span>硬性剔除</span>
+      <strong>黑名单、合作禁区、低活跃</strong>
+      <small>命中后直接剔除或进入需复核池</small>
+    </article>
+    <article>
+      <span>加权排序</span>
+      <strong>风格、预算、粉丝画像</strong>
+      <small>影响综合分和强推荐排序</small>
+    </article>
+    <article>
+      <span>组合均衡</span>
+      <strong>平台、价格带、头腰尾</strong>
+      <small>保证整份名单不重复、不偏科</small>
+    </article>
+    <article>
+      <span>客户偏好</span>
+      <strong>反馈沉淀和临时需求</strong>
+      <small>先人工确认,再决定生效范围</small>
+    </article>
+  </section>
+
+  <section class="rule-ops-panel">
+    <article>
+      <span>当前启用</span>
+      <strong>{{ state.selectedRulesCount }} 条规则</strong>
+      <small>影响召回、评分、预算保护和客户版字段展示</small>
+    </article>
+    <article>
+      <span>待复核账号</span>
+      <strong>{{ state.reviewQueueCandidates.length }} 个</strong>
+      <small>可用沙盘试算后批量转为备选或剔除</small>
+    </article>
+    <article>
+      <span>选中规则</span>
+      <strong>{{ state.selectedRule.category }}</strong>
+      <small>{{ state.selectedRule.impact }}</small>
+    </article>
+  </section>
+
+  <section class="rule-conflict-strip">
+    <article *ngFor="let conflict of state.ruleConflicts">
+      <em>{{ conflict.level }}</em>
+      <div>
+        <strong>{{ conflict.title }}</strong>
+        <p>{{ conflict.detail }}</p>
+      </div>
+    </article>
+  </section>
+
+  <section class="rule-sandbox">
+    <div class="section-mini-head">
+      <div>
+        <strong>规则沙盘试算</strong>
+        <small>选中一条规则,模拟客户临时要求对名单的影响</small>
+      </div>
+      <button type="button" class="primary-button compact" (click)="state.runRuleSandbox()">运行试算</button>
+    </div>
+
+    <div class="sandbox-grid">
+      <article class="sandbox-main">
+        <span>当前规则</span>
+        <h4>{{ state.selectedRule.title }}</h4>
+        <p>{{ state.selectedRule.description }}</p>
+        <label>
+          客户要求样例
+          <textarea [(ngModel)]="state.ruleSandboxText" aria-label="规则沙盘客户要求"></textarea>
+        </label>
+        <label>
+          本次权重
+          <input type="range" min="20" max="100" step="5" [(ngModel)]="state.ruleSandboxWeight" />
+          <strong>{{ state.ruleSandboxWeight }}%</strong>
+        </label>
+        <em>{{ state.ruleSimulationState }}</em>
+      </article>
+
+      <article class="sandbox-tests">
+        <strong>测试用例</strong>
+        <label *ngFor="let item of state.ruleTestCases" [class.active]="item.enabled">
+          <input type="checkbox" [checked]="item.enabled" (change)="state.toggleRuleTestCase(item)" />
+          <div>
+            <span>{{ item.label }}</span>
+            <small>{{ item.condition }}</small>
+            <p>{{ item.action }}</p>
+          </div>
+        </label>
+      </article>
+    </div>
+  </section>
+
+  <div class="rule-management">
+    <article
+      *ngFor="let rule of state.rules"
+      [class.active]="state.selectedRule.id === rule.id"
+      (click)="state.selectRule(rule)"
+    >
+      <span>{{ rule.id }}</span>
+      <div>
+        <strong>{{ rule.title }}</strong>
+        <p>{{ rule.description }}</p>
+        <small>{{ rule.source }} · {{ rule.impact }} · 命中 {{ rule.selected ? '12-48' : '0' }} 个账号</small>
+      </div>
+      <em>{{ rule.category }}</em>
+      <button type="button" class="text-button" (click)="$event.stopPropagation(); state.toggleRule(rule)">
+        {{ rule.selected ? '停用' : '启用' }}
+      </button>
+    </article>
+  </div>
+</section>

+ 13 - 0
src/app/pages/rules-page.component.ts

@@ -0,0 +1,13 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { DemoStateService } from '../demo-state.service';
+
+@Component({
+  selector: 'app-rules-page',
+  imports: [CommonModule, FormsModule],
+  templateUrl: './rules-page.component.html'
+})
+export class RulesPageComponent {
+  constructor(public state: DemoStateService) {}
+}

+ 152 - 0
src/app/pages/tasks-page.component.html

@@ -0,0 +1,152 @@
+<section class="plain-view">
+  <header class="page-hero">
+    <div class="page-hero-copy">
+      <p class="eyebrow">任务记录</p>
+      <h2>按客户任务追踪 Brief、名单和反馈版本</h2>
+      <small>商务可以从这里继续复核、复制相似任务,或把客户反馈送入学习。</small>
+      <div class="page-guide">
+        <span><b>目标</b>找到任务当前状态</span>
+        <span><b>操作</b>继续复核、交付预览、复制任务</span>
+        <span><b>产出</b>可追溯任务档案</span>
+      </div>
+    </div>
+    <div class="page-actions">
+      <button type="button" class="ghost-button compact" (click)="state.toggleAdvancedWorkspace()">
+        {{ state.showAdvancedWorkspace ? '收起表格' : '查看表格' }}
+      </button>
+      <button type="button" class="primary-button compact" (click)="state.setView('workspace')">新建提号任务</button>
+    </div>
+  </header>
+
+  <section class="task-status-grid">
+    <article>
+      <span>待确认</span>
+      <strong>1</strong>
+      <small>Brief 字段或平台数量仍需商务确认</small>
+    </article>
+    <article>
+      <span>提号/采样中</span>
+      <strong>3</strong>
+      <small>AI 正在评分或等待近10条内容采样</small>
+    </article>
+    <article>
+      <span>待复盘</span>
+      <strong>1</strong>
+      <small>客户反馈已收到,规则待人工确认</small>
+    </article>
+    <article>
+      <span>已交付</span>
+      <strong>2</strong>
+      <small>客户版名单已导出,可回填执行结果</small>
+    </article>
+  </section>
+
+  <section class="task-command-center">
+    <article class="task-focus-card">
+      <div class="section-mini-head">
+        <div>
+          <strong>{{ state.selectedTask.brand }}</strong>
+          <small>{{ state.selectedTask.id }} · {{ state.selectedTask.status }}</small>
+        </div>
+        <button type="button" class="ghost-button compact" (click)="state.setView('workspace')">继续处理</button>
+      </div>
+      <p>{{ state.selectedTask.lastAction }}</p>
+      <div class="task-mini-metrics">
+        <span>规则 {{ state.selectedRulesCount }}</span>
+        <span>已选 {{ state.selectedCandidateList.length }}</span>
+        <span>准备度 {{ state.exportReadiness }}%</span>
+      </div>
+    </article>
+
+    <article class="task-action-queue">
+      <div class="section-mini-head">
+        <strong>下一步队列</strong>
+        <small>按当前任务自动生成</small>
+      </div>
+      <button type="button" *ngFor="let item of state.taskAttentionItems" (click)="state.setView(item.view)">
+        <div>
+          <strong>{{ item.title }}</strong>
+          <small>{{ item.detail }}</small>
+        </div>
+        <span>{{ item.action }}</span>
+      </button>
+    </article>
+  </section>
+
+  <div class="task-board">
+    <article
+      *ngFor="let task of state.taskRecords"
+      [class.active]="state.selectedTask.id === task.id"
+      (click)="state.selectTask(task)"
+    >
+      <header>
+        <span>{{ task.id }}</span>
+        <strong>{{ task.status }}</strong>
+      </header>
+      <h4>{{ task.brand }}</h4>
+      <p>{{ task.lastAction }}</p>
+      <div>
+        <small>{{ task.owner }}</small>
+        <small>{{ task.version }}</small>
+      </div>
+      <footer>
+        <button type="button" class="text-button" (click)="$event.stopPropagation(); state.setView('workspace')">继续复核</button>
+        <button type="button" class="text-button" (click)="$event.stopPropagation(); state.setView('delivery')">交付预览</button>
+        <button type="button" class="text-button" (click)="$event.stopPropagation(); state.copyTask(task)">复制任务</button>
+      </footer>
+    </article>
+  </div>
+
+  <section class="task-detail-panel">
+    <article class="task-profile">
+      <div class="section-mini-head">
+        <div>
+          <strong>{{ state.selectedTask.brand }}</strong>
+          <small>{{ state.selectedTask.id }} · {{ state.selectedTask.owner }} · {{ state.selectedTask.version }}</small>
+        </div>
+        <span>{{ state.selectedTask.status }}</span>
+      </div>
+      <p>{{ state.selectedTask.lastAction }}</p>
+      <div class="panel-actions">
+        <button type="button" class="ghost-button compact" (click)="state.copyTask(state.selectedTask)">复制为相似客户任务</button>
+        <button type="button" class="primary-button compact" (click)="state.sendTaskFeedbackToLearning()">加入反馈学习</button>
+      </div>
+    </article>
+
+    <article class="task-timeline">
+      <div class="section-mini-head">
+        <strong>任务时间线</strong>
+        <small>需求、规则、名单、反馈全链路留痕</small>
+      </div>
+      <section *ngFor="let item of state.selectedTaskTimeline">
+        <time>{{ item.time }}</time>
+        <div>
+          <strong>{{ item.title }}</strong>
+          <p>{{ item.detail }}</p>
+        </div>
+      </section>
+    </article>
+
+    <article class="task-next-actions">
+      <strong>下一步建议</strong>
+      <button type="button" (click)="state.setView('resources')">查看资源字段缺口</button>
+      <button type="button" (click)="state.setView('rules')">复核本次命中规则</button>
+      <button type="button" (click)="state.setView('delivery')">预览客户版名单</button>
+      <button type="button" (click)="state.setView('learning')">沉淀客户反馈</button>
+    </article>
+  </section>
+
+  <div class="data-table wide-table" *ngIf="!state.simpleMode || state.showAdvancedWorkspace">
+    <div class="table-head">
+      <span>任务编号</span><span>客户/品牌</span><span>负责人</span><span>版本</span><span>状态</span><span>最近动作</span>
+    </div>
+    <div class="table-row clickable" *ngFor="let task of state.taskRecords" (click)="state.selectTask(task)">
+      <span>{{ task.id }}</span>
+      <span>{{ task.brand }}</span>
+      <span>{{ task.owner }}</span>
+      <span>{{ task.version }}</span>
+      <span>{{ task.status }}</span>
+      <span>{{ task.lastAction }}</span>
+    </div>
+  </div>
+</section>

+ 12 - 0
src/app/pages/tasks-page.component.ts

@@ -0,0 +1,12 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { DemoStateService } from '../demo-state.service';
+
+@Component({
+  selector: 'app-tasks-page',
+  imports: [CommonModule],
+  templateUrl: './tasks-page.component.html'
+})
+export class TasksPageComponent {
+  constructor(public state: DemoStateService) {}
+}

+ 112 - 0
src/app/pages/templates-page.component.html

@@ -0,0 +1,112 @@
+<section class="plain-view">
+  <header class="page-hero">
+    <div class="page-hero-copy">
+      <p class="eyebrow">模板中心</p>
+      <h2>统一 Brief、资源库和推荐名单的输出格式</h2>
+      <small>模板让商务对客输出更稳定,也让 AI 解析和导出字段更可控。</small>
+      <div class="page-guide">
+        <span><b>目标</b>管理输入和输出模板</span>
+        <span><b>操作</b>选择模板、配置字段、应用导出</span>
+        <span><b>产出</b>标准化推荐表</span>
+      </div>
+    </div>
+    <div class="page-actions">
+      <button type="button" class="primary-button compact" (click)="state.uploadTemplateMock()">上传模板</button>
+    </div>
+  </header>
+
+  <section class="template-ops-panel">
+    <article>
+      <span>当前模板</span>
+      <strong>{{ state.selectedTemplate.name }}</strong>
+      <small>{{ state.templateUploadState }}</small>
+    </article>
+    <article>
+      <span>可见字段</span>
+      <strong>{{ state.visibleTemplateFields.length }} 个</strong>
+      <small>{{ state.templatePreviewMode }} 会自动过滤内部字段</small>
+    </article>
+    <article>
+      <span>导出准备</span>
+      <strong>{{ state.exportReadiness }}%</strong>
+      <small>模板字段可一键同步到名单交付</small>
+    </article>
+  </section>
+
+  <div class="template-grid">
+    <article *ngFor="let template of state.templates" [class.selected]="template.selected">
+      <strong>{{ template.name }}</strong>
+      <span>{{ template.type }}</span>
+      <p>{{ template.useCase }}</p>
+      <div class="panel-actions">
+        <button type="button" class="text-button" (click)="state.selectTemplate(template)">
+          {{ template.selected ? '当前使用' : '设为本次模板' }}
+        </button>
+        <button type="button" class="text-button">下载模板</button>
+      </div>
+    </article>
+  </div>
+
+  <section class="template-preview">
+    <div class="section-mini-head">
+      <div>
+        <strong>推荐名单模板预览</strong>
+        <small>{{ state.selectedTemplate.name }} · {{ state.templatePreviewMode }}</small>
+      </div>
+      <div class="panel-actions">
+        <button type="button" class="ghost-button compact" (click)="state.setTemplatePreviewMode('客户版')">客户版</button>
+        <button type="button" class="ghost-button compact" (click)="state.setTemplatePreviewMode('内部复核版')">内部复核版</button>
+        <button type="button" class="ghost-button compact" (click)="state.setTemplatePreviewMode('复盘版')">复盘版</button>
+        <button type="button" class="primary-button compact" (click)="state.applyTemplateFieldsToDelivery()">应用到导出</button>
+      </div>
+    </div>
+
+    <div class="template-preview-grid">
+      <article>
+        <span>客户版字段</span>
+        <strong>平台、账号、粉丝、报价、推荐理由、内容样本</strong>
+        <p>适合对客沟通,隐藏供应商、风险和内部规则。</p>
+      </article>
+      <article>
+        <span>内部复核字段</span>
+        <strong>供应商、报价有效期、风险、规则命中、负责人</strong>
+        <p>适合媒介检查履约风险和执行准备度。</p>
+      </article>
+      <article>
+        <span>复盘字段</span>
+        <strong>客户采纳、驳回原因、执行结果、沉淀规则</strong>
+        <p>用于客户反馈学习和后续推荐分回算。</p>
+      </article>
+    </div>
+
+    <div class="template-config-grid">
+      <article class="template-field-list">
+        <div class="section-mini-head">
+          <strong>字段配置</strong>
+          <small>必填字段会自动保留</small>
+        </div>
+        <label *ngFor="let field of state.templateFields" [class.required]="field.required" [class.off]="!field.selected">
+          <input type="checkbox" [checked]="field.selected" [disabled]="field.required" (change)="state.toggleTemplateField(field)" />
+          <span>{{ field.label }}</span>
+          <small>{{ field.source }}</small>
+          <em>{{ field.customer ? '客户版' : '内部' }}</em>
+        </label>
+      </article>
+
+      <article class="template-table-preview">
+        <div class="section-mini-head">
+          <strong>导出列预览</strong>
+          <small>{{ state.visibleTemplateFields.length }} 个字段</small>
+        </div>
+        <div class="template-column-row head">
+          <span *ngFor="let field of state.visibleTemplateFields">{{ field.label }}</span>
+        </div>
+        <div class="template-column-row">
+          <span *ngFor="let field of state.visibleTemplateFields">
+            {{ field.label === '账号昵称' ? state.selectedCandidate.name : field.label === '平台' ? state.selectedCandidate.platform : field.label === '推荐理由' ? '推荐理由摘要' : '样例数据' }}
+          </span>
+        </div>
+      </article>
+    </div>
+  </section>
+</section>

+ 12 - 0
src/app/pages/templates-page.component.ts

@@ -0,0 +1,12 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { DemoStateService } from '../demo-state.service';
+
+@Component({
+  selector: 'app-templates-page',
+  imports: [CommonModule],
+  templateUrl: './templates-page.component.html'
+})
+export class TemplatesPageComponent {
+  constructor(public state: DemoStateService) {}
+}

+ 417 - 0
src/app/pages/workspace-page.component.html

@@ -0,0 +1,417 @@
+<section class="workspace-view flow-workbench" [class.simple-mode]="state.simpleMode">
+  <header class="flow-hero">
+    <div class="flow-hero-copy">
+      <p class="eyebrow">当前流程 {{ state.currentStep }}/{{ state.steps.length }}</p>
+      <h2>{{ state.steps[state.currentStep - 1].label }}</h2>
+      <small>{{ state.nextAction.detail }}</small>
+      <div class="flow-guide">
+        <span><b>目标</b>{{ state.currentStepGuide.objective }}</span>
+        <span><b>操作</b>{{ state.currentStepGuide.operator }}</span>
+        <span><b>产出</b>{{ state.currentStepGuide.output }}</span>
+      </div>
+    </div>
+    <div class="flow-hero-actions">
+      <button type="button" class="ghost-button" [disabled]="state.currentStep === 1" (click)="state.goStep(state.currentStep - 1)">
+        上一步
+      </button>
+      <button type="button" class="primary-button" (click)="state.runNextAction()">{{ state.nextAction.title }}</button>
+    </div>
+    <div class="flow-progress">
+      <i [style.width.%]="(state.currentStep / state.steps.length) * 100"></i>
+    </div>
+  </header>
+
+  <section class="ops-strip" aria-label="当前任务概览">
+    <article>
+      <span>候选池</span>
+      <strong>{{ state.totalMatchedCandidates }}</strong>
+      <small>来自资源库和相似账号召回</small>
+    </article>
+    <article>
+      <span>已选账号</span>
+      <strong>{{ state.selectedCandidateList.length }}</strong>
+      <small>会进入客户版交付预览</small>
+    </article>
+    <article>
+      <span>待复核</span>
+      <strong>{{ state.reviewQueueCandidates.length }}</strong>
+      <small>报价、风格或字段仍需确认</small>
+    </article>
+    <article>
+      <span>交付准备</span>
+      <strong>{{ state.exportReadiness }}%</strong>
+      <small>{{ state.exportState }}</small>
+    </article>
+  </section>
+
+  <nav class="flow-nav" aria-label="提号六步流程">
+    <button
+      type="button"
+      *ngFor="let step of state.steps; let index = index"
+      [class.done]="step.status === 'done'"
+      [class.active]="state.currentStep === index + 1"
+      (click)="state.goStep(index + 1)"
+    >
+      <span>{{ index + 1 }}</span>
+      <strong>{{ step.label }}</strong>
+      <small>{{ step.status === 'done' ? '已完成' : state.currentStep === index + 1 ? '进行中' : '待处理' }}</small>
+    </button>
+  </nav>
+
+  <div class="flow-body" *ngIf="state.currentStep !== 5; else recommendationStep">
+    <main class="flow-stage">
+      <section class="stage-card upload-stage" *ngIf="state.currentStep === 1">
+        <div class="stage-heading">
+          <div>
+            <p class="eyebrow">Step 1</p>
+            <h3>上传 Brief</h3>
+            <small>先把客户需求表放进来,AI 只做字段抽取,不直接替你拍板。</small>
+          </div>
+          <button type="button" class="icon-button" title="重新解析" (click)="state.analyzeBrief()">↻</button>
+        </div>
+
+        <label class="upload-box flow-upload">
+          <input type="file" accept=".xlsx,.xls,.docx" (change)="state.onFileSelected($event)" />
+          <span class="upload-icon">+</span>
+          <strong>{{ state.uploadedFileName }}</strong>
+          <small>支持 Excel / Word Brief,Demo 会模拟抽取客户、平台、预算和内容风格</small>
+        </label>
+
+        <div class="template-strip">
+          <button type="button" *ngFor="let template of state.templates.slice(0, 3)" title="下载模板">
+            {{ template.name }}
+          </button>
+        </div>
+      </section>
+
+      <section class="stage-card demand-stage" *ngIf="state.currentStep === 2">
+        <div class="stage-heading">
+          <div>
+            <p class="eyebrow">Step 2</p>
+            <h3>确认需求</h3>
+            <small>低置信度内容可以改,确认后的字段会进入规则和召回逻辑。</small>
+          </div>
+          <div class="panel-actions">
+            <button type="button" class="text-button" (click)="state.addRequirement()">+ 补充需求</button>
+            <button type="button" class="primary-button compact" (click)="state.confirmDemand()">确认需求</button>
+          </div>
+        </div>
+
+        <div class="requirement-list flow-requirements">
+          <article class="requirement-item editable" *ngFor="let item of state.requirements">
+            <input type="checkbox" [(ngModel)]="item.selected" />
+            <span>
+              <strong>{{ item.label }}</strong>
+              <input *ngIf="item.editable" [(ngModel)]="item.value" />
+              <small *ngIf="!item.editable">{{ item.value }}</small>
+              <em>{{ item.evidence }}</em>
+            </span>
+            <button type="button" class="text-button" (click)="state.toggleRequirementEdit(item)">
+              {{ item.editable ? '完成' : '编辑' }}
+            </button>
+            <b>{{ item.confidence }}%</b>
+          </article>
+        </div>
+      </section>
+
+      <section class="stage-card rule-stage" *ngIf="state.currentStep === 3">
+        <div class="stage-heading">
+          <div>
+            <p class="eyebrow">Step 3</p>
+            <h3>选择规则</h3>
+            <small>默认只展示本次最关键规则,完整规则沙盘可在完整业务模块里查看。</small>
+          </div>
+          <button type="button" class="ghost-button compact" (click)="state.setView('rules')">打开规则库</button>
+        </div>
+
+        <div class="temp-rule-box">
+          <input [(ngModel)]="state.tempRuleTitle" aria-label="临时规则标题" />
+          <input [(ngModel)]="state.tempRuleImpact" aria-label="临时规则影响" />
+          <button type="button" class="primary-button compact" (click)="state.addTemporaryRule()">加入本次提号</button>
+        </div>
+
+        <div class="rule-focus-grid">
+          <article class="rule-card" *ngFor="let rule of state.rules.slice(0, 6)" [class.active]="rule.selected">
+            <div>
+              <span class="rule-category">{{ rule.category }}</span>
+              <h4>{{ rule.title }}</h4>
+              <p>{{ rule.description }}</p>
+              <small>{{ rule.source }} · {{ rule.impact }}</small>
+            </div>
+            <button
+              type="button"
+              class="toggle"
+              [class.on]="rule.selected"
+              (click)="state.toggleRule(rule)"
+              [attr.aria-pressed]="rule.selected"
+              title="启用或停用规则"
+            >
+              <span></span>
+            </button>
+          </article>
+        </div>
+      </section>
+
+      <section class="stage-card engine-stage" *ngIf="state.currentStep === 4">
+        <div class="stage-heading">
+          <div>
+            <p class="eyebrow">Step 4</p>
+            <h3>推荐引擎</h3>
+            <small>把资源召回、风险过滤、近10条采样和评分排序压缩成可复核动作。</small>
+          </div>
+          <div class="panel-actions">
+            <button type="button" class="ghost-button compact" (click)="state.runSampling()">完成采样</button>
+            <button type="button" class="primary-button compact" (click)="state.generateRecommendations()">运行提号</button>
+          </div>
+        </div>
+
+        <div class="engine-grid">
+          <section class="activity-list">
+            <article *ngFor="let activity of state.activities" [class.running]="activity.status === '进行中'">
+              <span>{{ activity.status }}</span>
+              <div>
+                <strong>{{ activity.title }}</strong>
+                <small>{{ activity.detail }}</small>
+              </div>
+            </article>
+          </section>
+
+          <section class="sampling-list">
+            <article *ngFor="let task of state.samplingTasks">
+              <header>
+                <strong>{{ task.account }}</strong>
+                <small>{{ task.platform }} · {{ task.status }}</small>
+              </header>
+              <div class="progress"><i [style.width.%]="task.progress"></i></div>
+              <p>{{ task.result }}</p>
+            </article>
+          </section>
+        </div>
+      </section>
+
+      <section class="stage-card feedback-stage" *ngIf="state.currentStep === 6">
+        <div class="stage-heading">
+          <div>
+            <p class="eyebrow">Step 6</p>
+            <h3>反馈学习</h3>
+            <small>客户反馈不会自动污染规则库,先提炼成待确认规则。</small>
+          </div>
+          <button type="button" class="primary-button compact" (click)="state.extractRules()">提炼规则</button>
+        </div>
+
+        <div class="feedback-stage-grid">
+          <div class="feedback-box">
+            <textarea [(ngModel)]="state.feedbackText" aria-label="客户反馈"></textarea>
+            <div class="feedback-presets">
+              <button type="button" *ngFor="let preset of state.feedbackPresets" (click)="state.appendFeedbackPreset(preset)">
+                {{ preset }}
+              </button>
+            </div>
+          </div>
+          <div class="learned-list">
+            <article *ngFor="let item of state.learnedRules" [class.approved]="item.approved">
+              <header>
+                <strong>{{ item.title }}</strong>
+                <em>{{ item.confidence }}%</em>
+              </header>
+              <p>{{ item.description }}</p>
+              <small>{{ item.action }}</small>
+              <div class="panel-actions">
+                <button type="button" class="text-button" (click)="state.approveLearnedRule(item)" [disabled]="item.approved">
+                  {{ item.approved ? '已入库' : '确认入库' }}
+                </button>
+                <button type="button" class="text-button danger-text" (click)="state.rejectLearnedRule(item)">驳回</button>
+              </div>
+            </article>
+          </div>
+        </div>
+      </section>
+    </main>
+
+    <aside class="flow-aside">
+      <section class="assistant-card">
+        <p class="eyebrow">业务检查</p>
+        <div class="business-checklist">
+          <button
+            type="button"
+            *ngFor="let item of state.businessChecklist"
+            [class.done]="state.isChecklistDone(item.key)"
+            (click)="state.goStep(state.businessChecklist.indexOf(item) + 1)"
+          >
+            <span>{{ state.isChecklistDone(item.key) ? '✓' : '·' }}</span>
+            <div>
+              <strong>{{ item.label }}</strong>
+              <small>{{ item.detail }}</small>
+            </div>
+          </button>
+        </div>
+      </section>
+
+      <section class="assistant-card">
+        <div class="section-mini-head">
+          <strong>推荐引擎状态</strong>
+          <small>压缩展示,不再单独占一个页面</small>
+        </div>
+        <div class="mini-pipeline">
+          <article
+            *ngFor="let stage of state.workspacePipelineStages"
+            [class.done]="stage.status === '完成'"
+            [class.running]="stage.status === '进行中'"
+          >
+            <span>{{ stage.status }}</span>
+            <div>
+              <strong>{{ stage.title }}</strong>
+              <small>{{ stage.output }}</small>
+            </div>
+          </article>
+        </div>
+      </section>
+
+      <section class="assistant-card">
+        <div class="section-mini-head">
+          <strong>快捷操作</strong>
+          <button type="button" class="text-button" (click)="state.toggleAdvancedWorkspace()">
+            {{ state.showAdvancedWorkspace ? '收起细节' : '展开细节' }}
+          </button>
+        </div>
+        <div class="shortcut-grid one-column">
+          <button type="button" *ngFor="let shortcut of state.businessShortcuts" (click)="state.runBusinessShortcut(shortcut.id)">
+            <strong>{{ shortcut.title }}</strong>
+            <small>{{ shortcut.detail }}</small>
+          </button>
+        </div>
+      </section>
+
+      <section class="assistant-card" *ngIf="state.showAdvancedWorkspace">
+        <div class="section-mini-head">
+          <strong>客户临时改需求试算</strong>
+          <small>{{ state.activeScenarioCount }} 个生效</small>
+        </div>
+        <div class="scenario-grid compact">
+          <button
+            type="button"
+            *ngFor="let scenario of state.briefScenarios"
+            [class.active]="scenario.selected"
+            (click)="state.toggleScenario(scenario)"
+          >
+            <strong>{{ scenario.label }}</strong>
+            <small>{{ scenario.impact }}</small>
+          </button>
+        </div>
+      </section>
+    </aside>
+  </div>
+
+  <ng-template #recommendationStep>
+    <section class="recommendation-area flow-recommendation">
+      <div class="section-heading">
+        <div>
+          <p class="eyebrow">Step 5</p>
+          <h3>导出推荐表前,复核账号名单和内容证据</h3>
+        </div>
+        <div class="panel-actions">
+          <button type="button" class="ghost-button" (click)="state.rotateCandidate()">换一批/补足备选</button>
+          <button type="button" class="primary-button" (click)="state.exportRecommendations()">↓ 导出名单</button>
+        </div>
+      </div>
+
+      <div class="filter-bar">
+        <label>
+          平台
+          <select [(ngModel)]="state.selectedPlatform">
+            <option *ngFor="let platform of state.platforms" [ngValue]="platform">{{ platform }}</option>
+          </select>
+        </label>
+        <label>
+          状态
+          <select [(ngModel)]="state.selectedStatus">
+            <option *ngFor="let status of statuses" [ngValue]="status">{{ status }}</option>
+          </select>
+        </label>
+        <label>
+          最高报价
+          <input type="range" min="3000" max="20000" step="1000" [(ngModel)]="state.budgetMax" />
+          <strong>{{ state.budgetMax | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }}</strong>
+        </label>
+        <label>
+          排序
+          <select [(ngModel)]="state.sortMode">
+            <option [ngValue]="'综合分'">综合分</option>
+            <option [ngValue]="'风格匹配'">风格匹配</option>
+            <option [ngValue]="'报价升序'">报价升序</option>
+          </select>
+        </label>
+      </div>
+
+      <div class="bulk-toolbar">
+        <strong>已选 {{ state.selectedCandidateList.length }} 个账号</strong>
+        <button type="button" class="text-button" (click)="state.selectVisibleCandidates()">勾选当前筛选</button>
+        <button type="button" class="text-button" (click)="state.runBusinessShortcut('client-preview')">客户版预览</button>
+        <button type="button" class="text-button" (click)="state.bulkStatus('强推荐')">批量强推荐</button>
+        <button type="button" class="text-button" (click)="state.bulkStatus('备选')">批量备选</button>
+        <button type="button" class="text-button danger-text" (click)="state.bulkStatus('已剔除')">批量剔除</button>
+        <button type="button" class="ghost-button compact" (click)="state.toggleCompare()">
+          {{ state.compareOpen ? '收起对比' : '展开对比' }}
+        </button>
+      </div>
+
+      <div class="compare-panel" *ngIf="state.compareOpen">
+        <article *ngFor="let candidate of state.compareCandidates" (click)="state.openCandidate(candidate)">
+          <header>
+            <strong>{{ candidate.name }}</strong>
+            <em
+              [class.good]="candidate.status === '强推荐'"
+              [class.warn]="candidate.status === '备选'"
+              [class.danger]="candidate.status === '需复核' || candidate.status === '已剔除'"
+            >
+              {{ candidate.status }}
+            </em>
+          </header>
+          <div class="compare-metrics">
+            <span>平台 <b>{{ candidate.platform }}</b></span>
+            <span>报价 <b>{{ candidate.price | currency: 'CNY' : 'symbol-narrow' : '1.0-0' }}</b></span>
+            <span>综合 <b>{{ candidate.score }}</b></span>
+            <span>风格 <b>{{ candidate.styleMatch }}%</b></span>
+          </div>
+          <p>{{ state.previewAudience === '客户版' ? candidate.reason : candidate.risk }}</p>
+        </article>
+      </div>
+
+      <div class="recommendation-layout">
+        <div class="recommendation-list">
+          <article
+            class="candidate-row"
+            *ngFor="let candidate of state.filteredCandidates"
+            [class.active]="state.selectedCandidate.id === candidate.id"
+            [class.dimmed]="!candidate.selected"
+            (click)="state.openCandidate(candidate)"
+          >
+            <label class="candidate-check" (click)="$event.stopPropagation()">
+              <input type="checkbox" [checked]="candidate.selected" (change)="state.toggleCandidate(candidate)" />
+              <span></span>
+            </label>
+            <div class="avatar">{{ candidate.platform.slice(0, 1) }}</div>
+            <div>
+              <strong>{{ candidate.name }}</strong>
+              <small>{{ candidate.platform }} · {{ candidate.fans }}粉丝 · {{ candidate.quota }}</small>
+              <p>{{ candidate.reason }}</p>
+            </div>
+            <div class="candidate-score">
+              <strong>{{ candidate.score }}</strong>
+              <small>{{ candidate.styleMatch }}% 风格</small>
+            </div>
+            <em
+              [class.good]="candidate.status === '强推荐'"
+              [class.warn]="candidate.status === '备选'"
+              [class.danger]="candidate.status === '需复核' || candidate.status === '已剔除'"
+            >
+              {{ candidate.status }}
+            </em>
+          </article>
+        </div>
+
+        <app-account-detail></app-account-detail>
+      </div>
+    </section>
+  </ng-template>
+</section>

+ 17 - 0
src/app/pages/workspace-page.component.ts

@@ -0,0 +1,17 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { AccountDetailComponent } from '../components/account-detail.component';
+import { DemoStateService } from '../demo-state.service';
+import { CandidateStatus } from '../models';
+
+@Component({
+  selector: 'app-workspace-page',
+  imports: [CommonModule, FormsModule, AccountDetailComponent],
+  templateUrl: './workspace-page.component.html'
+})
+export class WorkspacePageComponent {
+  statuses: Array<CandidateStatus | '全部'> = ['全部', '强推荐', '备选', '需复核', '已剔除'];
+
+  constructor(public state: DemoStateService) {}
+}

+ 13 - 0
src/index.html

@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>提号AI</title>
+  <base href="/">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link rel="icon" type="image/x-icon" href="favicon.ico">
+</head>
+<body>
+  <app-root></app-root>
+</body>
+</html>

+ 6 - 0
src/main.ts

@@ -0,0 +1,6 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { appConfig } from './app/app.config';
+import { App } from './app/app';
+
+bootstrapApplication(App, appConfig)
+  .catch((err) => console.error(err));

+ 22 - 0
src/styles.scss

@@ -0,0 +1,22 @@
+* {
+  box-sizing: border-box;
+}
+
+html {
+  min-height: 100%;
+  background: #f4f5f1;
+}
+
+body {
+  min-height: 100%;
+  margin: 0;
+  font-family:
+    Inter, "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
+  color: #1f2528;
+  background: #f4f5f1;
+}
+
+::selection {
+  background: #1f8a70;
+  color: #fff;
+}

+ 15 - 0
tsconfig.app.json

@@ -0,0 +1,15 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "./out-tsc/app",
+    "types": []
+  },
+  "include": [
+    "src/**/*.ts"
+  ],
+  "exclude": [
+    "src/**/*.spec.ts"
+  ]
+}

+ 34 - 0
tsconfig.json

@@ -0,0 +1,34 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+  "compileOnSave": false,
+  "compilerOptions": {
+    "strict": true,
+    "noImplicitOverride": true,
+    "noPropertyAccessFromIndexSignature": true,
+    "noImplicitReturns": true,
+    "noFallthroughCasesInSwitch": true,
+    "skipLibCheck": true,
+    "isolatedModules": true,
+    "experimentalDecorators": true,
+    "importHelpers": true,
+    "target": "ES2022",
+    "module": "preserve"
+  },
+  "angularCompilerOptions": {
+    "enableI18nLegacyMessageIdFormat": false,
+    "strictInjectionParameters": true,
+    "strictInputAccessModifiers": true,
+    "typeCheckHostBindings": true,
+    "strictTemplates": true
+  },
+  "files": [],
+  "references": [
+    {
+      "path": "./tsconfig.app.json"
+    },
+    {
+      "path": "./tsconfig.spec.json"
+    }
+  ]
+}

+ 14 - 0
tsconfig.spec.json

@@ -0,0 +1,14 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "./out-tsc/spec",
+    "types": [
+      "jasmine"
+    ]
+  },
+  "include": [
+    "src/**/*.ts"
+  ]
+}