From 982fa188e2b5a3a76ed60cccc28aa6be5a80d5e3 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Thu, 5 Nov 2026 23:18:09 +0800 Subject: [PATCH] chore: import existing Endoleap Pages Router project --- .env.example | 2 + .gitignore | 6 + AGENTS.md | 9 + PERFORMANCE.md | 63 + README.md | 57 + VALIDATION.md | 18 + components.json | 19 + next-env.d.ts | 7 + next.config.ts | 3 + package-lock.json | 2639 +++++++++++++++ package.json | 30 + postcss.config.mjs | 1 + public/assets/dashboardcontext-img.svg | 5 + public/assets/dashboardcontext-imgFrame.svg | 6 + .../assets/dashboardcontext-imgIconBell.svg | 10 + public/assets/dashboardcontext-imgIconBot.svg | 10 + .../dashboardcontext-imgIconChevronDown.svg | 5 + .../dashboardcontext-imgIconChevronDown1.svg | 5 + .../dashboardcontext-imgIconChevronDown2.svg | 5 + .../dashboardcontext-imgIconChevronDown3.svg | 5 + .../assets/dashboardcontext-imgIconCircle.svg | 10 + .../dashboardcontext-imgIconEllipsis.svg | 7 + .../dashboardcontext-imgIconExternalLink.svg | 12 + public/assets/dashboardcontext-imgIconEye.svg | 6 + .../dashboardcontext-imgIconFileText.svg | 9 + .../dashboardcontext-imgIconFileText1.svg | 9 + .../assets/dashboardcontext-imgIconHand.svg | 13 + .../dashboardcontext-imgIconImagePlus.svg | 14 + .../assets/dashboardcontext-imgIconLayers.svg | 12 + .../dashboardcontext-imgIconLayers1.svg | 12 + ...ashboardcontext-imgIconLayoutDashboard.svg | 13 + ...shboardcontext-imgIconLayoutDashboard1.svg | 13 + .../assets/dashboardcontext-imgIconLink2.svg | 7 + .../dashboardcontext-imgIconMousePointer2.svg | 5 + .../dashboardcontext-imgIconPanelLeft.svg | 11 + .../assets/dashboardcontext-imgIconPlus.svg | 6 + .../assets/dashboardcontext-imgIconPlus1.svg | 6 + .../assets/dashboardcontext-imgIconRedo2.svg | 6 + .../assets/dashboardcontext-imgIconScan.svg | 8 + .../assets/dashboardcontext-imgIconScan1.svg | 13 + .../assets/dashboardcontext-imgIconSearch.svg | 11 + .../dashboardcontext-imgIconSettings.svg | 6 + .../assets/dashboardcontext-imgIconShare2.svg | 14 + .../assets/dashboardcontext-imgIconSquare.svg | 10 + .../dashboardcontext-imgIconSquare1.svg | 10 + .../dashboardcontext-imgIconSunMoon.svg | 14 + .../assets/dashboardcontext-imgIconType.svg | 7 + .../assets/dashboardcontext-imgIconType1.svg | 7 + .../assets/dashboardcontext-imgIconType2.svg | 7 + .../assets/dashboardcontext-imgIconUndo2.svg | 6 + public/assets/landingcontext-imgFrame.svg | 6 + public/assets/landingcontext-imgFrame1.svg | 11 + public/assets/landingcontext-imgFrame2.svg | 11 + public/assets/landingcontext-imgFrame3.svg | 11 + public/assets/landingcontext-imgFrame4.svg | 10 + public/assets/landingcontext-imgFrame5.svg | 11 + public/assets/landingcontext-imgFrame6.svg | 6 + public/assets/landingcontext-imgFrame7.svg | 7 + public/assets/landingcontext-imgFrame8.svg | 6 + public/assets/landingcontext-imgFrame9.svg | 6 + public/assets/logincontext-imgEllipse.svg | 6 + public/assets/logincontext-imgEllipse1.svg | 6 + public/assets/logincontext-imgFrame.svg | 6 + .../logincontext-imgIconArrowUpRight.svg | 6 + public/assets/logincontext-imgIconEye.svg | 6 + src/components/brand.tsx | 20 + src/components/icon.tsx | 10 + src/components/ui/button.tsx | 58 + src/components/ui/dialog.tsx | 122 + src/lib/api.ts | 56 + src/lib/utils.ts | 5 + src/lib/workspace.ts | 43 + src/pages/_app.tsx | 18 + src/pages/_document.tsx | 12 + src/pages/api/foundry/[...path].ts | 99 + src/pages/api/oauth/[provider].ts | 26 + src/pages/auth/callback.tsx | 1 + src/pages/dashboard.tsx | 934 ++++++ src/pages/index.tsx | 340 ++ src/pages/login.tsx | 243 ++ src/styles/globals.css | 2865 +++++++++++++++++ tests/api-smoke.mjs | 114 + tests/workspace.test.mjs | 82 + tsconfig.json | 22 + 84 files changed, 8374 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 PERFORMANCE.md create mode 100644 README.md create mode 100644 VALIDATION.md create mode 100644 components.json create mode 100644 next-env.d.ts create mode 100644 next.config.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 public/assets/dashboardcontext-img.svg create mode 100644 public/assets/dashboardcontext-imgFrame.svg create mode 100644 public/assets/dashboardcontext-imgIconBell.svg create mode 100644 public/assets/dashboardcontext-imgIconBot.svg create mode 100644 public/assets/dashboardcontext-imgIconChevronDown.svg create mode 100644 public/assets/dashboardcontext-imgIconChevronDown1.svg create mode 100644 public/assets/dashboardcontext-imgIconChevronDown2.svg create mode 100644 public/assets/dashboardcontext-imgIconChevronDown3.svg create mode 100644 public/assets/dashboardcontext-imgIconCircle.svg create mode 100644 public/assets/dashboardcontext-imgIconEllipsis.svg create mode 100644 public/assets/dashboardcontext-imgIconExternalLink.svg create mode 100644 public/assets/dashboardcontext-imgIconEye.svg create mode 100644 public/assets/dashboardcontext-imgIconFileText.svg create mode 100644 public/assets/dashboardcontext-imgIconFileText1.svg create mode 100644 public/assets/dashboardcontext-imgIconHand.svg create mode 100644 public/assets/dashboardcontext-imgIconImagePlus.svg create mode 100644 public/assets/dashboardcontext-imgIconLayers.svg create mode 100644 public/assets/dashboardcontext-imgIconLayers1.svg create mode 100644 public/assets/dashboardcontext-imgIconLayoutDashboard.svg create mode 100644 public/assets/dashboardcontext-imgIconLayoutDashboard1.svg create mode 100644 public/assets/dashboardcontext-imgIconLink2.svg create mode 100644 public/assets/dashboardcontext-imgIconMousePointer2.svg create mode 100644 public/assets/dashboardcontext-imgIconPanelLeft.svg create mode 100644 public/assets/dashboardcontext-imgIconPlus.svg create mode 100644 public/assets/dashboardcontext-imgIconPlus1.svg create mode 100644 public/assets/dashboardcontext-imgIconRedo2.svg create mode 100644 public/assets/dashboardcontext-imgIconScan.svg create mode 100644 public/assets/dashboardcontext-imgIconScan1.svg create mode 100644 public/assets/dashboardcontext-imgIconSearch.svg create mode 100644 public/assets/dashboardcontext-imgIconSettings.svg create mode 100644 public/assets/dashboardcontext-imgIconShare2.svg create mode 100644 public/assets/dashboardcontext-imgIconSquare.svg create mode 100644 public/assets/dashboardcontext-imgIconSquare1.svg create mode 100644 public/assets/dashboardcontext-imgIconSunMoon.svg create mode 100644 public/assets/dashboardcontext-imgIconType.svg create mode 100644 public/assets/dashboardcontext-imgIconType1.svg create mode 100644 public/assets/dashboardcontext-imgIconType2.svg create mode 100644 public/assets/dashboardcontext-imgIconUndo2.svg create mode 100644 public/assets/landingcontext-imgFrame.svg create mode 100644 public/assets/landingcontext-imgFrame1.svg create mode 100644 public/assets/landingcontext-imgFrame2.svg create mode 100644 public/assets/landingcontext-imgFrame3.svg create mode 100644 public/assets/landingcontext-imgFrame4.svg create mode 100644 public/assets/landingcontext-imgFrame5.svg create mode 100644 public/assets/landingcontext-imgFrame6.svg create mode 100644 public/assets/landingcontext-imgFrame7.svg create mode 100644 public/assets/landingcontext-imgFrame8.svg create mode 100644 public/assets/landingcontext-imgFrame9.svg create mode 100644 public/assets/logincontext-imgEllipse.svg create mode 100644 public/assets/logincontext-imgEllipse1.svg create mode 100644 public/assets/logincontext-imgFrame.svg create mode 100644 public/assets/logincontext-imgIconArrowUpRight.svg create mode 100644 public/assets/logincontext-imgIconEye.svg create mode 100644 src/components/brand.tsx create mode 100644 src/components/icon.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/lib/api.ts create mode 100644 src/lib/utils.ts create mode 100644 src/lib/workspace.ts create mode 100644 src/pages/_app.tsx create mode 100644 src/pages/_document.tsx create mode 100644 src/pages/api/foundry/[...path].ts create mode 100644 src/pages/api/oauth/[provider].ts create mode 100644 src/pages/auth/callback.tsx create mode 100644 src/pages/dashboard.tsx create mode 100644 src/pages/index.tsx create mode 100644 src/pages/login.tsx create mode 100644 src/styles/globals.css create mode 100644 tests/api-smoke.mjs create mode 100644 tests/workspace.test.mjs create mode 100644 tsconfig.json diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..10a3552 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +FOUNDRY_API_ORIGIN=https://api.foundry.entroia.com +NEXT_PUBLIC_FOUNDRY_PROJECT=endoleap diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5f328f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +.next/ +.env* +!.env.example +*.tsbuildinfo +.DS_Store diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..af3b7c8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,9 @@ + + +## This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. + +This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. + + diff --git a/PERFORMANCE.md b/PERFORMANCE.md new file mode 100644 index 0000000..80026be --- /dev/null +++ b/PERFORMANCE.md @@ -0,0 +1,63 @@ +# 卡顿与首次创建失败检查 + +范围:本地 Next.js 前端、Foundry 代理、线上只读健康检查与现有 Go 代码。没有读取浏览器会话令牌,也没有向用户的线上账号写测试数据。 + +## 结论与证据 + +主要等待位于本地前端到公网 API 的请求链路;原来的前端串行加载进一步累加了这部分延迟。尚无证据表明页面绘制或某条业务 SQL 是这次秒级等待的主要来源。下面的采样数量有限,不是负载测试,也不能代替真实授权请求的逐段追踪。 + +| 测量位置 | 本次样本 | +| --- | --- | +| 本地 /login HTTP 完整响应,3 次 | 1.6、1.8、7.0 ms | +| 本地代理调用未登录 /profile,修改前,3 次 | 473、686、1262 ms | +| 公网 /healthz,直连、新连接,3 次 | 1.38、2.71、4.09 s | +| 公网 /healthz,经当前 Clash 代理,3 次 | 1.19、2.65、3.28 s | +| 服务器容器内 /readyz,5 次 | 10–81 ms | +| 服务器访问 Google token URL(无有效 code),3 次 | 52、74、309 ms | +| 服务器访问 Google userinfo(无会话),3 次 | 55、60、112 ms | + +本地代理新增 Server-Timing 后,再测同一条未登录 /profile: + +| 样本 | 等待上游响应头 | 代理总耗时 | 总耗时减去上游等待 | +| --- | --- | --- | --- | +| 1 | 5196.4 ms | 5198.3 ms | 1.9 ms | +| 2 | 614.6 ms | 615.0 ms | 0.4 ms | +| 3 | 1080.6 ms | 1081.5 ms | 0.9 ms | + +这条未登录请求在后端会话格式校验时就返回 401,不需要业务 SQL。上游耗时包含 DNS、连接/TLS、公网传输、边缘入口与后端响应;这次未在边缘入口加分段追踪,不能把它进一步精确归因给某一个网络跳点。直连与代理样本都有波动,目前不支持简单添加代理规则即可解决的结论。 + +## 代码中的等待与失败点 + +1. 登录回调先兑换会话,再导航到 dashboard;dashboard 原来依次获取 profile、workspaces,最后再请求首个空间的画布。资料与空间没有数据依赖,原来的串行等待是多余的。 +2. 初次进入的账号可能没有 workspace。原来的创建画布分支直接抛出 workspace_required,错误映射又没有这个编码,所以截图只显示“操作未完成,请稍后重试”。没有发出创建画布 HTTP 请求。 +3. 切换空间时没有取消旧读取;旧列表还可能在创建完成后返回,从而覆盖刚添加的画布。 +4. 画布读取期间显示空状态,Google 跳转时缺乏忙碌提示,会把真实等待和“操作没有生效”混在一起。 +5. 全局 h2 样式覆盖 DialogTitle 的字体工具类,导致截图中的弹窗标题异常偏大。 + +## 本地已修改 + +- src/lib/workspace.ts:并行加载资料和空间;创建首张画布前建立默认个人空间,空间创建成功后立即保留其 ID,避免画布失败重试时重复创建空间。 +- src/pages/dashboard.tsx:接入上述流程;取消过期读取,防止旧列表覆盖新画布,增加画布加载状态;读取空间失败时禁止误判为“尚无空间”;限定弹窗标题样式。 +- src/lib/api.ts:补充空间、物料与超时的明确错误提示。 +- src/pages/api/foundry/[...path].ts:增加仅含耗时数字的 Server-Timing;取消已断开的上游读取;明确区分超时,保持 HttpOnly 会话处理。 +- src/pages/login.tsx:Google / Slack 跳转提供忙碌状态,避免重复点击。 +- src/styles/globals.css:明确限定弹窗标题、描述字体大小。 +- tests/workspace.test.mjs:覆盖读取并行、首张画布、创建失败后的重试、已有空间直接创建。 +- tests/api-smoke.mjs:保留会话安全检查并验证耗时标记。 + +没有修改后端业务源码、路由安全策略或线上数据。公网链路延迟仍待进一步追踪;本轮没有把它宣称为已解决。 + +## 验证 + +- 最终 npm run build 成功,包含 TypeScript 检查。 +- 4 项 workspace 流程回归全部成功。 +- API 会话、跨站拒绝、白名单与耗时标记 smoke 通过。 +- 隔离浏览器验收:空账号直接点击新建,创建“个人空间”和“周末的灵感”成功。模拟旧画布列表延迟 650 ms,新建响应 100 ms,画布仍保持可见,没有被旧列表覆盖。 +- 隔离后端记录 profile 与 workspaces 在相隔 2 ms 时发起,确认已并行。 +- 本地生产预览已重启到 http://localhost:17321。原有登录 Cookie 保留;刷新页面即可载入新代码。 +- 首次画布的完整浏览器回归使用本机模拟后端;没有替用户创建线上测试画布。 + +![首次创建回归(本机隔离数据)](/Users/zzyang/Documents/Codex/2026-11-05/foundry-core-codex-integration/outputs/foundry-first-board-check.jpg) + + +后续真实账号验收已完成:创建「个人空间」和「周末的灵感」后,完整刷新页面仍能读取画布。此前的隔离测试限制已由此项验收补齐,详情见 VALIDATION.md。 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f6049c --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# 啡跃 Endoleap + +本地 Next.js Pages Router + TypeScript + Tailwind CSS + shadcn/ui 项目。首页和账户页参考 qyof 的 PROMPT 文件,工作台结合双侧栏画布、Notion 的留白与 Miro 的空间组织方式。Other Designs 用于首页叙事与版式参考。 + +项目目录:`/Users/zzyang/endoleap`。 + +## 启动 + +```sh +npm ci +npm run dev +``` + +默认仅监听本机 localhost:17321。生产模式:`npm run build && npm start`。 + +- 首页:/ +- 登录、注册:/login +- 登录回调:/auth/callback +- 真实工作台:/dashboard +- 本地演示:/dashboard?demo=1 + +## 配置 + +复制 .env.example 为 .env.local,按实际部署填写: + +- FOUNDRY_API_ORIGIN:仅供 Next 服务端请求后端,默认 https://api.foundry.entroia.com。 +- NEXT_PUBLIC_FOUNDRY_PROJECT:项目标识,默认 endoleap。 + +Slack Client Secret、Signing Secret、Verification Token、用户令牌与 app token 均不需要放入此前端。浏览器调用同源 Next API,由服务端转发到 Foundry。Foundry 会话保存在 HttpOnly / SameSite=Lax Cookie,生产 HTTPS 反向代理需传 X-Forwarded-Proto=https。不要将原始会话写入客户端存储。 + +Google / Slack 的提供方回调仍是 Foundry 后端地址;后端的项目回调映射必须指向本前端 /auth/callback。协议、主机名、端口必须与启动第三方登录时一致,否则 sessionStorage 中的 verifier 无法恢复。正式账号授权、邮件验证与 OAuth 全流程尚未完成真人验收;HTTP 302 跳转成功不能代表登录成功。 + +## 当前功能与范围 + +- 响应式首页、锚点导航与 FAQ。 +- 邮箱注册 / 登录 / 邮件验证兑换,Google 和 Slack 的 PKCE 登录入口及回调处理。 +- 真实用户资料、空间列表与创建、画布列表与创建。资料和空间并行读取;首次创建画布时自动建立个人空间。 +- 本地演示有示例画布、搜索、新建、画布界面、笔记浏览器保存、缩放、待办勾选和临时文字节点。 +- 图形编辑、连接线、分享、Agent、收藏及完整布局持久化尚未接入。画布界面是交互预览,不是完整编辑器;演示数据不写入线上。 +- 本地演示仅用于查看界面,不提供后端认证与权限。 + +Figma 原始 Logo、人物插画与图标已下载到 public/assets,不依赖临时 Figma URL。品牌保持啡跃 Endoleap;shadcn Button / Dialog 使用官方 registry 源码。依赖版本固定,package-lock.json 可用于 npm ci。 + +## 验证 + +```sh +npm run build +node tests/api-smoke.mjs +``` + +API 测试使用本机临时后端和独立前端进程,检查会话 Cookie、令牌不泄漏、同源校验和路径白名单,不访问线上账号。构建需先完成。浏览器验收覆盖登录/注册切换、演示画布创建、搜索空状态、笔记保存、桌面与 390px 手机布局。 + +项目尚未创建远程仓库或部署。 + + +性能分析、实测耗时和修复说明见 [PERFORMANCE.md](PERFORMANCE.md)。 +流程回归可在支持 TypeScript 类型擦除的 Node 版本执行:`node --experimental-strip-types --test tests/workspace.test.mjs`。 diff --git a/VALIDATION.md b/VALIDATION.md new file mode 100644 index 0000000..93c9dff --- /dev/null +++ b/VALIDATION.md @@ -0,0 +1,18 @@ +# 本地验收记录 + +- 生产构建:Next.js 16.4.5,TypeScript 检查及 6 个页面静态生成成功。 +- API 会话测试:HttpOnly / SameSite Cookie、令牌不返回前端、带会话代理、401、跨站拒绝、非法 Origin、路径白名单、OAuth challenge 校验通过。 +- 线上轻量检查:profile 401;空登录参数 400;Slack 与 Google 启动登录均返回 302,目标分别为 slack.com、accounts.google.com。未执行真人账户登录。 +- 浏览器:登录/注册切换、演示画布创建、搜索无结果、打开画布、笔记保存、待办勾选,以及未登录访问 /dashboard 返回 /login。 +- 1440px 首页和 390px 首页/工作台:页面宽度等于视口宽度,未发现横向溢出。首页图片全部加载。 +- Figma:原为 DIRECT;已添加 figma.com、figmausercontent.com 代理规则并从实际连接确认 DomainSuffix 生效。验证时代理组当前节点为香港 Y03。 +- 本机生产预览:http://localhost:17321(只监听本机)。 +- 尚未完成:真人 OAuth / 邮箱验证完整回路、后端项目回调地址匹配、完整编辑器布局持久化、分享/收藏/Agent。 +- 本项目仅本地创建,未新建 Gitea 远程仓库、未提交或推送。 + + +后续性能检查与首次创建流程修复已完成,最终构建、API smoke、4 项流程回归与隔离浏览器验收通过。详见 PERFORMANCE.md。 + +## 真实账号创建验收 + +已在用户已登录的 Chrome 中打开 http://localhost:17321/dashboard。初始空间列表为空;使用新建画布流程提交用户原先填写的「周末的灵感」后,创建了「个人空间」和该画布。完整刷新页面后,侧栏和主列表仍显示该画布,确认读取到后端持久化记录。此项为真实账号验收,补充此前只完成隔离模拟测试的限制。 diff --git a/components.json b/components.json new file mode 100644 index 0000000..6f9470a --- /dev/null +++ b/components.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/styles/globals.css", + "baseColor": "neutral", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..15849f6 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,7 @@ +/// +/// +import "./.next/types/routes.d.ts"; +import "./.next/types/root-params.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..c111517 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,3 @@ +import type { NextConfig } from "next"; +const config: NextConfig = { reactStrictMode: true, poweredByHeader: false }; +export default config; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ea58e9e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2639 @@ +{ + "name": "endoleap", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "endoleap", + "version": "0.1.0", + "dependencies": { + "@radix-ui/react-dialog": "1.3.1", + "@radix-ui/react-slot": "1.5.0", + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "lucide-react": "1.69.0", + "next": "16.4.5", + "react": "19.3.1", + "react-dom": "19.3.1", + "tailwind-merge": "3.7.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "4.3.4", + "@types/node": "26.6.6", + "@types/react": "19.3.0", + "@types/react-dom": "19.3.0", + "tailwindcss": "4.3.4", + "typescript": "7.0.2" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.3.0.tgz", + "integrity": "sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@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.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "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/@next/env": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.4.5.tgz", + "integrity": "sha512-JwSPwpdkZL5VMl2jA/q+JI8MZdweAL3xmw5/tb9y/TLtmS0YXZnmYDzSihwk8xTj1OL+WM53gTqaj96yuLp6Xw==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.4.5.tgz", + "integrity": "sha512-W5TniBzWKASbNNwHZ/S/f1MxQUXU/LdjklVMWA0Ujbfl7SZnUzFls45hO0i/sF7Bx1jJBWp7WWmoQajXtX/O8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.4.5.tgz", + "integrity": "sha512-uWq4qkHapBDS1oFltWS4YxTb9pLHAtLNcpbuK6SmRsebLYZqpBML/j/C0op+50JYGTpZgVL/DWNt/6oWlamrrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.4.5.tgz", + "integrity": "sha512-FdRcyOx5u5P51mlAqLB9EXdd8jZO5fsdHtk4BAQSkqOywCsbTNN/rmw+jO7pnmjNdAtu2AG46NzbCL2FPDrrgw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.4.5.tgz", + "integrity": "sha512-cyvmmgtRXR8aGVT86wi9Py53IlfyCx7P2fZxuAXAoTummDnhKtUyjrMeXfapqp4qgD+gT5RqyGD/VfA16jEK7Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.4.5.tgz", + "integrity": "sha512-hPc+Fl+N22DAvqZHq559NmamXboOX5Lu8I5Wl0DezfrhTk1Zz21NQeYoZDmNI/NjTcrdsVxM72Fzn2lI+Q+vAw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.4.5.tgz", + "integrity": "sha512-gbACYE8IP/jlprNTpiWXHb8N9CofOzpnEwH2SrIz1dUbiJf1FbDssDupCAPeP1Taxe8mgG20sGZamJI7KFOdZw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.4.5.tgz", + "integrity": "sha512-+8gj++ZMo8H20Xh2ijjNqyFk5LPLw0AC4Fs4Tq/G94rjjQXhOjN4jgSWsWKPFsyY26hfIeemJIwKtMxOsp5GBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.4.5.tgz", + "integrity": "sha512-qNZj66pYXnaWLiF9R9GUbfBdrCv7kC6TaZfIwB2KH5WPc/8pEM3nVOj8hpQhWJU8S94rlH5MPDcX15+RrgUhiw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.2.0.tgz", + "integrity": "sha512-KABY+VMIRPJL+Vyzv/335FEhXXD/xDv8BMb1kl48/aXJZMH0LtHCTx5ga5RnxaEP3nZHtmTLf1P9vanmFX46bw==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz", + "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.3.0.tgz", + "integrity": "sha512-v5AYEocMISkbJ+1fTXzZpiFv7NRr3D2WiYbLIKf+FkmJ8VkP6d503eV2n34MFussHXY1pcoq3yfJiQH77dc4Mg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.3.1.tgz", + "integrity": "sha512-+0E4qvVTwjAWra9sEhJ+9BTsvHE00zkUuNw1VGh7S+Gc13dfYk+S1PVQdchWDj+XYHhAai7Z7IpzXVDCGsDplg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-context": "1.3.0", + "@radix-ui/react-dismissable-layer": "1.2.1", + "@radix-ui/react-focus-guards": "1.2.0", + "@radix-ui/react-focus-scope": "1.3.1", + "@radix-ui/react-id": "1.1.4", + "@radix-ui/react-portal": "1.2.0", + "@radix-ui/react-presence": "1.1.11", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-use-controllable-state": "1.3.0", + "@radix-ui/react-use-layout-effect": "1.1.4", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.2.1.tgz", + "integrity": "sha512-KIfDcAsx+oVylFZ4xryVKusJUrLLhTQmfnJW4kwk4Km5myvhHCrj04hnWWUC166+xD4DHdH8tQGylwYX1h6+Pg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-callback-ref": "1.1.5", + "@radix-ui/react-use-effect-event": "0.0.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.2.0.tgz", + "integrity": "sha512-MPm5R0iRGUDrDnPNxmLBkv+X7pN4XKzt+MbWJEuJQsH3NFH4omrbpXpucyYCCKTSt+na/ZxGhEWQrWTZ0285cA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.3.1.tgz", + "integrity": "sha512-ugeMhbXt4y5S2T1GnIqbWDKEN962PDwnX1fN0eKOOgf5f63Dh2mn8F1FUySlgW0iF6GiVsRF32DzuDIWTUyQJg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5", + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-callback-ref": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz", + "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.2.0.tgz", + "integrity": "sha512-StX7xXnaRU41VvFtMm9zlhVGz8XF6GmWWTXftkQaY+tqVkbs/R9UmAp5mLzHHapk5hM9RMZQvO/3usyIP/g42g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.2.0", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.11.tgz", + "integrity": "sha512-Z7/atlkab36Z8hm+V8zYc79r0W+tiOB1o0tun1By94JyadkekLQmtEAnBSP9XKXBNQsStoStS4+gX10JpS5akA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.2.0.tgz", + "integrity": "sha512-HCTSPMNqv55Qk0IX4geJbpyXazmqulcimwuyjxTkKi29v+QZbG2Zho9BnbBq4YS2PF+KlNb2CXoLz66uUmblkg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.5.0.tgz", + "integrity": "sha512-tyYd9ddPXAysAbdbD9eYxgwpCSv6f3PncqVSNKQFSR5lcJVLz3cb/pANDoYrLiHBpXv7skortyUgGUWsYuPPFQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.5" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.5.tgz", + "integrity": "sha512-Y5GBf4NKeADoXI1geiMlMuMoURT3k9MizzzKhGb/m55H94aGigZ01PIpkvsO6lML13BA6XYAXSJ6gza7vTn5nw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.3.0.tgz", + "integrity": "sha512-TAcBI7bw2ljYCbv4+zuTSd6zICu8pRt6SDN2vJ/Z06K2MXh6I9WYFe/A9ovlFDtR5HVHGm5iDxDoABm/++dbKg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.2.0", + "@radix-ui/react-use-effect-event": "0.0.5", + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz", + "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz", + "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.4.tgz", + "integrity": "sha512-b7QK/QG04v3j04NbpG82XLCedRyulnkuwUDwRa9oK/ypnJIzMapz2Wg+0TltVczjUzDaJJHIa1+jj9aMUOFMTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.5", + "jiti": "^2.7.0", + "lightningcss": "1.33.0", + "magic-string": "^1.1.0", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.4" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.4.tgz", + "integrity": "sha512-riqsRw2sLF7B1sNCCkTl3KYXEqvhTiABzZ/4oxxHfZ3c3Td60bCBfOrUuUGOiHagd3E7V+zG46c+XBDWZGFBcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.4", + "@tailwindcss/oxide-darwin-arm64": "4.3.4", + "@tailwindcss/oxide-darwin-x64": "4.3.4", + "@tailwindcss/oxide-freebsd-x64": "4.3.4", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.4", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.4", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.4", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.4", + "@tailwindcss/oxide-linux-x64-musl": "4.3.4", + "@tailwindcss/oxide-wasm32-wasi": "4.3.4", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.4", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.4" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.4.tgz", + "integrity": "sha512-qkjxt+EFocOi3mtsUS3ndlj6yj4SHubwBdvBynLnS8T4mvSzX0Enn0CpypJKmBEtczUAXOHVZKA2zTGzSNU2Sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.4.tgz", + "integrity": "sha512-i/awUA/7mJQAbA3AzCW8aQtUh5goMieUdF1zOoclLaJUCxDvsXQ8VJqpQZY3dfcHS6PJjd3tw25nNneD/mEviQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.4.tgz", + "integrity": "sha512-q56V9U6AnoYz/yj/alkDLhSQ9AZoXQSEl93f7WETa0+32CudbqM57BXdYXfMYPKudueXKaA+MG6L/0KRseF7Jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.4.tgz", + "integrity": "sha512-r0W7A+Z9HTHh7bwihJl45E/zZKLjxD50/jToVF/E/RZHSl8+EWO+4yKKJpPMcUooT9hdoip3Zx1uWnbMg4N79g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.4.tgz", + "integrity": "sha512-3aih/sRxzeYfi2Bkh+bGYNf2YU9Llamb2mpA7BNF1obYzdgEeWDAMQzK6BSwzLhs/eTdOaSur92qrGfchagUtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.4.tgz", + "integrity": "sha512-ktJSrPGQou4OqL88rDEx5CkeM9BjzrwZvYo8u7B7VL1zkBa2XBm351o4MQrek95qikb2M++26Y7w7vbH6Mgl8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.4.tgz", + "integrity": "sha512-rt3hjUxT7utAtcB+df6wHyaXDyxhE7Zd1x7L/nvB5Jb2qBb8dZwFUoWqeRja1BaF5OlSqkKSjBmVXj9OsevmCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.4.tgz", + "integrity": "sha512-XE3jO2yOOWjttpeGvpwf3/b274NMi3QapQSAI/EzsgrmYNan1Tw8dXT9JQkN7K0OgvuqiC8mcCyNvGzEkpVJPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.4.tgz", + "integrity": "sha512-PaAZ2FjJaZk9SQLYtKIfQWiFm/xtl7pX2MKPgCzn0mS/VU54yu+vP457AJdB2XFLxU3gO2abLCt8N7Lg4EbKNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.4.tgz", + "integrity": "sha512-bjO9WmoM687p8AoCIyw1DUqzpAs4JICLvNmIPxIWDmhw8IOsdubtWQLShyJmISnDKtRy1BBApHVOUl6sNFQQJA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.3", + "@emnapi/runtime": "^1.11.3", + "@emnapi/wasi-threads": "^1.2.3", + "@napi-rs/wasm-runtime": "^1.2.2", + "@tybys/wasm-util": "^0.10.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.4.tgz", + "integrity": "sha512-jCrwCvWVtt7ruMXp6dFPd5KBNU8o1tWtEdZbTL/w/hvD3lUYZA0E2mmfvTzW4QLHIx5wGQU9HeY7997R1QTrEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.4.tgz", + "integrity": "sha512-cge1wcedn1FrRSXL22lF5sNDYr8c9+VImk7zFYLPs12jkDmchSrZNfzWqOKub+5Hb/aYRdDEqERGGDKONBlOzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.4.tgz", + "integrity": "sha512-6O0QLY+1CseO8ivlYK2Y7IxNPaQ8D5ypxrV+ws34mbxknWH824J+gEWtJ0gyFiYAudmdEeXdF8kqwgXIaZRyHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.4", + "@tailwindcss/oxide": "4.3.4", + "postcss": "^8.5.25", + "tailwindcss": "4.3.4" + } + }, + "node_modules/@types/node": { + "version": "26.6.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz", + "integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.3.0" + } + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.35", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.35.tgz", + "integrity": "sha512-GNk8KX52CHqeNKGk8+7tZnQab/2k1t/BgrUHPKNdijzpEhF1saPQZHVKb6m5loSAxB39gyrTYw34Qf9CQ3u1qQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001822", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001822.tgz", + "integrity": "sha512-Y3fvWQWzc69dlCyr07tuNrEhotv+db5FpMSPD3slZnkPKwRNOKwFBz2dP966XUmWMXLTOt+YShkFoQoom3U7hg==", + "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/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "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==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.26.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.26.1.tgz", + "integrity": "sha512-PPnnSJq3azKOIewXR/uppBV/6h98dprBJ/WaQ9Qgj10xX1lJLNfg+XShpbsrSqcDSy2yYYyhfXM1wWhftqgyzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lucide-react": { + "version": "1.69.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.69.0.tgz", + "integrity": "sha512-UTFECm4yEgkgMN0kfLuxWcmlk+4u02Jrqehgk3ZXRx/Ud68OpP7hjkp67bvkBHmIpMaZCIveF1QDYeupO7XmYQ==", + "license": "ISC", + "peerDependencies": { + "@types/react": "*", + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/magic-string": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.5.tgz", + "integrity": "sha512-oLLC2+YvQUfAa+vxoufE/yc1icb87M9iXIRqAoR/2EhE/8cb3SF/+Gi0c2By1B+5Vz2e2vQtUvHiu1+63Znh+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "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/next": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/next/-/next-16.4.5.tgz", + "integrity": "sha512-rmdfsWosjTUO+6R0S3KokoIk6Kj0sWDRTe86tZHdqaWH/oXq/udX3/4xb+YQi7aWbyEFoglDU54kaifLCdXbBw==", + "license": "MIT", + "dependencies": { + "@next/env": "16.4.5", + "@swc/helpers": "0.5.23", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.5.23", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.4.5", + "@next/swc-darwin-x64": "16.4.5", + "@next/swc-linux-arm64-gnu": "16.4.5", + "@next/swc-linux-arm64-musl": "16.4.5", + "@next/swc-linux-x64-gnu": "16.4.5", + "@next/swc-linux-x64-musl": "16.4.5", + "@next/swc-win32-arm64-msvc": "16.4.5", + "@next/swc-win32-x64-msvc": "16.4.5", + "sharp": "^0.35.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", + "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.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.32.tgz", + "integrity": "sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==", + "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.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz", + "integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.1.tgz", + "integrity": "sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.28.0" + }, + "peerDependencies": { + "react": "^19.3.1" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.6.tgz", + "integrity": "sha512-9lpSSU4Mly3mrtruwLs1eLK6+gzbzqeBFwRNjIjE+9LuDpWdYctrQlQ3ej1Ilgi7gknpsTRnPoLP8DpCHqHIJw==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tailwind-merge": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.7.0.tgz", + "integrity": "sha512-XPPUyAc+cvspz3lHTcR/QgPfW2A0lv/xQNIjX3HGhLR+Nq2lHaLq5MtTesHn8GUr3W3DguT2KT5x3NVgRtYwmA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.4.tgz", + "integrity": "sha512-PCJZTFFdG+sL3gvnP1Do9o6GbkvH2q0p04xSs3f7cSvmAeK+sttG+/7ncK1fdRwKFfC7n+wDDJaOMBSefkI9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tslib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..4df8d4f --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "endoleap", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --hostname localhost --port 17321", + "build": "next build", + "start": "next start --hostname localhost --port 17321", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "next": "16.4.5", + "react": "19.3.1", + "react-dom": "19.3.1", + "class-variance-authority": "0.7.1", + "clsx": "2.1.1", + "tailwind-merge": "3.7.0", + "@radix-ui/react-slot": "1.5.0", + "@radix-ui/react-dialog": "1.3.1", + "lucide-react": "1.69.0" + }, + "devDependencies": { + "typescript": "7.0.2", + "@types/node": "26.6.6", + "@types/react": "19.3.0", + "@types/react-dom": "19.3.0", + "tailwindcss": "4.3.4", + "@tailwindcss/postcss": "4.3.4" + } +} diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..a9b5c43 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1 @@ +export default { plugins: { "@tailwindcss/postcss": {} } }; diff --git a/public/assets/dashboardcontext-img.svg b/public/assets/dashboardcontext-img.svg new file mode 100644 index 0000000..eaeaad2 --- /dev/null +++ b/public/assets/dashboardcontext-img.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/dashboardcontext-imgFrame.svg b/public/assets/dashboardcontext-imgFrame.svg new file mode 100644 index 0000000..8c35d19 --- /dev/null +++ b/public/assets/dashboardcontext-imgFrame.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/dashboardcontext-imgIconBell.svg b/public/assets/dashboardcontext-imgIconBell.svg new file mode 100644 index 0000000..08fe6cc --- /dev/null +++ b/public/assets/dashboardcontext-imgIconBell.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconBot.svg b/public/assets/dashboardcontext-imgIconBot.svg new file mode 100644 index 0000000..ebdb30a --- /dev/null +++ b/public/assets/dashboardcontext-imgIconBot.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconChevronDown.svg b/public/assets/dashboardcontext-imgIconChevronDown.svg new file mode 100644 index 0000000..eb0df99 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconChevronDown.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/dashboardcontext-imgIconChevronDown1.svg b/public/assets/dashboardcontext-imgIconChevronDown1.svg new file mode 100644 index 0000000..b8ca438 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconChevronDown1.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/dashboardcontext-imgIconChevronDown2.svg b/public/assets/dashboardcontext-imgIconChevronDown2.svg new file mode 100644 index 0000000..eb0df99 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconChevronDown2.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/dashboardcontext-imgIconChevronDown3.svg b/public/assets/dashboardcontext-imgIconChevronDown3.svg new file mode 100644 index 0000000..80129e4 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconChevronDown3.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/dashboardcontext-imgIconCircle.svg b/public/assets/dashboardcontext-imgIconCircle.svg new file mode 100644 index 0000000..ba3acdc --- /dev/null +++ b/public/assets/dashboardcontext-imgIconCircle.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconEllipsis.svg b/public/assets/dashboardcontext-imgIconEllipsis.svg new file mode 100644 index 0000000..a4ba14b --- /dev/null +++ b/public/assets/dashboardcontext-imgIconEllipsis.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconExternalLink.svg b/public/assets/dashboardcontext-imgIconExternalLink.svg new file mode 100644 index 0000000..e8d88a9 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconExternalLink.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconEye.svg b/public/assets/dashboardcontext-imgIconEye.svg new file mode 100644 index 0000000..157dcb0 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconEye.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/dashboardcontext-imgIconFileText.svg b/public/assets/dashboardcontext-imgIconFileText.svg new file mode 100644 index 0000000..b056b24 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconFileText.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconFileText1.svg b/public/assets/dashboardcontext-imgIconFileText1.svg new file mode 100644 index 0000000..d11ad44 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconFileText1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconHand.svg b/public/assets/dashboardcontext-imgIconHand.svg new file mode 100644 index 0000000..b4fbfc4 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconHand.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconImagePlus.svg b/public/assets/dashboardcontext-imgIconImagePlus.svg new file mode 100644 index 0000000..d82896d --- /dev/null +++ b/public/assets/dashboardcontext-imgIconImagePlus.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconLayers.svg b/public/assets/dashboardcontext-imgIconLayers.svg new file mode 100644 index 0000000..7085002 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconLayers.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconLayers1.svg b/public/assets/dashboardcontext-imgIconLayers1.svg new file mode 100644 index 0000000..0a11745 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconLayers1.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconLayoutDashboard.svg b/public/assets/dashboardcontext-imgIconLayoutDashboard.svg new file mode 100644 index 0000000..7a82a39 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconLayoutDashboard.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconLayoutDashboard1.svg b/public/assets/dashboardcontext-imgIconLayoutDashboard1.svg new file mode 100644 index 0000000..dd2c304 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconLayoutDashboard1.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconLink2.svg b/public/assets/dashboardcontext-imgIconLink2.svg new file mode 100644 index 0000000..0f3e17b --- /dev/null +++ b/public/assets/dashboardcontext-imgIconLink2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconMousePointer2.svg b/public/assets/dashboardcontext-imgIconMousePointer2.svg new file mode 100644 index 0000000..96f4692 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconMousePointer2.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/dashboardcontext-imgIconPanelLeft.svg b/public/assets/dashboardcontext-imgIconPanelLeft.svg new file mode 100644 index 0000000..775fd91 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconPanelLeft.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconPlus.svg b/public/assets/dashboardcontext-imgIconPlus.svg new file mode 100644 index 0000000..97d641a --- /dev/null +++ b/public/assets/dashboardcontext-imgIconPlus.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/dashboardcontext-imgIconPlus1.svg b/public/assets/dashboardcontext-imgIconPlus1.svg new file mode 100644 index 0000000..d0db25d --- /dev/null +++ b/public/assets/dashboardcontext-imgIconPlus1.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/dashboardcontext-imgIconRedo2.svg b/public/assets/dashboardcontext-imgIconRedo2.svg new file mode 100644 index 0000000..b2a1595 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconRedo2.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/dashboardcontext-imgIconScan.svg b/public/assets/dashboardcontext-imgIconScan.svg new file mode 100644 index 0000000..62982ea --- /dev/null +++ b/public/assets/dashboardcontext-imgIconScan.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconScan1.svg b/public/assets/dashboardcontext-imgIconScan1.svg new file mode 100644 index 0000000..3234af1 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconScan1.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconSearch.svg b/public/assets/dashboardcontext-imgIconSearch.svg new file mode 100644 index 0000000..829a2e5 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconSearch.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconSettings.svg b/public/assets/dashboardcontext-imgIconSettings.svg new file mode 100644 index 0000000..19a7445 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconSettings.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/dashboardcontext-imgIconShare2.svg b/public/assets/dashboardcontext-imgIconShare2.svg new file mode 100644 index 0000000..530090f --- /dev/null +++ b/public/assets/dashboardcontext-imgIconShare2.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconSquare.svg b/public/assets/dashboardcontext-imgIconSquare.svg new file mode 100644 index 0000000..32ed3ef --- /dev/null +++ b/public/assets/dashboardcontext-imgIconSquare.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconSquare1.svg b/public/assets/dashboardcontext-imgIconSquare1.svg new file mode 100644 index 0000000..f7b1855 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconSquare1.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconSunMoon.svg b/public/assets/dashboardcontext-imgIconSunMoon.svg new file mode 100644 index 0000000..259bdca --- /dev/null +++ b/public/assets/dashboardcontext-imgIconSunMoon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconType.svg b/public/assets/dashboardcontext-imgIconType.svg new file mode 100644 index 0000000..58b6687 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconType.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconType1.svg b/public/assets/dashboardcontext-imgIconType1.svg new file mode 100644 index 0000000..ebdad37 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconType1.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconType2.svg b/public/assets/dashboardcontext-imgIconType2.svg new file mode 100644 index 0000000..d3ae6d3 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconType2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/dashboardcontext-imgIconUndo2.svg b/public/assets/dashboardcontext-imgIconUndo2.svg new file mode 100644 index 0000000..5aeede4 --- /dev/null +++ b/public/assets/dashboardcontext-imgIconUndo2.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/landingcontext-imgFrame.svg b/public/assets/landingcontext-imgFrame.svg new file mode 100644 index 0000000..0f69126 --- /dev/null +++ b/public/assets/landingcontext-imgFrame.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/landingcontext-imgFrame1.svg b/public/assets/landingcontext-imgFrame1.svg new file mode 100644 index 0000000..721a74c --- /dev/null +++ b/public/assets/landingcontext-imgFrame1.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/assets/landingcontext-imgFrame2.svg b/public/assets/landingcontext-imgFrame2.svg new file mode 100644 index 0000000..7543b1f --- /dev/null +++ b/public/assets/landingcontext-imgFrame2.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/assets/landingcontext-imgFrame3.svg b/public/assets/landingcontext-imgFrame3.svg new file mode 100644 index 0000000..f15dc12 --- /dev/null +++ b/public/assets/landingcontext-imgFrame3.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/assets/landingcontext-imgFrame4.svg b/public/assets/landingcontext-imgFrame4.svg new file mode 100644 index 0000000..6344a17 --- /dev/null +++ b/public/assets/landingcontext-imgFrame4.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/landingcontext-imgFrame5.svg b/public/assets/landingcontext-imgFrame5.svg new file mode 100644 index 0000000..c83b107 --- /dev/null +++ b/public/assets/landingcontext-imgFrame5.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/assets/landingcontext-imgFrame6.svg b/public/assets/landingcontext-imgFrame6.svg new file mode 100644 index 0000000..8196ce0 --- /dev/null +++ b/public/assets/landingcontext-imgFrame6.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/landingcontext-imgFrame7.svg b/public/assets/landingcontext-imgFrame7.svg new file mode 100644 index 0000000..efb61bb --- /dev/null +++ b/public/assets/landingcontext-imgFrame7.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/assets/landingcontext-imgFrame8.svg b/public/assets/landingcontext-imgFrame8.svg new file mode 100644 index 0000000..1dfe60a --- /dev/null +++ b/public/assets/landingcontext-imgFrame8.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/landingcontext-imgFrame9.svg b/public/assets/landingcontext-imgFrame9.svg new file mode 100644 index 0000000..b562335 --- /dev/null +++ b/public/assets/landingcontext-imgFrame9.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/logincontext-imgEllipse.svg b/public/assets/logincontext-imgEllipse.svg new file mode 100644 index 0000000..a52830f --- /dev/null +++ b/public/assets/logincontext-imgEllipse.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/logincontext-imgEllipse1.svg b/public/assets/logincontext-imgEllipse1.svg new file mode 100644 index 0000000..42c7932 --- /dev/null +++ b/public/assets/logincontext-imgEllipse1.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/logincontext-imgFrame.svg b/public/assets/logincontext-imgFrame.svg new file mode 100644 index 0000000..0654b5f --- /dev/null +++ b/public/assets/logincontext-imgFrame.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/logincontext-imgIconArrowUpRight.svg b/public/assets/logincontext-imgIconArrowUpRight.svg new file mode 100644 index 0000000..a0afeab --- /dev/null +++ b/public/assets/logincontext-imgIconArrowUpRight.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/logincontext-imgIconEye.svg b/public/assets/logincontext-imgIconEye.svg new file mode 100644 index 0000000..1a51378 --- /dev/null +++ b/public/assets/logincontext-imgIconEye.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/brand.tsx b/src/components/brand.tsx new file mode 100644 index 0000000..deae253 --- /dev/null +++ b/src/components/brand.tsx @@ -0,0 +1,20 @@ +import Link from "next/link"; +export function Brand({ light = false }: { light?: boolean }) { + return ( + + + + 啡跃 Endoleap + + + ); +} diff --git a/src/components/icon.tsx b/src/components/icon.tsx new file mode 100644 index 0000000..b282cd2 --- /dev/null +++ b/src/components/icon.tsx @@ -0,0 +1,10 @@ +export function Icon({ name, size = 18 }: { name: string; size?: number }) { + return ( + + ); +} diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..775d380 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,58 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends + React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..ac2b9bb --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,122 @@ +"use client"; + +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = "DialogHeader"; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = "DialogFooter"; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/src/lib/api.ts b/src/lib/api.ts new file mode 100644 index 0000000..577a5fa --- /dev/null +++ b/src/lib/api.ts @@ -0,0 +1,56 @@ +export type Profile = { + id: string; + username: string; + display_name: string | null; + email: string | null; +}; +export async function api( + path: string, + options: RequestInit = {}, +): Promise { + const res = await fetch("/api/foundry/" + path, { + ...options, + headers: { "Content-Type": "application/json", ...options.headers }, + }); + const body = await res.json().catch(() => null); + if (!res.ok) + throw new Error(body?.error?.code || body?.error || "request_failed"); + return body as T; +} +export const PROJECT = process.env.NEXT_PUBLIC_FOUNDRY_PROJECT || "endoleap"; +export async function startOAuth(provider: "google" | "slack") { + const bytes = crypto.getRandomValues(new Uint8Array(32)); + const verifier = btoa(String.fromCharCode(...bytes)) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=/g, ""); + const digest = await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(verifier), + ); + const challenge = btoa(String.fromCharCode(...new Uint8Array(digest))) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=/g, ""); + sessionStorage.setItem("foundry_verifier", verifier); + window.location.assign("/api/oauth/" + provider + "?challenge=" + challenge); +} +export const errorText = (error: unknown) => { + const code = error instanceof Error ? error.message : ""; + const messages: Record = { + invalid_credentials: "邮箱或密码不正确,或邮箱尚未验证。", + rate_limited: "请求太频繁,请稍后再试。", + invalid_session: "登录已过期,请重新登录。", + workspace_not_loaded: "空间列表尚未加载成功,请刷新页面后重试。", + workspace_required: "请先创建或选择一个工作空间。", + invalid_workspace: "工作空间名称不符合要求,请修改后重试。", + invalid_material: "画布名称或内容不符合要求,请修改后重试。", + invalid_reference: "工作空间不存在或当前账户无权访问,请刷新空间列表。", + upstream_timeout: "连接服务超时,请稍后再试。", + upstream_unavailable: "暂时无法连接服务,请稍后重试。", + not_found: "接口暂未上线,请稍后重试。", + invalid_verification: "验证链接无效或已过期,请重新注册以获取邮件。", + slack_not_configured: "Slack 登录尚未配置完成。", + }; + return messages[code] || "操作未完成,请稍后重试。"; +}; diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..109c4e2 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,5 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/src/lib/workspace.ts b/src/lib/workspace.ts new file mode 100644 index 0000000..8dea658 --- /dev/null +++ b/src/lib/workspace.ts @@ -0,0 +1,43 @@ +import type { Profile } from "./api"; + +export type Workspace = { id: string; name: string }; +type Request = (path: string, options?: RequestInit) => Promise; + +export async function loadWorkspaceHome( + request: Request, + signal?: AbortSignal, +) { + const [profile, result] = await Promise.all([ + request("profile", { signal }), + request("workspaces", { signal }), + ]); + return { + profile, + workspaces: Array.isArray(result) ? result : result.items || [], + }; +} + +export async function createBoard( + request: Request, + title: string, + workspaceId: string, + onWorkspaceCreated: (workspace: Workspace) => void, +) { + let id = workspaceId; + if (!id) { + const workspace = await request("workspaces", { + method: "POST", + body: JSON.stringify({ name: "个人空间" }), + }); + id = workspace.id; + onWorkspaceCreated(workspace); + } + return request<{ id: string }>("workspaces/" + id + "/materials", { + method: "POST", + body: JSON.stringify({ + kind: "board", + title: title.trim(), + content: { schema_version: 1 }, + }), + }); +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx new file mode 100644 index 0000000..b45f7ef --- /dev/null +++ b/src/pages/_app.tsx @@ -0,0 +1,18 @@ +import type { AppProps } from "next/app"; +import Head from "next/head"; +import "@/styles/globals.css"; +export default function App({ Component, pageProps }: AppProps) { + return ( + <> + + 啡跃 Endoleap · 让灵感有形 + + + + + + ); +} diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx new file mode 100644 index 0000000..531fba1 --- /dev/null +++ b/src/pages/_document.tsx @@ -0,0 +1,12 @@ +import { Html, Head, Main, NextScript } from "next/document"; +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/src/pages/api/foundry/[...path].ts b/src/pages/api/foundry/[...path].ts new file mode 100644 index 0000000..a6630ab --- /dev/null +++ b/src/pages/api/foundry/[...path].ts @@ -0,0 +1,99 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +const allowed = + /^(profile|auth\/(login|register|verify-email|exchange|me|logout)|workspaces(?:\/[a-zA-Z0-9_-]+(?:\/(?:materials|search)(?:\/[a-zA-Z0-9_-]+)?)?)?)$/; +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + res.setHeader("Cache-Control", "no-store"); + if (!["GET", "POST", "PATCH", "DELETE"].includes(req.method || "")) + return res.status(405).json({ error: "method_not_allowed" }); + if (req.method !== "GET" && req.headers.origin) { + try { + if (new URL(req.headers.origin).host !== req.headers.host) + return res.status(403).json({ error: "invalid_origin" }); + } catch { + return res.status(403).json({ error: "invalid_origin" }); + } + } + const path = (Array.isArray(req.query.path) ? req.query.path : []).join("/"); + if (!allowed.test(path)) return res.status(404).json({ error: "not_found" }); + const origin = + process.env.FOUNDRY_API_ORIGIN || "https://api.foundry.entroia.com"; + const project = process.env.NEXT_PUBLIC_FOUNDRY_PROJECT || "endoleap"; + const headers: Record = { + "Content-Type": "application/json", + }; + if (req.cookies.foundry_session) + headers.Authorization = "Bearer " + req.cookies.foundry_session; + for (const h of ["x-foundry-code", "x-foundry-verifier", "if-match"]) + if (typeof req.headers[h] === "string") + headers[h] = req.headers[h] as string; + const query = new URLSearchParams(); + for (const key of ["kind", "sort", "q", "limit", "offset"]) { + const v = req.query[key]; + if (typeof v === "string" && v.length < 300) query.set(key, v); + } + const started = performance.now(); + const disconnected = new AbortController(); + const onClose = () => { + if (!res.writableEnded) disconnected.abort(); + }; + res.once("close", onClose); + try { + const upstream = await fetch( + origin + + "/projects/" + + encodeURIComponent(project) + + "/" + + path + + (query.size ? "?" + query.toString() : ""), + { + method: req.method, + headers, + body: req.method === "GET" ? undefined : JSON.stringify(req.body || {}), + signal: AbortSignal.any([ + AbortSignal.timeout(15000), + disconnected.signal, + ]), + redirect: "manual", + }, + ); + const headersReceived = performance.now(); + const body = upstream.status === 204 ? null : await upstream.json(); + res.setHeader( + "Server-Timing", + `upstream;dur=${(headersReceived - started).toFixed(1)}, total;dur=${(performance.now() - started).toFixed(1)}`, + ); + const session = body?.access_token; + if (session) { + res.setHeader( + "Set-Cookie", + `foundry_session=${encodeURIComponent(session)}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${Math.min(body.expires_in || 28800, 28800)}${process.env.NODE_ENV === "production" && req.headers["x-forwarded-proto"] === "https" ? "; Secure" : ""}`, + ); + delete body.access_token; + } + if (path === "auth/logout" && upstream.ok) + res.setHeader( + "Set-Cookie", + "foundry_session=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0", + ); + if (upstream.status === 204) return res.status(204).end(); + return res + .status(upstream.status) + .json(body || { error: "upstream_unavailable" }); + } catch (error) { + if (res.destroyed) return; + res.setHeader( + "Server-Timing", + `total;dur=${(performance.now() - started).toFixed(1)}`, + ); + const timeout = error instanceof Error && error.name === "TimeoutError"; + return res + .status(timeout ? 504 : 502) + .json({ error: timeout ? "upstream_timeout" : "upstream_unavailable" }); + } finally { + res.off("close", onClose); + } +} +export const config = { api: { bodyParser: { sizeLimit: "1mb" } } }; diff --git a/src/pages/api/oauth/[provider].ts b/src/pages/api/oauth/[provider].ts new file mode 100644 index 0000000..49a503a --- /dev/null +++ b/src/pages/api/oauth/[provider].ts @@ -0,0 +1,26 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +export default function handler(req: NextApiRequest, res: NextApiResponse) { + const p = req.query.provider, + c = req.query.challenge; + if ( + req.method !== "GET" || + !["google", "slack"].includes(String(p)) || + typeof c !== "string" || + !/^[-_a-zA-Z0-9]{43}$/.test(c) + ) + return res.status(400).json({ error: "invalid_request" }); + const origin = + process.env.FOUNDRY_API_ORIGIN || "https://api.foundry.entroia.com"; + const project = process.env.NEXT_PUBLIC_FOUNDRY_PROJECT || "endoleap"; + res.setHeader("Cache-Control", "no-store"); + res.redirect( + 302, + origin + + "/projects/" + + encodeURIComponent(project) + + "/auth/" + + p + + "?challenge=" + + c, + ); +} diff --git a/src/pages/auth/callback.tsx b/src/pages/auth/callback.tsx new file mode 100644 index 0000000..b88e0c4 --- /dev/null +++ b/src/pages/auth/callback.tsx @@ -0,0 +1 @@ +export { default } from "../login"; diff --git a/src/pages/dashboard.tsx b/src/pages/dashboard.tsx new file mode 100644 index 0000000..f8ebeae --- /dev/null +++ b/src/pages/dashboard.tsx @@ -0,0 +1,934 @@ +import { useEffect, useRef, useState, type FormEvent } from "react"; +import { useRouter } from "next/router"; +import Link from "next/link"; +import { + ArrowUpRight, + Plus, + Search, + Folder, + FileText, + LayoutGrid, + LogOut, + ChevronDown, + PanelLeftClose, + PanelLeftOpen, + Check, + MoreHorizontal, + X, + ArrowLeft, + Sun, + Moon, +} from "lucide-react"; +import { Brand } from "@/components/brand"; +import { Icon } from "@/components/icon"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; +import { api, errorText, type Profile } from "@/lib/api"; +import { + createBoard, + loadWorkspaceHome, + type Workspace, +} from "@/lib/workspace"; +type Board = { + id: string; + title: string; + updated: string; + style: number; + text: string; +}; +const initialBoards: Board[] = [ + { + id: "morning", + title: "城市清晨", + updated: "刚刚", + style: 0, + text: "让阳光穿过叶片,落在安静的房间里。", + }, + { + id: "ideas", + title: "灵感收集", + updated: "昨天", + style: 1, + text: "把一闪而过的念头,留给下一次创作。", + }, + { + id: "journey", + title: "下一站,去哪里", + updated: "2 天前", + style: 2, + text: "为一段还未开始的旅程,收集一些可能。", + }, +]; +export default function Dashboard() { + const router = useRouter(); + const demo = router.query.demo === "1"; + const mutationVersion = useRef(0); + const [boardsLoading, setBoardsLoading] = useState(false); + const [spacesLoaded, setSpacesLoaded] = useState(false); + const [ready, setReady] = useState(false), + [profile, setProfile] = useState(null), + [workspaces, setWorkspaces] = useState([]), + [workspace, setWorkspace] = useState(""), + [boards, setBoards] = useState([]), + [query, setQuery] = useState(""), + [view, setView] = useState("全部文件"), + [canvas, setCanvas] = useState(null), + [sidebar, setSidebar] = useState(true), + [dialog, setDialog] = useState<"board" | "workspace" | null>(null), + [title, setTitle] = useState(""), + [error, setError] = useState(""), + [busy, setBusy] = useState(false), + [workspaceMenu, setWorkspaceMenu] = useState(false), + [notice, setNotice] = useState(""), + [dark, setDark] = useState(false), + [checked, setChecked] = useState(false), + [zoom, setZoom] = useState(100), + [nodeText, setNodeText] = useState(""), + [note, setNote] = useState(""); + useEffect(() => { + if (!router.isReady) return; + let active = true; + if (demo) { + setProfile({ + id: "demo", + username: "creator", + display_name: "创作者", + email: null, + }); + setWorkspaces([{ id: "demo", name: "个人空间" }]); + setWorkspace("demo"); + setSpacesLoaded(true); + let stored: Board[] | null = null; + try { + stored = JSON.parse( + localStorage.getItem("endoleap_demo_boards_demo") || "null", + ); + } catch {} + setBoards(stored || initialBoards); + setReady(true); + return; + } + const controller = new AbortController(); + loadWorkspaceHome(api, controller.signal) + .then(({ profile, workspaces: list }) => { + if (!active) return; + setProfile(profile); + setWorkspaces(list); + setSpacesLoaded(true); + setWorkspace(list[0]?.id || ""); + setReady(true); + }) + .catch((e) => { + if (!active) return; + if (e.message === "invalid_session") router.replace("/login"); + else { + setError(errorText(e)); + setReady(true); + } + }); + return () => { + active = false; + controller.abort(); + }; + }, [router.isReady, demo, router]); + useEffect(() => { + if (demo && ready) + localStorage.setItem( + "endoleap_demo_boards_" + workspace, + JSON.stringify(boards), + ); + }, [boards, demo, ready, workspace]); + useEffect(() => { + if (!workspace || demo) { + setBoardsLoading(false); + return; + } + let active = true; + const controller = new AbortController(); + const version = mutationVersion.current; + setBoardsLoading(true); + setBoards([]); + api<{ items: { id: string; title: string }[] }>( + "workspaces/" + + workspace + + "/materials?kind=board&sort=modified&limit=100", + { signal: controller.signal }, + ) + .then((r) => { + if (active && version === mutationVersion.current) + setBoards( + r.items.map((b, i) => ({ + id: b.id, + title: b.title, + updated: "最近", + style: i % 3, + text: "", + })), + ); + }) + .catch((e) => { + if (active) setError(errorText(e)); + }) + .finally(() => { + if (active) setBoardsLoading(false); + }); + return () => { + active = false; + controller.abort(); + }; + }, [workspace, demo]); + useEffect(() => { + if (notice) { + const timer = setTimeout(() => setNotice(""), 3500); + return () => clearTimeout(timer); + } + }, [notice]); + async function create(e: FormEvent) { + e.preventDefault(); + if (!title.trim()) return; + setBusy(true); + setError(""); + try { + if (dialog === "workspace") { + const w = demo + ? { id: crypto.randomUUID(), name: title.trim() } + : await api("workspaces", { + method: "POST", + body: JSON.stringify({ name: title.trim() }), + }); + setWorkspaces([...workspaces, w]); + setWorkspace(w.id); + setBoards([]); + } else { + if (!workspace && !spacesLoaded) + throw new Error("workspace_not_loaded"); + const id = demo + ? crypto.randomUUID() + : ( + await createBoard(api, title, workspace, (w) => { + setWorkspaces((previous) => + previous.some((x) => x.id === w.id) + ? previous + : [...previous, w], + ); + setWorkspace(w.id); + }) + ).id; + mutationVersion.current += 1; + setBoards((previous) => [ + { + id, + title: title.trim(), + updated: "刚刚", + style: boards.length % 3, + text: "一张空白画布,等待你的第一个念头。", + }, + ...previous, + ]); + } + setDialog(null); + setTitle(""); + setNotice("已创建"); + } catch (e) { + setError(errorText(e)); + } finally { + setBusy(false); + } + } + async function logout() { + try { + if (!demo) await api("auth/logout", { method: "POST" }); + await router.push("/login"); + } catch (e) { + setError(errorText(e)); + } + } + function open(b: Board) { + setCanvas(b); + setNote(b.text); + setNodeText(""); + if (!demo) setNotice("当前为画布界面预览;服务端已保存画布名称。"); + } + function saveNote() { + if (!canvas) return; + if (demo) { + setBoards( + boards.map((b) => (b.id === canvas.id ? { ...b, text: note } : b)), + ); + setNotice("已保存到当前浏览器"); + } else setNotice("画布文字编辑将在布局接口接入后保存。"); + } + const names = + workspaces.find((w) => w.id === workspace)?.name || "创建你的空间"; + const filtered = boards.filter((b) => + b.title.toLowerCase().includes(query.toLowerCase()), + ); + if (!ready) + return ( +
+ +

正在打开你的创作空间…

+
+ ); + return ( +
+ + {sidebar && ( + + )} +
+
+ + {names} + / + {canvas ? canvas.title : "工作台"} +
+ {demo && ( + + 本地演示 · 内容保存在此浏览器{" "} + + + )} + +
+
+ {error && ( +
+ {error} + +
+ )} + {canvas ? ( +
+
+ + {canvas.title} + 已打开 +
+
+ + {zoom}% + + +
+
+
+ 灵感片段 +

+ 把日常, +
+ 拍成一场电影。 +

+ 一闪而过的想法。 +
+
+
+ 镜头研究 子画布 · 740 × 600 +
+
+

清晨光线

+