diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bb6ad9f..78596a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,18 +1,5 @@ # Contributing to Oreo Badge -
-` in a new tab β the badge's own
+upload page picks up the prefill and continues the gated handshake
+from there. End-to-end bytes never leave the local network.
diff --git a/oreo.elixpo/next-env.d.ts b/oreo.elixpo/next-env.d.ts
new file mode 100644
index 0000000..830fb59
--- /dev/null
+++ b/oreo.elixpo/next-env.d.ts
@@ -0,0 +1,6 @@
+///
+///
+///
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/oreo.elixpo/next.config.mjs b/oreo.elixpo/next.config.mjs
new file mode 100644
index 0000000..7c2f1d3
--- /dev/null
+++ b/oreo.elixpo/next.config.mjs
@@ -0,0 +1,20 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ // Static export β Cloudflare Pages serves the resulting /out directory
+ // as a plain CDN-fronted site. Keeps the deployment story to two
+ // commands (`next build` + `wrangler pages deploy out`) and lets us
+ // skip the Workers runtime entirely. The cost is no server-rendered
+ // routes; the file-transfer page does its work entirely client-side
+ // against the badge's local HTTP server, so that's fine.
+ output: "export",
+ // Image optimisation requires a server runtime β disable so the
+ // static export contains the original asset bytes.
+ images: {
+ unoptimized: true,
+ },
+ // Trailing slashes on every URL so Cloudflare Pages serves the
+ // matching `path/index.html` even without rewrite rules.
+ trailingSlash: true,
+};
+
+export default nextConfig;
diff --git a/oreo.elixpo/package-lock.json b/oreo.elixpo/package-lock.json
new file mode 100644
index 0000000..fedbdd0
--- /dev/null
+++ b/oreo.elixpo/package-lock.json
@@ -0,0 +1,3738 @@
+{
+ "name": "oreo-elixpo",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "oreo-elixpo",
+ "version": "1.0.0",
+ "dependencies": {
+ "framer-motion": "^11.11.17",
+ "lucide-react": "^0.460.0",
+ "next": "^15.5.0",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/node": "^22.10.1",
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "autoprefixer": "^10.4.20",
+ "postcss": "^8.4.49",
+ "tailwindcss": "^3.4.16",
+ "typescript": "^5.7.2",
+ "wrangler": "^3.95.0"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@cloudflare/kv-asset-handler": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz",
+ "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "mime": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.13"
+ }
+ },
+ "node_modules/@cloudflare/unenv-preset": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.0.2.tgz",
+ "integrity": "sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "peerDependencies": {
+ "unenv": "2.0.0-rc.14",
+ "workerd": "^1.20250124.0"
+ },
+ "peerDependenciesMeta": {
+ "workerd": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@cloudflare/workerd-darwin-64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20250718.0.tgz",
+ "integrity": "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-darwin-arm64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20250718.0.tgz",
+ "integrity": "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-linux-64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20250718.0.tgz",
+ "integrity": "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-linux-arm64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20250718.0.tgz",
+ "integrity": "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cloudflare/workerd-windows-64": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20250718.0.tgz",
+ "integrity": "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@esbuild-plugins/node-globals-polyfill": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz",
+ "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==",
+ "dev": true,
+ "license": "ISC",
+ "peerDependencies": {
+ "esbuild": "*"
+ }
+ },
+ "node_modules/@esbuild-plugins/node-modules-polyfill": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz",
+ "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "escape-string-regexp": "^4.0.0",
+ "rollup-plugin-node-polyfills": "^0.2.1"
+ },
+ "peerDependencies": {
+ "esbuild": "*"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
+ "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
+ "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
+ "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
+ "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
+ "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
+ "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
+ "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
+ "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
+ "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
+ "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
+ "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
+ "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
+ "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
+ "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
+ "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
+ "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
+ "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
+ "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
+ "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
+ "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
+ "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@fastify/busboy": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
+ "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "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.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
+ "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
+ "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
+ "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
+ "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
+ "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
+ "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
+ "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
+ "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
+ "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
+ "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
+ "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "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.2.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
+ "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
+ "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
+ "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
+ "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
+ "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
+ "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
+ "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
+ "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
+ "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
+ "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.7.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
+ "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
+ "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
+ "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.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/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@next/env": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.18.tgz",
+ "integrity": "sha512-hAV85Ckd9QR6RvH04MEKwsfLTksvFpO47j9xwtoIuvuPnlwecpSi+uZTtm8HirVbtlI2Fnz//xpcSTjFdyJk+g==",
+ "license": "MIT"
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.18.tgz",
+ "integrity": "sha512-w0WvQf1n+txiwns/9pwIQteCJpZTbxzO2SE0FLcwuD4v0WEh1JPOjdyxWL21XwJsdpx8cFRjyzxzCS/siP7HcQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.18.tgz",
+ "integrity": "sha512-znn71QmDuxm+BOaglihMZfvyySMnNljkVIY5Z2TCssBmm+WqL6c19VhtH5ktFkHa8EZ2bnTUpcNcmNSQsg67og==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.18.tgz",
+ "integrity": "sha512-yPPe5MNL+igZUa+OsqQJisqSfh6oarIuA1Q0BDxljGJhRQyZeP+WRHh7rs/jZUGMh5aY0YdIjXZG0VohkKkUdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.18.tgz",
+ "integrity": "sha512-glaCczEWIrHsokFZ3pP08U4BpKxwIdnT+txdOM32OBgpL9Yw4aqx8NejmgtZQZOdstQ5f0L3CasIZudzCuD+nw==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.18.tgz",
+ "integrity": "sha512-oUfg2EgJmU3R0OCOWiokGFUTvZiPfXtriXiuF3YNxRoROCdgvTedHIzYoeKH34gsZxS/V7mHbfq2hpAHwhH1/A==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.18.tgz",
+ "integrity": "sha512-JLxSP3KTd9iu/bvUMQxH7RJo9xKSHf55/6RPE4a6FTSZygGn7uvZbCej0AHXydwkggQGSD9UddSjwv6Xz5ESfA==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.18.tgz",
+ "integrity": "sha512-ir1v7enP52K2HNz3tQQvwF+x7VNxBk1ciiZ18WBPvxf4C59IqdfmHPJYK3vH7rSxpuCVw/8C712wTXNAtEp+NA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "15.5.18",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.18.tgz",
+ "integrity": "sha512-LIu5me6QTANCd25E7I5uIEfvgQ06RK7tvHAbYo3zCb3VpxQEPvMcSpd87NwUABDT6MbGPdEGR5VRiK4PPTJhQg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.19.19",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz",
+ "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.14",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
+ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.14.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
+ "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/as-table": {
+ "version": "1.0.55",
+ "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz",
+ "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "printable-characters": "^1.0.42"
+ }
+ },
+ "node_modules/autoprefixer": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
+ "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.28.2",
+ "caniuse-lite": "^1.0.30001787",
+ "fraction.js": "^5.3.4",
+ "picocolors": "^1.1.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.31",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.31.tgz",
+ "integrity": "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/blake3-wasm": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
+ "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.12",
+ "caniuse-lite": "^1.0.30001782",
+ "electron-to-chromium": "^1.5.328",
+ "node-releases": "^2.0.36",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001793",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
+ "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
+ "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/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/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/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/commander": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz",
+ "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/defu": {
+ "version": "6.1.7",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
+ "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==",
+ "dev": 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==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.359",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.359.tgz",
+ "integrity": "sha512-8lPELWuYZIWk7NDvCNthtmMw/7Q5Wu25NpM4djFMHBmk8DubPAtL4YTOp7ou0e7HyJtwkVlWv8XMLURnrtgJQw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.17.19",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
+ "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.17.19",
+ "@esbuild/android-arm64": "0.17.19",
+ "@esbuild/android-x64": "0.17.19",
+ "@esbuild/darwin-arm64": "0.17.19",
+ "@esbuild/darwin-x64": "0.17.19",
+ "@esbuild/freebsd-arm64": "0.17.19",
+ "@esbuild/freebsd-x64": "0.17.19",
+ "@esbuild/linux-arm": "0.17.19",
+ "@esbuild/linux-arm64": "0.17.19",
+ "@esbuild/linux-ia32": "0.17.19",
+ "@esbuild/linux-loong64": "0.17.19",
+ "@esbuild/linux-mips64el": "0.17.19",
+ "@esbuild/linux-ppc64": "0.17.19",
+ "@esbuild/linux-riscv64": "0.17.19",
+ "@esbuild/linux-s390x": "0.17.19",
+ "@esbuild/linux-x64": "0.17.19",
+ "@esbuild/netbsd-x64": "0.17.19",
+ "@esbuild/openbsd-x64": "0.17.19",
+ "@esbuild/sunos-x64": "0.17.19",
+ "@esbuild/win32-arm64": "0.17.19",
+ "@esbuild/win32-ia32": "0.17.19",
+ "@esbuild/win32-x64": "0.17.19"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/exit-hook": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz",
+ "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/exsolve": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
+ "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fraction.js": {
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
+ "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/framer-motion": {
+ "version": "11.18.2",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz",
+ "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^11.18.1",
+ "motion-utils": "^11.18.1",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-source": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz",
+ "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==",
+ "dev": true,
+ "license": "Unlicense",
+ "dependencies": {
+ "data-uri-to-buffer": "^2.0.0",
+ "source-map": "^0.6.1"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/hasown": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
+ "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "1.21.7",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
+ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lucide-react": {
+ "version": "0.460.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.460.0.tgz",
+ "integrity": "sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
+ "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sourcemap-codec": "^1.4.8"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+ "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/miniflare": {
+ "version": "3.20250718.3",
+ "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20250718.3.tgz",
+ "integrity": "sha512-JuPrDJhwLrNLEJiNLWO7ZzJrv/Vv9kZuwMYCfv0LskQDM6Eonw4OvywO3CH/wCGjgHzha/qyjUh8JQ068TjDgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cspotcode/source-map-support": "0.8.1",
+ "acorn": "8.14.0",
+ "acorn-walk": "8.3.2",
+ "exit-hook": "2.2.1",
+ "glob-to-regexp": "0.4.1",
+ "stoppable": "1.1.0",
+ "undici": "^5.28.5",
+ "workerd": "1.20250718.0",
+ "ws": "8.18.0",
+ "youch": "3.3.4",
+ "zod": "3.22.3"
+ },
+ "bin": {
+ "miniflare": "bootstrap.js"
+ },
+ "engines": {
+ "node": ">=16.13"
+ }
+ },
+ "node_modules/motion-dom": {
+ "version": "11.18.1",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz",
+ "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^11.18.1"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "11.18.1",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz",
+ "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==",
+ "license": "MIT"
+ },
+ "node_modules/mustache": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+ "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mustache": "bin/mustache"
+ }
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+ "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": "15.5.18",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.5.18.tgz",
+ "integrity": "sha512-eKL8zUJkX9Y5lE+RX/2YJoItVdGlIscyVyboeD9wSpp0PaGqjoA4tTpT2qPqz9ax+5IzGESyLSeZ/RCwbSZ2uQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@next/env": "15.5.18",
+ "@swc/helpers": "0.5.15",
+ "caniuse-lite": "^1.0.30001579",
+ "postcss": "8.4.31",
+ "styled-jsx": "5.1.6"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "15.5.18",
+ "@next/swc-darwin-x64": "15.5.18",
+ "@next/swc-linux-arm64-gnu": "15.5.18",
+ "@next/swc-linux-arm64-musl": "15.5.18",
+ "@next/swc-linux-x64-gnu": "15.5.18",
+ "@next/swc-linux-x64-musl": "15.5.18",
+ "@next/swc-win32-arm64-msvc": "15.5.18",
+ "@next/swc-win32-x64-msvc": "15.5.18",
+ "sharp": "^0.34.3"
+ },
+ "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.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "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.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.44",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz",
+ "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/ohash": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/path-to-regexp": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
+ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
+ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+ "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.12",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
+ "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
+ "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "lilconfig": "^3.1.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "jiti": ">=1.21.0",
+ "postcss": ">=8.0.9",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "postcss-selector-parser": "^6.1.1"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/printable-characters": {
+ "version": "1.0.42",
+ "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz",
+ "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==",
+ "dev": true,
+ "license": "Unlicense"
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/react": {
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
+ "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.6",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
+ "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.6"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.12",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
+ "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup-plugin-inject": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz",
+ "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==",
+ "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "estree-walker": "^0.6.1",
+ "magic-string": "^0.25.3",
+ "rollup-pluginutils": "^2.8.1"
+ }
+ },
+ "node_modules/rollup-plugin-node-polyfills": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz",
+ "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "rollup-plugin-inject": "^3.0.0"
+ }
+ },
+ "node_modules/rollup-pluginutils": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+ "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "estree-walker": "^0.6.1"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
+ "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
+ "license": "ISC",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.34.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
+ "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/colour": "^1.0.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.7.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.34.5",
+ "@img/sharp-darwin-x64": "0.34.5",
+ "@img/sharp-libvips-darwin-arm64": "1.2.4",
+ "@img/sharp-libvips-darwin-x64": "1.2.4",
+ "@img/sharp-libvips-linux-arm": "1.2.4",
+ "@img/sharp-libvips-linux-arm64": "1.2.4",
+ "@img/sharp-libvips-linux-ppc64": "1.2.4",
+ "@img/sharp-libvips-linux-riscv64": "1.2.4",
+ "@img/sharp-libvips-linux-s390x": "1.2.4",
+ "@img/sharp-libvips-linux-x64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
+ "@img/sharp-linux-arm": "0.34.5",
+ "@img/sharp-linux-arm64": "0.34.5",
+ "@img/sharp-linux-ppc64": "0.34.5",
+ "@img/sharp-linux-riscv64": "0.34.5",
+ "@img/sharp-linux-s390x": "0.34.5",
+ "@img/sharp-linux-x64": "0.34.5",
+ "@img/sharp-linuxmusl-arm64": "0.34.5",
+ "@img/sharp-linuxmusl-x64": "0.34.5",
+ "@img/sharp-wasm32": "0.34.5",
+ "@img/sharp-win32-arm64": "0.34.5",
+ "@img/sharp-win32-ia32": "0.34.5",
+ "@img/sharp-win32-x64": "0.34.5"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "deprecated": "Please use @jridgewell/sourcemap-codec instead",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/stacktracey": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.2.0.tgz",
+ "integrity": "sha512-ETyQEz+CzXiLjEbyJqpbp+/T79RQD/6wqFucRBIlVNZfYq2Ay7wbretD4cxpbymZlaPWx58aIhPEY1Cr8DlVvg==",
+ "dev": true,
+ "license": "Unlicense",
+ "dependencies": {
+ "as-table": "^1.0.36",
+ "get-source": "^2.0.12"
+ }
+ },
+ "node_modules/stoppable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz",
+ "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4",
+ "npm": ">=6"
+ }
+ },
+ "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/sucrase": {
+ "version": "3.35.1",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
+ "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "tinyglobby": "^0.2.11",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.4.19",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
+ "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.6.0",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.3.2",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.21.7",
+ "lilconfig": "^3.1.3",
+ "micromatch": "^4.0.8",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.1.1",
+ "postcss": "^8.4.47",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0",
+ "postcss-nested": "^6.2.0",
+ "postcss-selector-parser": "^6.1.2",
+ "resolve": "^1.22.8",
+ "sucrase": "^3.35.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.16",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.6.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz",
+ "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/undici": {
+ "version": "5.29.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
+ "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@fastify/busboy": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unenv": {
+ "version": "2.0.0-rc.14",
+ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.14.tgz",
+ "integrity": "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "defu": "^6.1.4",
+ "exsolve": "^1.0.1",
+ "ohash": "^2.0.10",
+ "pathe": "^2.0.3",
+ "ufo": "^1.5.4"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/workerd": {
+ "version": "1.20250718.0",
+ "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20250718.0.tgz",
+ "integrity": "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "workerd": "bin/workerd"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "optionalDependencies": {
+ "@cloudflare/workerd-darwin-64": "1.20250718.0",
+ "@cloudflare/workerd-darwin-arm64": "1.20250718.0",
+ "@cloudflare/workerd-linux-64": "1.20250718.0",
+ "@cloudflare/workerd-linux-arm64": "1.20250718.0",
+ "@cloudflare/workerd-windows-64": "1.20250718.0"
+ }
+ },
+ "node_modules/wrangler": {
+ "version": "3.114.17",
+ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.114.17.tgz",
+ "integrity": "sha512-tAvf7ly+tB+zwwrmjsCyJ2pJnnc7SZhbnNwXbH+OIdVas3zTSmjcZOjmLKcGGptssAA3RyTKhcF9BvKZzMUycA==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@cloudflare/kv-asset-handler": "0.3.4",
+ "@cloudflare/unenv-preset": "2.0.2",
+ "@esbuild-plugins/node-globals-polyfill": "0.2.3",
+ "@esbuild-plugins/node-modules-polyfill": "0.2.2",
+ "blake3-wasm": "2.1.5",
+ "esbuild": "0.17.19",
+ "miniflare": "3.20250718.3",
+ "path-to-regexp": "6.3.0",
+ "unenv": "2.0.0-rc.14",
+ "workerd": "1.20250718.0"
+ },
+ "bin": {
+ "wrangler": "bin/wrangler.js",
+ "wrangler2": "bin/wrangler.js"
+ },
+ "engines": {
+ "node": ">=16.17.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2",
+ "sharp": "^0.33.5"
+ },
+ "peerDependencies": {
+ "@cloudflare/workers-types": "^4.20250408.0"
+ },
+ "peerDependenciesMeta": {
+ "@cloudflare/workers-types": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+ "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.0.4"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+ "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.0.4"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+ "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+ "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+ "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+ "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+ "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+ "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+ "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+ "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-linux-arm": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+ "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.0.5"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+ "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.0.4"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+ "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.0.4"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+ "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.0.4"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+ "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+ "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-wasm32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+ "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.2.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-win32-ia32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+ "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/@img/sharp-win32-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+ "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/wrangler/node_modules/sharp": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
+ "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.5",
+ "@img/sharp-darwin-x64": "0.33.5",
+ "@img/sharp-libvips-darwin-arm64": "1.0.4",
+ "@img/sharp-libvips-darwin-x64": "1.0.4",
+ "@img/sharp-libvips-linux-arm": "1.0.5",
+ "@img/sharp-libvips-linux-arm64": "1.0.4",
+ "@img/sharp-libvips-linux-s390x": "1.0.4",
+ "@img/sharp-libvips-linux-x64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
+ "@img/sharp-linux-arm": "0.33.5",
+ "@img/sharp-linux-arm64": "0.33.5",
+ "@img/sharp-linux-s390x": "0.33.5",
+ "@img/sharp-linux-x64": "0.33.5",
+ "@img/sharp-linuxmusl-arm64": "0.33.5",
+ "@img/sharp-linuxmusl-x64": "0.33.5",
+ "@img/sharp-wasm32": "0.33.5",
+ "@img/sharp-win32-ia32": "0.33.5",
+ "@img/sharp-win32-x64": "0.33.5"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/youch": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz",
+ "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^0.7.1",
+ "mustache": "^4.2.0",
+ "stacktracey": "^2.1.8"
+ }
+ },
+ "node_modules/zod": {
+ "version": "3.22.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz",
+ "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ }
+ }
+}
diff --git a/oreo.elixpo/package.json b/oreo.elixpo/package.json
new file mode 100644
index 0000000..7e926dd
--- /dev/null
+++ b/oreo.elixpo/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "oreo-elixpo",
+ "version": "1.0.0",
+ "private": true,
+ "description": "The Oreo Badge β marketing site, app catalogue, and gated file-transfer launcher.",
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint",
+ "deploy": "next build && wrangler pages deploy out --project-name=oreo"
+ },
+ "dependencies": {
+ "framer-motion": "^11.11.17",
+ "lucide-react": "^0.460.0",
+ "next": "^15.5.0",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@types/node": "^22.10.1",
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "autoprefixer": "^10.4.20",
+ "postcss": "^8.4.49",
+ "tailwindcss": "^3.4.16",
+ "typescript": "^5.7.2",
+ "wrangler": "^3.95.0"
+ }
+}
diff --git a/oreo.elixpo/plan.md b/oreo.elixpo/plan.md
new file mode 100644
index 0000000..df9c4b6
--- /dev/null
+++ b/oreo.elixpo/plan.md
@@ -0,0 +1,448 @@
+You are given a task to integrate an existing React component in the codebase
+
+The codebase should support:
+- shadcn project structure
+- Tailwind CSS
+- Typescript
+
+If it doesn't, provide instructions on how to setup project via shadcn CLI, install Tailwind or Typescript.
+
+Determine the default path for components and styles.
+If default path for components is not /components/ui, provide instructions on why it's important to create this folder
+Copy-paste this component to /components/ui folder:
+```tsx
+glowy-waves-hero-shadcnui.tsx
+import { motion, type Variants } from "framer-motion";
+import { ArrowRight, Sparkles } from "lucide-react";
+import { useEffect, useRef } from "react";
+
+import { Button } from "@/components/ui/button";
+
+type Point = {
+ x: number;
+ y: number;
+};
+
+interface WaveConfig {
+ offset: number;
+ amplitude: number;
+ frequency: number;
+ color: string;
+ opacity: number;
+}
+
+const highlightPills = [
+ "Immersive visuals",
+ "Responsive motion",
+ "GPU friendly",
+] as const;
+
+const heroStats: { label: string; value: string }[] = [
+ { label: "Live installations", value: "320+" },
+ { label: "Latency", value: "8ms" },
+ { label: "Teams onboarded", value: "120+" },
+];
+
+const containerVariants: Variants = {
+ hidden: { opacity: 0, y: 24 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.8, staggerChildren: 0.12 },
+ },
+};
+
+const itemVariants: Variants = {
+ hidden: { opacity: 0, y: 24 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.6, ease: "easeOut" },
+ },
+};
+
+const statsVariants: Variants = {
+ hidden: { opacity: 0, scale: 0.95 },
+ visible: {
+ opacity: 1,
+ scale: 1,
+ transition: { duration: 0.6, ease: "easeOut", staggerChildren: 0.08 },
+ },
+};
+
+export function GlowyWavesHero() {
+ const canvasRef = useRef(null);
+ const mouseRef = useRef({ x: 0, y: 0 });
+ const targetMouseRef = useRef({ x: 0, y: 0 });
+
+ useEffect(() => {
+ const canvas = canvasRef.current;
+ if (!canvas) return undefined;
+
+ const ctx = canvas.getContext("2d");
+ if (!ctx) return undefined;
+
+ let animationId: number;
+ let time = 0;
+
+ const computeThemeColors = () => {
+ const rootStyles = getComputedStyle(document.documentElement);
+
+ // Helper to convert any CSS color to a Canvas-compatible format
+ const resolveColor = (variables: string[], alpha = 1) => {
+ // Create a temporary element to get computed color
+ const tempEl = document.createElement("div");
+ tempEl.style.position = "absolute";
+ tempEl.style.visibility = "hidden";
+ tempEl.style.width = "1px";
+ tempEl.style.height = "1px";
+ document.body.appendChild(tempEl);
+
+ let color = `rgba(255, 255, 255, ${alpha})`;
+
+ for (const variable of variables) {
+ const value = rootStyles.getPropertyValue(variable).trim();
+ if (value) {
+ // Try to set the background color using the CSS variable
+ tempEl.style.backgroundColor = `var(${variable})`;
+ const computedColor = getComputedStyle(tempEl).backgroundColor;
+
+ if (computedColor && computedColor !== "rgba(0, 0, 0, 0)") {
+ // Convert RGB to RGBA with alpha if needed
+ if (alpha < 1) {
+ const rgbMatch = computedColor.match(
+ /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/
+ );
+ if (rgbMatch) {
+ color = `rgba(${rgbMatch[1]}, ${rgbMatch[2]}, ${rgbMatch[3]}, ${alpha})`;
+ } else {
+ color = computedColor;
+ }
+ } else {
+ color = computedColor;
+ }
+ break;
+ }
+ }
+ }
+
+ document.body.removeChild(tempEl);
+ return color;
+ };
+
+ return {
+ backgroundTop: resolveColor(["--background"], 1),
+ backgroundBottom: resolveColor(["--muted", "--background"], 0.95),
+ wavePalette: [
+ {
+ offset: 0,
+ amplitude: 70,
+ frequency: 0.003,
+ color: resolveColor(["--primary"], 0.8),
+ opacity: 0.45,
+ },
+ {
+ offset: Math.PI / 2,
+ amplitude: 90,
+ frequency: 0.0026,
+ color: resolveColor(["--accent", "--primary"], 0.7),
+ opacity: 0.35,
+ },
+ {
+ offset: Math.PI,
+ amplitude: 60,
+ frequency: 0.0034,
+ color: resolveColor(["--secondary", "--foreground"], 0.65),
+ opacity: 0.3,
+ },
+ {
+ offset: Math.PI * 1.5,
+ amplitude: 80,
+ frequency: 0.0022,
+ color: resolveColor(["--primary-foreground", "--foreground"], 0.25),
+ opacity: 0.25,
+ },
+ {
+ offset: Math.PI * 2,
+ amplitude: 55,
+ frequency: 0.004,
+ color: resolveColor(["--foreground"], 0.2),
+ opacity: 0.2,
+ },
+ ] satisfies WaveConfig[],
+ };
+ };
+
+ let themeColors = computeThemeColors();
+
+ const handleThemeMutation = () => {
+ themeColors = computeThemeColors();
+ };
+
+ const observer = new MutationObserver(handleThemeMutation);
+ observer.observe(document.documentElement, {
+ attributes: true,
+ attributeFilter: ["class", "data-theme"],
+ });
+
+ const prefersReducedMotion = window.matchMedia(
+ "(prefers-reduced-motion: reduce)"
+ ).matches;
+
+ const mouseInfluence = prefersReducedMotion ? 10 : 70;
+ const influenceRadius = prefersReducedMotion ? 160 : 320;
+ const smoothing = prefersReducedMotion ? 0.04 : 0.1;
+
+ const resizeCanvas = () => {
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ };
+
+ const recenterMouse = () => {
+ const centerPoint = { x: canvas.width / 2, y: canvas.height / 2 };
+ mouseRef.current = centerPoint;
+ targetMouseRef.current = centerPoint;
+ };
+
+ const handleResize = () => {
+ resizeCanvas();
+ recenterMouse();
+ };
+
+ const handleMouseMove = (event: MouseEvent) => {
+ targetMouseRef.current = { x: event.clientX, y: event.clientY };
+ };
+
+ const handleMouseLeave = () => {
+ recenterMouse();
+ };
+
+ resizeCanvas();
+ recenterMouse();
+
+ window.addEventListener("resize", handleResize);
+ window.addEventListener("mousemove", handleMouseMove);
+ window.addEventListener("mouseleave", handleMouseLeave);
+
+ const drawWave = (wave: WaveConfig) => {
+ ctx.save();
+ ctx.beginPath();
+
+ for (let x = 0; x <= canvas.width; x += 4) {
+ const dx = x - mouseRef.current.x;
+ const dy = canvas.height / 2 - mouseRef.current.y;
+ const distance = Math.sqrt(dx * dx + dy * dy);
+ const influence = Math.max(0, 1 - distance / influenceRadius);
+ const mouseEffect =
+ influence *
+ mouseInfluence *
+ Math.sin(time * 0.001 + x * 0.01 + wave.offset);
+
+ const y =
+ canvas.height / 2 +
+ Math.sin(x * wave.frequency + time * 0.002 + wave.offset) *
+ wave.amplitude +
+ Math.sin(x * wave.frequency * 0.4 + time * 0.003) *
+ (wave.amplitude * 0.45) +
+ mouseEffect;
+
+ if (x === 0) {
+ ctx.moveTo(x, y);
+ } else {
+ ctx.lineTo(x, y);
+ }
+ }
+
+ ctx.lineWidth = 2.5;
+ ctx.strokeStyle = wave.color;
+ ctx.globalAlpha = wave.opacity;
+ ctx.shadowBlur = 35;
+ ctx.shadowColor = wave.color;
+ ctx.stroke();
+
+ ctx.restore();
+ };
+
+ const animate = () => {
+ time += 1;
+
+ mouseRef.current.x +=
+ (targetMouseRef.current.x - mouseRef.current.x) * smoothing;
+ mouseRef.current.y +=
+ (targetMouseRef.current.y - mouseRef.current.y) * smoothing;
+
+ const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
+ gradient.addColorStop(0, themeColors.backgroundTop);
+ gradient.addColorStop(1, themeColors.backgroundBottom);
+
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ ctx.globalAlpha = 1;
+ ctx.shadowBlur = 0;
+
+ themeColors.wavePalette.forEach(drawWave);
+
+ animationId = window.requestAnimationFrame(animate);
+ };
+
+ animationId = window.requestAnimationFrame(animate);
+
+ return () => {
+ window.removeEventListener("resize", handleResize);
+ window.removeEventListener("mousemove", handleMouseMove);
+ window.removeEventListener("mouseleave", handleMouseLeave);
+ cancelAnimationFrame(animationId);
+ observer.disconnect();
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reactive canvas hero
+
+
+
+ Welcome to immersive{" "}
+
+ realtime playgrounds
+
+
+
+
+ Build living surfaces that respond to every interaction. Craft
+ cinematic hero moments, responsive canvases, and luminous gradients
+ without leaving your design system.
+
+
+
+
+
+
+
+
+ {highlightPills.map((pill) => (
+
+ {pill}
+
+ ))}
+
+
+
+ {heroStats.map((stat) => (
+
+
+ {stat.label}
+
+
+ {stat.value}
+
+
+ ))}
+
+
+
+
+ );
+}
+
+
+demo.tsx
+import { GlowyWavesHero } from "@/components/ui/glowy-waves-hero-shadcnui"
+
+export default function Demo() {
+ return (
+
+
+
+ )
+}
+
+```
+
+Install NPM dependencies:
+```bash
+lucide-react, framer-motion
+```
+
+Implementation Guidelines
+ 1. Analyze the component structure and identify all required dependencies
+ 2. Review the component's argumens and state
+ 3. Identify any required context providers or hooks and install them
+ 4. Questions to Ask
+ - What data/props will be passed to this component?
+ - Are there any specific state management requirements?
+ - Are there any required assets (images, icons, etc.)?
+ - What is the expected responsive behavior?
+ - What is the best place to use this component in the app?
+
+Steps to integrate
+ 0. Copy paste all the code above in the correct directories
+ 1. Install external dependencies
+ 2. Fill image assets with Unsplash stock images you know exist
+ 3. Use lucide-react icons for svgs or logos if component requires them
diff --git a/oreo.elixpo/postcss.config.js b/oreo.elixpo/postcss.config.js
new file mode 100644
index 0000000..12a703d
--- /dev/null
+++ b/oreo.elixpo/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
diff --git a/oreo.elixpo/public/CONTRIBUTING.md b/oreo.elixpo/public/CONTRIBUTING.md
new file mode 100644
index 0000000..78596a4
--- /dev/null
+++ b/oreo.elixpo/public/CONTRIBUTING.md
@@ -0,0 +1,215 @@
+# Contributing to Oreo Badge
+
+## Quick map
+
+- **π Bug?** β open an issue with the badge model, firmware version
+ (`Settings β Version`), and a one-line description.
+- **π¨ New app?** β see [Writing an app](#writing-an-app) below.
+- **π§ Driver / OS change?** β see [Hacking on the OS](#hacking-on-the-os).
+- **π¦ Release / OTA?** β see [Releasing](#releasing).
+- **π§βπ€βπ§ Conduct?** β see [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md).
+
+---
+
+## Setup
+
+```bash
+git clone https://github.com/elixpo/oreo
+cd oreo
+python -m venv .venv && source .venv/bin/activate
+pip install -r oreoOS/requirements.txt
+```
+
+You don't strictly need a real badge to develop most apps β running the
+CPython importers locally catches the majority of issues. But the real
+test is always on hardware. If you don't have a badge, ping
+**hello@elixpo.com** and we'll see what we can do.
+
+---
+
+## Writing an app
+
+The fastest path to a working app:
+
+```bash
+cp -r templates/example_app apps/my_app
+# edit apps/my_app/main.py β three methods is the whole API
+python tools/deploy.py /dev/ttyACM0
+```
+
+**Default-installed vs Market apps.** Where you put the folder decides
+how the app reaches the user:
+
+| Path | Behaviour |
+|---|---|
+| `apps//` | **Default-installed.** Tile appears in the drawer on every fresh deploy. Use for core OS tools + apps every badge owner should have |
+| `apps_market//` | **Opt-in.** Ships in the catalogue but isn't in the drawer until the user installs from the on-device **App Market** tile. Use for games, sketches, hackathon entries, themed extras |
+
+The two trees have **identical shape** β `main.py + manifest.json +
+__init__.py + assets/`. `tools/deploy.py` walks both and ships them to
+the matching path on the device. The Market app calls into
+[`oreoOS.store`](oreoOS/store.py) which `cp -r`s a folder between the
+two trees on install / uninstall.
+
+When in doubt, ship to `apps_market/` β flash and drawer real estate
+are precious, and the install flow is one tap away.
+
+**The contract.** Your app subclasses `oreoOS.App` and implements three
+lifecycle methods:
+
+```python
+class App(oreoOS.App):
+ name = "My App"
+
+ def on_enter(self, os):
+ # one-shot setup. load sprites, restore state, calibrate sensors.
+
+ def update(self, dt):
+ # per-frame logic. dt is seconds since last frame.
+
+ def draw(self, d):
+ # per-frame render. d is the framebuffer. don't call d.present().
+```
+
+Optional hooks: `on_exit`, `on_button_press(btn)`,
+`on_button_release(btn)`, `on_home_press()` (returns True to suppress
+the default HOME-to-drawer behaviour).
+
+**Class attributes you can set:**
+
+- `name` β what appears on the launcher tile + loading screen
+- `SHOW_LOADING` β `True` if `on_enter` takes > 200 ms
+- `BLOCK_IDLE` β `True` for apps that should keep the screen on
+ even without button presses (games, IR scanner)
+
+**Where things live:**
+
+```
+apps/my_app/
+βββ __init__.py empty marker
+βββ main.py your App class
+βββ manifest.json name + version + icon + author
+βββ assets/
+ βββ raw/ source images you commit
+ βββ optimized/ baked RGB565 .py modules
+```
+
+To bake assets: drop a PNG/JPG into `assets/raw/`, run
+`python tools/optimize_assets.py --app my_app`, commit the result.
+
+The `theme` module is the source of truth for colours. If you find
+yourself reaching for `api.rgb(...)` directly, ask whether there's a
+themed constant that fits.
+
+---
+
+## Hacking on the OS
+
+The OS lives in two packages:
+
+- `oreoOS/` β pure Python: launcher, splash, theme, widgets, app base
+ class, OTA client, cache, power manager, etc.
+- `oreoWare/` β hardware drivers: display, buttons, WiFi, BT, IMU, IR,
+ battery, touch. **Everything is funnelled through `oreoWare/pins.py`**
+ so a PCB pin swap only touches that file.
+
+**Conventions worth knowing:**
+
+- One source of truth for pins, one for colours, one for VERSION.
+- Apps that read network data should cache to disk with a TTL via
+ `oreoOS.cache`. See `apps/badge/main.py` for the pattern.
+- The framebuf is RGB565 big-endian. Use `api.rgb(r, g, b)` to pack β
+ don't construct the integer by hand.
+- Anything that might block (network, heavy compute) should either be
+ short-timeout-bounded OR set `SHOW_LOADING = True` so the user sees a
+ panel during `on_enter`.
+
+---
+
+## Pull requests
+
+1. **Branch off main.** Name it something descriptive
+ (`feature/ir-quest-leaderboard`, not `patch-1`).
+2. **Run the deploy** locally to make sure the OS still boots. If your
+ change touches drivers, test wake-from-sleep, OTA, and at least two
+ apps you didn't write.
+3. **One PR, one purpose.** Don't bundle a bug-fix with a rename, and
+ don't fold a 4-file refactor into a typo PR.
+4. **Title format:** `[scope] short description`, e.g.
+ `[ota] fix peek() to handle malformed manifest`.
+5. **Tag a maintainer** in the PR description so we see it. Right now
+ that's [@Circuit-Overtime](https://github.com/Circuit-Overtime).
+
+We try to respond within a week. If we haven't, please nudge β the
+notification probably got lost in conference-season chaos.
+
+---
+
+## Releasing
+
+Maintainers only β feel free to skip this section.
+
+Releases are **manual on purpose**. We want a human to look at a badge
+running the release candidate before the wider fleet pulls it in.
+
+**Before tagging:** add the new version's section to the top of
+[`CHANGELOG.md`](CHANGELOG.md). The CI release workflow takes the
+**top section** of that file verbatim and posts it as the GitHub
+release's `body` β which is what the badge's **Updates** screen shows
+as the in-device changelog when an upgrade is found. Keep entries
+short, bullet-style, present tense.
+
+The one-liner:
+
+```bash
+# Dry-run first so you can read every command the script will execute.
+python tools/release.py v1.4.0 --channel stable --dry-run
+
+# Looks good? Drop --dry-run and ship.
+python tools/release.py v1.4.0 --channel stable --notes "Fly mode + new pet sprites"
+```
+
+Under the hood the script:
+
+1. Verifies `git` + `gh` are installed and you're authenticated.
+2. Refuses to release if the working tree is dirty (override with `--force`).
+3. Bumps `oreoOS/config.py:VERSION` to `v1.4.0` if it isn't already.
+4. Commits the bump and pushes `main` + the new tag (`stable/v1.4.0`).
+5. Runs `tools/build_release.py` to produce
+ `dist/v1.4.0/{manifest.json, bundle.tar, files/...}`.
+6. Calls `gh release create` to publish, uploading every file as a
+ per-asset attachment so the manifest's per-file URLs resolve.
+
+A few minutes later every badge in the field with WiFi will see the
+SHA-based check find the new version within 6 h, and **Settings β
+Check Update** will pull it down on demand.
+
+For a **beta** channel: `python tools/release.py v1.4.0-rc1 --channel beta`.
+Badges only pick up the channel they're configured for (`stable` by
+default).
+
+If you don't have a dev machine handy: the GitHub Actions
+[`release` workflow](.github/workflows/release.yml) does the same thing
+when you click **Run workflow** in the Actions tab β same script under
+the hood, no auto-trigger on tag push.
+
+---
+
+## Project values
+
+- **Friendly is feature.** A confusing-but-correct UI is a bug.
+- **Readable comments beat clever code.** This project is meant to be
+ hackable; if something would surprise a first-time reader, comment it.
+- **Hardware is a teammate, not a constraint.** Lean on the chip's
+ strengths. Don't fight the LDO.
+- **Ship small, ship often.** The OTA pipeline is there so we can.
+
+---
+
+## Contact
+
+- **Email:** hello@elixpo.com
+- **GitHub:** https://github.com/elixpo/oreo
+- **Maintainer:** [@Circuit-Overtime](https://github.com/Circuit-Overtime)
+
+Thanks for being here. πΌ
diff --git a/oreo.elixpo/public/favicon.png b/oreo.elixpo/public/favicon.png
new file mode 100644
index 0000000..2fc6344
Binary files /dev/null and b/oreo.elixpo/public/favicon.png differ
diff --git a/oreo.elixpo/public/icons/IR_Quest_icon.png b/oreo.elixpo/public/icons/IR_Quest_icon.png
new file mode 100644
index 0000000..41516b8
Binary files /dev/null and b/oreo.elixpo/public/icons/IR_Quest_icon.png differ
diff --git a/oreo.elixpo/public/icons/about_icon.png b/oreo.elixpo/public/icons/about_icon.png
new file mode 100644
index 0000000..bef6c80
Binary files /dev/null and b/oreo.elixpo/public/icons/about_icon.png differ
diff --git a/oreo.elixpo/public/icons/apps_icon.png b/oreo.elixpo/public/icons/apps_icon.png
new file mode 100644
index 0000000..85aa4b9
Binary files /dev/null and b/oreo.elixpo/public/icons/apps_icon.png differ
diff --git a/oreo.elixpo/public/icons/badge_icon.png b/oreo.elixpo/public/icons/badge_icon.png
new file mode 100644
index 0000000..6937866
Binary files /dev/null and b/oreo.elixpo/public/icons/badge_icon.png differ
diff --git a/oreo.elixpo/public/icons/bluetooth_icon.png b/oreo.elixpo/public/icons/bluetooth_icon.png
new file mode 100644
index 0000000..f3e66de
Binary files /dev/null and b/oreo.elixpo/public/icons/bluetooth_icon.png differ
diff --git a/oreo.elixpo/public/icons/cat_games.png b/oreo.elixpo/public/icons/cat_games.png
new file mode 100644
index 0000000..bc6aaa5
Binary files /dev/null and b/oreo.elixpo/public/icons/cat_games.png differ
diff --git a/oreo.elixpo/public/icons/cat_github.png b/oreo.elixpo/public/icons/cat_github.png
new file mode 100644
index 0000000..4c0f1df
Binary files /dev/null and b/oreo.elixpo/public/icons/cat_github.png differ
diff --git a/oreo.elixpo/public/icons/cat_system.png b/oreo.elixpo/public/icons/cat_system.png
new file mode 100644
index 0000000..a863a72
Binary files /dev/null and b/oreo.elixpo/public/icons/cat_system.png differ
diff --git a/oreo.elixpo/public/icons/cat_tools.png b/oreo.elixpo/public/icons/cat_tools.png
new file mode 100644
index 0000000..99e05e3
Binary files /dev/null and b/oreo.elixpo/public/icons/cat_tools.png differ
diff --git a/oreo.elixpo/public/icons/cat_utils.png b/oreo.elixpo/public/icons/cat_utils.png
new file mode 100644
index 0000000..d9343f2
Binary files /dev/null and b/oreo.elixpo/public/icons/cat_utils.png differ
diff --git a/oreo.elixpo/public/icons/color_icon.png b/oreo.elixpo/public/icons/color_icon.png
new file mode 100644
index 0000000..f356b8d
Binary files /dev/null and b/oreo.elixpo/public/icons/color_icon.png differ
diff --git a/oreo.elixpo/public/icons/commits_breaker_icon.png b/oreo.elixpo/public/icons/commits_breaker_icon.png
new file mode 100644
index 0000000..41007b4
Binary files /dev/null and b/oreo.elixpo/public/icons/commits_breaker_icon.png differ
diff --git a/oreo.elixpo/public/icons/commits_icon.png b/oreo.elixpo/public/icons/commits_icon.png
new file mode 100644
index 0000000..36a5e3d
Binary files /dev/null and b/oreo.elixpo/public/icons/commits_icon.png differ
diff --git a/oreo.elixpo/public/icons/elixpo_pet_icon.png b/oreo.elixpo/public/icons/elixpo_pet_icon.png
new file mode 100644
index 0000000..e461260
Binary files /dev/null and b/oreo.elixpo/public/icons/elixpo_pet_icon.png differ
diff --git a/oreo.elixpo/public/icons/elixpo_sketch_icon.png b/oreo.elixpo/public/icons/elixpo_sketch_icon.png
new file mode 100644
index 0000000..fee4870
Binary files /dev/null and b/oreo.elixpo/public/icons/elixpo_sketch_icon.png differ
diff --git a/oreo.elixpo/public/icons/flappy_icon.png b/oreo.elixpo/public/icons/flappy_icon.png
new file mode 100644
index 0000000..1e6721c
Binary files /dev/null and b/oreo.elixpo/public/icons/flappy_icon.png differ
diff --git a/oreo.elixpo/public/icons/gallery_icon.png b/oreo.elixpo/public/icons/gallery_icon.png
new file mode 100644
index 0000000..e5aa48a
Binary files /dev/null and b/oreo.elixpo/public/icons/gallery_icon.png differ
diff --git a/oreo.elixpo/public/icons/gamepad_icon.png b/oreo.elixpo/public/icons/gamepad_icon.png
new file mode 100644
index 0000000..131306e
Binary files /dev/null and b/oreo.elixpo/public/icons/gamepad_icon.png differ
diff --git a/oreo.elixpo/public/icons/home_bg.png b/oreo.elixpo/public/icons/home_bg.png
new file mode 100644
index 0000000..1d0edad
Binary files /dev/null and b/oreo.elixpo/public/icons/home_bg.png differ
diff --git a/oreo.elixpo/public/icons/identity_icon.png b/oreo.elixpo/public/icons/identity_icon.png
new file mode 100644
index 0000000..c98c601
Binary files /dev/null and b/oreo.elixpo/public/icons/identity_icon.png differ
diff --git a/oreo.elixpo/public/icons/notifications_icon.png b/oreo.elixpo/public/icons/notifications_icon.png
new file mode 100644
index 0000000..135d78f
Binary files /dev/null and b/oreo.elixpo/public/icons/notifications_icon.png differ
diff --git a/oreo.elixpo/public/icons/racer_icon.png b/oreo.elixpo/public/icons/racer_icon.png
new file mode 100644
index 0000000..b3c396b
Binary files /dev/null and b/oreo.elixpo/public/icons/racer_icon.png differ
diff --git a/oreo.elixpo/public/icons/reader_icon.png b/oreo.elixpo/public/icons/reader_icon.png
new file mode 100644
index 0000000..f5c8de9
Binary files /dev/null and b/oreo.elixpo/public/icons/reader_icon.png differ
diff --git a/oreo.elixpo/public/icons/settings_icon.png b/oreo.elixpo/public/icons/settings_icon.png
new file mode 100644
index 0000000..b9054b4
Binary files /dev/null and b/oreo.elixpo/public/icons/settings_icon.png differ
diff --git a/oreo.elixpo/public/icons/snake_icon.png b/oreo.elixpo/public/icons/snake_icon.png
new file mode 100644
index 0000000..652cf77
Binary files /dev/null and b/oreo.elixpo/public/icons/snake_icon.png differ
diff --git a/oreo.elixpo/public/icons/storage_icon.png b/oreo.elixpo/public/icons/storage_icon.png
new file mode 100644
index 0000000..2bab4f3
Binary files /dev/null and b/oreo.elixpo/public/icons/storage_icon.png differ
diff --git a/oreo.elixpo/public/icons/store_icon.png b/oreo.elixpo/public/icons/store_icon.png
new file mode 100644
index 0000000..2e0f6ca
Binary files /dev/null and b/oreo.elixpo/public/icons/store_icon.png differ
diff --git a/oreo.elixpo/public/icons/wallpaper_icon.png b/oreo.elixpo/public/icons/wallpaper_icon.png
new file mode 100644
index 0000000..0e3078d
Binary files /dev/null and b/oreo.elixpo/public/icons/wallpaper_icon.png differ
diff --git a/oreo.elixpo/public/icons/wifi_icon.png b/oreo.elixpo/public/icons/wifi_icon.png
new file mode 100644
index 0000000..fd617e6
Binary files /dev/null and b/oreo.elixpo/public/icons/wifi_icon.png differ
diff --git a/oreo.elixpo/public/mascot.png b/oreo.elixpo/public/mascot.png
new file mode 100644
index 0000000..c5a64cc
Binary files /dev/null and b/oreo.elixpo/public/mascot.png differ
diff --git a/oreo.elixpo/src/app/apps/[slug]/_components/DetailIcon.tsx b/oreo.elixpo/src/app/apps/[slug]/_components/DetailIcon.tsx
new file mode 100644
index 0000000..b532334
--- /dev/null
+++ b/oreo.elixpo/src/app/apps/[slug]/_components/DetailIcon.tsx
@@ -0,0 +1,45 @@
+"use client";
+
+import { useState } from "react";
+import { motion } from "framer-motion";
+import type { AppEntry } from "@/data/apps";
+
+/* Big hero icon for the detail route. Renders the real PNG with a
+ * subtle scale-in + pixelated rendering so the badge artwork stays
+ * crisp at 128 px. Wrapped in a client boundary because we want the
+ * graceful fallback (Lucide isn't loaded here intentionally β if the
+ * PNG fails we just show the first letter, keeping the bundle thin). */
+
+export default function DetailIcon({
+ app, tintRing,
+}: {
+ app: AppEntry;
+ tintRing: string;
+}) {
+ const [pngOk, setPngOk] = useState(true);
+ return (
+
+ {app.pngIcon && pngOk ? (
+ // eslint-disable-next-line @next/next/no-img-element
+
setPngOk(false)}
+ className="h-full w-full object-contain"
+ style={{ imageRendering: "pixelated" }}
+ />
+ ) : (
+
+ {app.name[0]?.toUpperCase()}
+
+ )}
+
+ );
+}
diff --git a/oreo.elixpo/src/app/apps/[slug]/page.tsx b/oreo.elixpo/src/app/apps/[slug]/page.tsx
new file mode 100644
index 0000000..d09fa5d
--- /dev/null
+++ b/oreo.elixpo/src/app/apps/[slug]/page.tsx
@@ -0,0 +1,281 @@
+import type { Metadata } from "next";
+import { notFound } from "next/navigation";
+import Link from "next/link";
+import {
+ ArrowLeft, Github, Tag, User, FileJson, Hash, Layers, ArrowRight,
+} from "lucide-react";
+import { ALL_CATALOG, findApp, type AppEntry } from "@/data/apps";
+import DetailIcon from "./_components/DetailIcon";
+
+/* /apps/[slug]/ β per-app detail route.
+ *
+ * Static export means we need every reachable URL pre-generated at
+ * build time. `generateStaticParams` returns one entry per app in
+ * `ALL_CATALOG`; the build emits an HTML file for each, so Cloudflare
+ * Pages can serve them as plain static assets β no runtime params.
+ *
+ * The page itself is a server component (no `use client`) because all
+ * its data is build-time-known. The hero "blurred logo" backdrop is
+ * pure CSS, no canvas, so the route loads instantly with zero JS
+ * cost. The header / footer animations still come along via the root
+ * layout.
+ */
+
+// `dynamicParams = false` locks the route to the slugs we declare β
+// any other URL 404s instead of trying to render at request time.
+// Required for `output: "export"` to know what to pre-render.
+export const dynamicParams = false;
+
+export async function generateStaticParams() {
+ return ALL_CATALOG.map((a) => ({ slug: a.urlSlug }));
+}
+
+// Next 15 made `params` async β it's now a Promise that must be
+// awaited before its fields can be read. The shape is otherwise
+// unchanged. This was the single most common Next 14 β 15 migration
+// gotcha; flagged here so future edits don't drop the await.
+type RouteParams = Promise<{ slug: string }>;
+
+export async function generateMetadata({
+ params,
+}: {
+ params: RouteParams;
+}): Promise {
+ const { slug } = await params;
+ const app = findApp(slug);
+ if (!app) return { title: "Not found" };
+ return {
+ title: `${app.name} Β· Oreo`,
+ description: app.blurb,
+ openGraph: {
+ title: `${app.name} Β· Oreo`,
+ description: app.blurb,
+ images: app.pngIcon ? [{ url: app.pngIcon }] : undefined,
+ },
+ };
+}
+
+const TINT_BG: Record = {
+ primary: "rgba(255, 93, 104, 0.22)",
+ teal: "rgba( 61, 220, 151, 0.20)",
+ gold: "rgba(255, 209, 102, 0.20)",
+ lilac: "rgba(162, 155, 254, 0.22)",
+};
+const TINT_TEXT: Record = {
+ primary: "text-primary",
+ teal: "text-teal",
+ gold: "text-gold",
+ lilac: "text-lilac",
+};
+const TINT_RING: Record = {
+ primary: "ring-primary/50",
+ teal: "ring-teal/50",
+ gold: "ring-gold/50",
+ lilac: "ring-lilac/50",
+};
+
+export default async function AppDetail({
+ params,
+}: {
+ params: RouteParams;
+}) {
+ const { slug } = await params;
+ const app = findApp(slug);
+ if (!app) notFound();
+
+ // Pick a few "related" apps in the same category for the bottom
+ // strip. Keep the original ordering so it's deterministic across
+ // builds (no Math.random).
+ const related = ALL_CATALOG
+ .filter((a) => a.urlSlug !== app.urlSlug && a.category === app.category)
+ .slice(0, 3);
+
+ const bgUrl = app.pngIcon ?? "";
+
+ return (
+
+ {/* ββ BLURRED LOGO BACKDROP βββββββββββββββββββββββββββββββββββββ
+ Two stacked layers:
+ 1. The PNG icon itself, scaled up and heavily blurred β the
+ "out-of-focus poster" feel.
+ 2. A tinted gradient overlay using the app's brand colour
+ to keep the page readable and on-theme.
+ Both layers are pointer-events-none so they never intercept
+ taps on the content above. */}
+ {bgUrl && (
+
+ )}
+
+
+ {/* Back link */}
+
+ All apps
+
+
+ {/* ββ HERO βββββββββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+
+
+
+ {app.name}
+
+
+
+ {app.category}
+ Β·
+ v{app.version}
+
+
+
+ {app.blurb}
+
+
+
+ {/* ββ META GRID ββββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+ } label="Author" value={app.author!} />
+ } label="Version" value={"v" + app.version} />
+ } label="Category" value={app.category} />
+ } label="Path" value={`apps/${app.slug}/`} mono />
+
+
+ {/* ββ ABOUT ββββββββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+
+ About
+
+ {(app.details ?? app.blurb).split("\n\n").map((p, i) => (
+ {p}
+ ))}
+
+
+
+
+ {/* ββ ACTION BAR βββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+
+ {/* ββ RELATED ββββββββββββββββββββββββββββββββββββββββββββββββββ */}
+ {related.length > 0 && (
+
+
+ More in {app.category}
+
+
+ {related.map((r) => (
+
+
+
+
+ {r.name}
+
+ {r.blurb}
+
+
+
+ ))}
+
+
+ )}
+
+
+ );
+}
+
+function Meta({
+ icon, label, value, mono = false,
+}: {
+ icon: React.ReactNode;
+ label: string;
+ value: string;
+ mono?: boolean;
+}) {
+ return (
+
+
+ {icon} {label}
+
+
+ {value}
+
+
+ );
+}
+
+function RelatedIcon({ app }: { app: AppEntry }) {
+ return (
+
+ {app.pngIcon ? (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ ) : (
+ {app.name[0]}
+ )}
+
+ );
+}
diff --git a/oreo.elixpo/src/app/apps/page.tsx b/oreo.elixpo/src/app/apps/page.tsx
new file mode 100644
index 0000000..3721ee7
--- /dev/null
+++ b/oreo.elixpo/src/app/apps/page.tsx
@@ -0,0 +1,104 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { Reveal, staggerContainer, fadeUp } from "@/components/MotionWrap";
+import AppCard from "@/components/AppCard";
+import { PRELOADED, ALL_APPS, STORE } from "@/data/apps";
+
+export default function AppsPage() {
+ return (
+
+ {/* Ambient glows so the page feels like part of the brand. */}
+
+
+
+
+
+
+ {/* Centred header */}
+
+
+ {ALL_APPS.length + STORE.length} apps and counting
+
+
+ Everything that ships,
+
+
+ and everything that streams in.
+
+
+
+ The preloaded set lands on the badge at flash time. The store
+ pulls fresh apps from GitHub at runtime β no laptop, no
+ recompile, no developer mode toggle.
+
+
+
+ {/* Preloaded β centred */}
+
+
+ Preloaded
+
+ Shipped with v1. Edit or remove any of them locally.
+
+
+
+
+ {PRELOADED.map((a, i) => )}
+
+
+ {/* Full catalogue */}
+
+
+ More on the badge
+
+ Settings, tools, and games sit one drawer-tap away.
+
+
+
+
+ {ALL_APPS.filter(a => !PRELOADED.find(p => p.slug === a.slug))
+ .map((a, i) => )}
+
+
+ {/* Store */}
+
+
+ From the store
+
+ Community apps installable at runtime from{" "}
+ apps_market/ on the repo.
+
+
+
+
+ {STORE.map((a, i) => )}
+
+
+
+
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/app/badge/page.tsx b/oreo.elixpo/src/app/badge/page.tsx
new file mode 100644
index 0000000..7b6318b
--- /dev/null
+++ b/oreo.elixpo/src/app/badge/page.tsx
@@ -0,0 +1,176 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { Reveal, fadeUp, staggerContainer } from "@/components/MotionWrap";
+import BadgeMockup from "@/components/BadgeMockup";
+import {
+ Cpu, MemoryStick, Battery, Radio, Usb, Layers,
+ Layout, Ruler, Github,
+} from "lucide-react";
+
+const SPECS = [
+ { Icon: Cpu, k: "MCU", v: "ESP32-S3 dual core @ 240 MHz" },
+ { Icon: MemoryStick, k: "Memory", v: "16 MB flash Β· 8 MB PSRAM" },
+ { Icon: Radio, k: "Radio", v: "WiFi 2.4 GHz Β· BLE 5 Β· IR transceiver" },
+ { Icon: Layout, k: "Display", v: "ST7789 240Γ320 IPS Β· portrait" },
+ { Icon: Battery, k: "Power", v: "USB-C + LiPo deep-sleep Β· ~5 Β΅A standby" },
+ { Icon: Usb, k: "I/O", v: "8-button matrix Β· IMU Β· 1-wire IR Β· IΒ²C bus" },
+ { Icon: Ruler, k: "Dimensions", v: "55 Γ 90 mm portrait PCB" },
+ { Icon: Layers, k: "Layers", v: "4-layer FR-4 Β· 1.6 mm Β· ENIG finish" },
+];
+
+const STACK = [
+ { lvl: "apps/", body: "Userland β manifest.json + main.py per app.",
+ tint: "from-primary/30 to-primary/5" },
+ { lvl: "oreoOS/", body: "The OS: launcher, store, OTA, notifications, file transfer.",
+ tint: "from-lilac/30 to-lilac/5" },
+ { lvl: "oreoWare/", body: "HAL / Board Support: drivers for screen, buttons, IMU, BLE, WiFi, IR, battery.",
+ tint: "from-teal/30 to-teal/5" },
+ { lvl: "MicroPython", body: "Runtime β we credit it loudly; we did not write it.",
+ tint: "from-gold/30 to-gold/5" },
+];
+
+export default function BadgePage() {
+ return (
+
+ {/* Soft brand glows */}
+
+
+
+
+
+
+
+ {/* ββ HERO: copy left, mockup right βββββββββββββββββββββββββββββ */}
+
+
+
+ ESP32-S3-DevKitC Β· breadboard phase
+
+
+ The hardware,{" "}
+
+ all open.
+
+
+
+ Tufty-classic portrait layout. Eight buttons, IR for line-of-sight
+ quests, an MPU6050 for shake and tilt, four LEDs around the frame.
+ Schematics and BOM live on the repo β fork them and roll your own.
+
+
+
+ Schematics + BOM
+
+
+ Repo
+
+
+
+
+
+
+
+
+
+ {/* ββ SCHEMATICS CALLOUT ββββββββββββββββββββββββββββββββββββββββ */}
+
+
+
+
+
+
+
+ Full schematics
+
+ KiCad project (4-layer FR-4, ENIG finish), Gerbers, and a
+ full BOM with substitutions live in docs/hardware/.
+ PCB v1 fab files coming soon.
+
+
+ Coming soon
+
+
+
+
+
+
+ {/* ββ SPEC GRID ββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+ {SPECS.map((s, i) => (
+
+
+
+
+
+ {s.k}
+ {s.v}
+
+
+ ))}
+
+
+ {/* ββ LAYERED ARCHITECTURE ββββββββββββββββββββββββββββββββββ */}
+
+
+
+ Layered architecture
+
+
+ Four layers, each can be rewritten without the others noticing.
+
+
+
+
+
+ {STACK.map((row, i) => (
+
+
+ {row.lvl}
+
+ L{STACK.length - i}
+
+
+ {row.body}
+
+ ))}
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/app/contribute/page.tsx b/oreo.elixpo/src/app/contribute/page.tsx
new file mode 100644
index 0000000..bb38223
--- /dev/null
+++ b/oreo.elixpo/src/app/contribute/page.tsx
@@ -0,0 +1,121 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { Reveal, fadeUp, staggerContainer } from "@/components/MotionWrap";
+import MarkdownView from "@/components/MarkdownView";
+import {
+ GitPullRequest, Bug, BookOpen, Code2, Heart, ExternalLink,
+} from "lucide-react";
+
+const TRACKS = [
+ { Icon: Code2, title: "Write an app",
+ body: "manifest.json + main.py and you're in the drawer. Look at apps/snake/ or apps/badge/ for ~50-line templates.",
+ href: "https://github.com/elixpo/oreo/blob/main/CONTRIBUTING.md#building-an-app",
+ tint: "text-primary" as const },
+ { Icon: Bug, title: "Fix a bug",
+ body: "Open issues are labelled by area (os / store / ota / wifi / bt). 'good first issue' tags exist; pair them with a serial log.",
+ href: "https://github.com/elixpo/oreo/issues",
+ tint: "text-teal" as const },
+ { Icon: BookOpen, title: "Write a hack",
+ body: "Drop Markdown into docs/hacks/ β we feature it on /hacks the next deploy.",
+ href: "https://github.com/elixpo/oreo/tree/main/docs/hacks",
+ tint: "text-gold" as const },
+ { Icon: GitPullRequest, title: "Improve the OS",
+ body: "Performance, polish, new services. Big changes β open a draft PR early so we can review the shape.",
+ href: "https://github.com/elixpo/oreo/tree/main/oreoOS",
+ tint: "text-lilac" as const },
+];
+
+export default function ContributePage() {
+ return (
+
+ {/* Soft glows so the page reads as part of the brand even
+ without the canvas hero. */}
+
+
+
+
+
+
+
+
+ made by humans, with humans
+
+
+ Contribute to Oreo.{" "}
+
+ Bring snacks.
+
+
+
+ OreoOS is open: code, hardware, prompts, assets, the lot.
+ Pick a lane β or invent one. We merge fast and credit loudly.
+
+
+
+ {/* Contribution tracks */}
+
+ {TRACKS.map((t, i) => (
+
+
+
+
+
+ {t.title}
+ {t.body}
+
+ Open
+
+
+
+ ))}
+
+
+ {/* CONTRIBUTING.md β fetched from /public at runtime and rendered
+ through a tiny inline markdown formatter. The file is also a
+ real on-disk asset at /CONTRIBUTING.md if a contributor wants
+ the source. */}
+
+
+
+
+ The full contributing guide
+
+
+ view raw β
+
+
+
+ Mirrored verbatim from the repo's CONTRIBUTING.md. Edits to
+ the source on GitHub re-deploy here automatically.
+
+
+
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/app/get-started/page.tsx b/oreo.elixpo/src/app/get-started/page.tsx
new file mode 100644
index 0000000..a513a9b
--- /dev/null
+++ b/oreo.elixpo/src/app/get-started/page.tsx
@@ -0,0 +1,114 @@
+"use client";
+
+import Link from "next/link";
+import { motion } from "framer-motion";
+import { Reveal, fadeUp, staggerContainer } from "@/components/MotionWrap";
+import { Download, Terminal, Usb, Github } from "lucide-react";
+
+const STEPS = [
+ { n: "01", t: "Flash MicroPython", b: "Download the ESP32-S3 build, hold the BOOT button, flash via esptool. Two-minute job." },
+ { n: "02", t: "Clone the OS", b: "`git clone https://github.com/elixpo/oreo` and copy `.env.example` β `.env` with your WiFi credentials." },
+ { n: "03", t: "Deploy", b: "`python tools/deploy.py` β pushes everything over USB, skips unchanged files, bumps the version." },
+ { n: "04", t: "Open the badge", b: "Drawer β Settings β WiFi β Send files. Cloudflare-served `/upload` works from any phone on the same WiFi." },
+];
+
+export default function GetStartedPage() {
+ return (
+
+
+
+
+
+
+
+ ~15 minutes Β· USB-C + a computer
+
+ From box to badge,{" "}
+
+ in four steps.
+
+
+
+ The deploy script handles version bumps, hash-cache pruning,
+ free-space guards, and secrets generation. You hold the BOOT
+ button, you wait, you tap A.
+
+
+
+
+
+ {STEPS.map((s, i) => (
+
+
+ {s.n}
+
+ {s.t}
+ {s.b}
+
+
+
+ ))}
+
+
+
+
+
+ } title="MicroPython firmware"
+ body="ESP32-S3 build matching your flash size."
+ href="https://micropython.org/download/ESP32_GENERIC_S3/" />
+ } title="mpremote"
+ body="Talks to the badge over USB serial."
+ href="https://docs.micropython.org/en/latest/reference/mpremote.html" />
+ } title="Repo"
+ body="Source, schematics, CHANGELOG."
+ href="https://github.com/elixpo/oreo" />
+
+
+
+
+
+ Need help?
+
+ Open an issue with your serial-console log
+ (mpremote connect /dev/ttyACM0 repl) β
+ the project's print breadcrumbs make most boot failures
+ diagnosable in one round trip.
+
+
+
+
+
+ );
+}
+
+function CTA({ icon, title, body, href }: { icon: React.ReactNode; title: string; body: string; href: string }) {
+ return (
+
+
+ {icon}
+
+
+ {title}
+ {body}
+
+
+ );
+}
diff --git a/oreo.elixpo/src/app/globals.css b/oreo.elixpo/src/app/globals.css
new file mode 100644
index 0000000..488651d
--- /dev/null
+++ b/oreo.elixpo/src/app/globals.css
@@ -0,0 +1,133 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* ββ Design tokens βββββββββββββββββββββββββββββββββββββββββββββββββββ
+ *
+ * Two parallel naming schemes coexist on the site:
+ *
+ * β’ Brand tokens (`bg`, `card`, `primary` β¦) β declared in
+ * theme.js, re-exported via tailwind.config.ts, used by everything
+ * we wrote by hand.
+ *
+ * β’ shadcn-style semantic tokens (`--background`, `--foreground`,
+ * `--primary`, `--border` β¦) β needed by the canvas-wave hero
+ * and any drop-in shadcn component we add later. They're populated
+ * from the same brand palette so visually they always agree.
+ *
+ * Adding a new colour: update theme.js first, then mirror into the
+ * shadcn variable here if a third-party component needs it.
+ */
+:root {
+ color-scheme: dark;
+ --font-display: "Pixelify Sans", "JetBrains Mono", ui-sans-serif, system-ui,
+ sans-serif;
+
+ /* shadcn-compatible semantic tokens (kept in oklch-adjacent hex
+ so we can paste in shadcn components without rewriting them) */
+ --background: #0F0C1C;
+ --foreground: #F5E6DC;
+ --card: #1C1A2E;
+ --card-foreground: #F5E6DC;
+ --popover: #1F1B33;
+ --popover-foreground: #F5E6DC;
+ --primary: #FF5D68;
+ --primary-foreground: #0F0C1C;
+ --secondary: #A29BFE;
+ --secondary-foreground: #0F0C1C;
+ --muted: #1F1B33;
+ --muted-foreground: #8A8294;
+ --accent: #3DDC97;
+ --accent-foreground: #0F0C1C;
+ --destructive: #FF5D68;
+ --destructive-foreground:#0F0C1C;
+ --border: #2A2640;
+ --input: #2A2640;
+ --ring: #FF5D68;
+ --radius: 0.65rem;
+}
+
+html, body {
+ background: var(--background);
+ color: var(--foreground);
+ font-family: theme("fontFamily.sans");
+ font-feature-settings: "ss01" 1, "ss02" 1, "cv11" 1;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+}
+
+/* Subtle ambient gradient layer β sits behind everything so the page
+ feels alive even before any component animates. Kept very faint so
+ it never fights real content. */
+body::before {
+ content: "";
+ position: fixed;
+ inset: 0;
+ background:
+ radial-gradient(60% 50% at 25% 15%, rgba(255, 93, 104, 0.10), transparent 60%),
+ radial-gradient(50% 45% at 80% 90%, rgba(162, 155, 254, 0.08), transparent 60%),
+ radial-gradient(40% 35% at 90% 10%, rgba(61, 220, 151, 0.06), transparent 60%);
+ pointer-events: none;
+ z-index: -1;
+}
+
+::selection {
+ background: theme("colors.primary");
+ color: theme("colors.bg");
+}
+
+/* ββ Reusable components βββββββββββββββββββββββββββββββββββββββββββ */
+@layer components {
+ .container-page {
+ @apply mx-auto w-full max-w-6xl px-6 sm:px-8;
+ }
+ .btn-primary {
+ @apply inline-flex items-center gap-2 rounded-md bg-primary px-5 py-2.5
+ font-semibold text-bg transition-colors hover:bg-primary-dim;
+ }
+ .btn-ghost {
+ @apply inline-flex items-center gap-2 rounded-md border border-border
+ px-5 py-2.5 text-text transition-colors hover:bg-card;
+ }
+ .chip {
+ @apply inline-flex items-center gap-1.5 rounded-pill bg-card-sub px-2.5 py-1
+ text-xs uppercase tracking-wider text-text-dim;
+ }
+ .card-surface {
+ @apply rounded-lg border border-border bg-card transition-colors;
+ }
+ /* Conic-gradient border treatment used on hero CTAs and accent
+ cards β produces a thin animated luminous edge. Pairs with the
+ wave hero for visual continuity. */
+ .ring-glow {
+ position: relative;
+ isolation: isolate;
+ }
+ .ring-glow::before {
+ content: "";
+ position: absolute;
+ inset: -1px;
+ border-radius: inherit;
+ padding: 1px;
+ background: conic-gradient(
+ from var(--ring-angle, 0deg),
+ theme("colors.primary"),
+ theme("colors.lilac"),
+ theme("colors.teal"),
+ theme("colors.primary")
+ );
+ -webkit-mask:
+ linear-gradient(#000 0 0) content-box,
+ linear-gradient(#000 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+ pointer-events: none;
+ opacity: 0.7;
+ animation: spin 8s linear infinite;
+ }
+ @keyframes spin {
+ to { --ring-angle: 360deg; transform: rotate(360deg); }
+ }
+}
+
+html { overscroll-behavior: none; }
diff --git a/oreo.elixpo/src/app/hacks/page.tsx b/oreo.elixpo/src/app/hacks/page.tsx
new file mode 100644
index 0000000..9e36a8a
--- /dev/null
+++ b/oreo.elixpo/src/app/hacks/page.tsx
@@ -0,0 +1,149 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { Reveal, fadeUp, staggerContainer } from "@/components/MotionWrap";
+import { Clock, Wrench, ExternalLink } from "lucide-react";
+
+type Hack = {
+ slug: string;
+ title: string;
+ body: string;
+ difficulty: "beginner" | "intermediate" | "advanced";
+ mins: number;
+ href: string;
+};
+
+const HACKS: Hack[] = [
+ { slug: "github-handle", title: "Set Your GitHub Handle",
+ body: "Edit secrets.py so the badge app pulls your live GitHub profile stats.",
+ difficulty: "beginner", mins: 5,
+ href: "https://github.com/elixpo/oreo/blob/main/docs/hacks/github-handle.md" },
+ { slug: "gallery-photo", title: "Add Your Photo to Gallery",
+ body: "Drop a PNG into apps/gallery/assets/raw/, deploy, watch it land in the carousel.",
+ difficulty: "beginner", mins: 8,
+ href: "https://github.com/elixpo/oreo/blob/main/docs/hacks/gallery-photo.md" },
+ { slug: "commits-brick", title: "Add the Commits Brick-Breaker",
+ body: "Install the Commits arcade so you can bat merge balls through a wall of green squares.",
+ difficulty: "beginner", mins: 15,
+ href: "https://github.com/elixpo/oreo/blob/main/docs/hacks/commits-brick.md" },
+ { slug: "custom-theme", title: "Theme the OS in your colours",
+ body: "Edit oreoOS/theme.py to retint the whole UI in a single commit.",
+ difficulty: "beginner", mins: 10,
+ href: "https://github.com/elixpo/oreo/blob/main/docs/hacks/custom-theme.md" },
+ { slug: "ir-quest", title: "Build an IR-Quest beacon",
+ body: "Wire a TSOP38 to a spare ESP and beam tokens to nearby badges.",
+ difficulty: "intermediate", mins: 30,
+ href: "https://github.com/elixpo/oreo/blob/main/docs/hacks/ir-quest.md" },
+ { slug: "imu-tilt", title: "Tilt-to-scroll any app",
+ body: "Pull the MPU6050 accel readings into your update() and remap UP/DOWN.",
+ difficulty: "intermediate", mins: 25,
+ href: "https://github.com/elixpo/oreo/blob/main/docs/hacks/imu-tilt.md" },
+ { slug: "custom-app", title: "Ship your first app",
+ body: "manifest.json + main.py β 30 lines, lands in the drawer.",
+ difficulty: "intermediate", mins: 45,
+ href: "https://github.com/elixpo/oreo/blob/main/CONTRIBUTING.md#building-an-app" },
+ { slug: "ota-self-host", title: "Self-host OTA updates",
+ body: "Point the OTA module at your own GitHub fork β ship private builds to your badge.",
+ difficulty: "advanced", mins: 60,
+ href: "https://github.com/elixpo/oreo/blob/main/docs/hacks/ota-fork.md" },
+ { slug: "pcb-design", title: "Spin a PCB",
+ body: "Use the KiCad project in /docs/hardware/ as a starting point for a v2 board.",
+ difficulty: "advanced", mins: 240,
+ href: "https://github.com/elixpo/oreo/tree/main/docs/hardware" },
+];
+
+const DIFF_TINT = {
+ beginner: { bg: "bg-teal/10", text: "text-teal", border: "border-teal/30" },
+ intermediate: { bg: "bg-gold/10", text: "text-gold", border: "border-gold/30" },
+ advanced: { bg: "bg-lilac/10", text: "text-lilac", border: "border-lilac/30" },
+};
+
+export default function HacksPage() {
+ return (
+
+
+
+
+
+
+
+
+
+ open hardware, open invitation
+
+
+ Customize Your Badge.{" "}
+
+ Make it weird.
+
+
+
+ Step-by-step recipes for retinting the OS, writing your first
+ app, or wiring extra sensors. Each hack is one Markdown file
+ on the repo β copy, paste, deploy.
+
+
+
+
+ {HACKS.map((h, i) => {
+ const t = DIFF_TINT[h.difficulty];
+ return (
+
+
+ {h.title}
+
+ {h.difficulty}
+
+
+ {h.body}
+
+
+
+ {h.mins < 60 ? `${h.mins} min` : `${Math.round(h.mins / 60)} h`}
+
+
+ Try this hack
+
+
+
+ );
+ })}
+
+
+
+
+ Got an idea for a hack?
+
+ Write it up as Markdown, drop it in docs/hacks/,
+ send a PR. We'll surface it here.
+
+
+ Open hacks folder on GitHub
+
+
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/app/layout.tsx b/oreo.elixpo/src/app/layout.tsx
new file mode 100644
index 0000000..69bf92a
--- /dev/null
+++ b/oreo.elixpo/src/app/layout.tsx
@@ -0,0 +1,98 @@
+import type { Metadata, Viewport } from "next";
+import "./globals.css";
+import Header from "@/components/Header";
+import Footer from "@/components/Footer";
+import PageTransition from "@/components/PageTransition";
+
+// SEO + social-card metadata. The og-banner.png referenced here is the
+// same artwork used as the README banner on the main repo β generated
+// from `prompts/site_assets.md` and dropped into /public/og-banner.png.
+// Keeping a single image for both surfaces means a contributor only
+// has to refresh one file when the brand shifts.
+
+const SITE_TITLE = "OreoOS β a Python OS in a pocket-sized badge";
+const SITE_DESCRIPTION =
+ "Open hardware. Open firmware. 20+ apps, on-device store, OTA over " +
+ "WiFi, AirDrop-style file transfer. MicroPython on ESP32-S3.";
+const SITE_URL = "https://oreo.elixpo.com";
+const OG_IMAGE = "/og-banner.png";
+
+export const metadata: Metadata = {
+ metadataBase: new URL(SITE_URL),
+ title: {
+ default: SITE_TITLE,
+ template: "%s Β· Oreo",
+ },
+ description: SITE_DESCRIPTION,
+ applicationName: "OreoOS",
+ authors: [{ name: "Elixpo", url: "https://github.com/elixpo" }],
+ generator: "Next.js",
+ keywords: [
+ "OreoOS", "Elixpo Badge", "conference badge", "MicroPython",
+ "ESP32-S3", "open hardware", "open source OS", "app store",
+ "file transfer", "BLE", "WiFi", "IR quest",
+ ],
+ // Per-route titles override `default` via Next's metadata API;
+ // robots gets allow-everywhere here because the site is fully public.
+ robots: {
+ index: true, follow: true,
+ googleBot: { index: true, follow: true, "max-image-preview": "large" },
+ },
+ openGraph: {
+ title: SITE_TITLE,
+ description: SITE_DESCRIPTION,
+ url: SITE_URL,
+ siteName: "Oreo",
+ type: "website",
+ locale: "en_US",
+ images: [{
+ url: OG_IMAGE,
+ width: 1200,
+ height: 630,
+ alt: "Oreo Badge β a Python OS in a pocket-sized conference badge",
+ }],
+ },
+ twitter: {
+ card: "summary_large_image",
+ title: SITE_TITLE,
+ description: SITE_DESCRIPTION,
+ images: [OG_IMAGE],
+ },
+ // Icons β pulled from the same mascot.png the header + footer use,
+ // so the favicon/apple-touch-icon look identical to the in-page
+ // wordmark. Pixel-art works at every favicon size; Cloudflare Pages
+ // serves the file verbatim from /public.
+ icons: {
+ icon: [{ url: "/favicon.png", type: "image/png" }],
+ shortcut: "/favicon.png",
+ apple: "/favicon.png",
+ },
+ formatDetection: { telephone: false, email: false, address: false },
+};
+
+// Next 14 moved themeColor / colorScheme out of `metadata` into a
+// separate `viewport` export β they're per-render rather than static.
+export const viewport: Viewport = {
+ themeColor: "#0F0C1C",
+ colorScheme: "dark",
+ width: "device-width",
+ initialScale: 1,
+};
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/app/not-found.tsx b/oreo.elixpo/src/app/not-found.tsx
new file mode 100644
index 0000000..fce5789
--- /dev/null
+++ b/oreo.elixpo/src/app/not-found.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+import Link from "next/link";
+import { motion } from "framer-motion";
+import { Home, Github, Compass } from "lucide-react";
+
+/* 404 β uses the same wave gradient palette as the hero so a misroute
+ * still feels like part of the product. No canvas here because we want
+ * the page to be as cheap to render as possible (some misrouted bots
+ * will hammer it). */
+
+export default function NotFound() {
+ return (
+
+ {/* Soft gradient glows behind the content */}
+
+
+
+
+
+
+
+ 404 / not found
+
+
+
+ Off the map.
+
+
+
+ The route you tapped doesn't exist on this build of the site.
+ Maybe it's an IR-Quest beacon hidden in a different timeline β
+ or maybe a typo. Head back home and we'll forget this ever
+ happened.
+
+
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/app/page.tsx b/oreo.elixpo/src/app/page.tsx
new file mode 100644
index 0000000..bdabc6c
--- /dev/null
+++ b/oreo.elixpo/src/app/page.tsx
@@ -0,0 +1,132 @@
+import Link from "next/link";
+import { Cpu, Wifi, Bluetooth, Code2 } from "lucide-react";
+import { Reveal } from "@/components/MotionWrap";
+import AppCard from "@/components/AppCard";
+import WavesHero from "@/components/WavesHero";
+import { PRELOADED } from "@/data/apps";
+
+const FEATURES = [
+ {
+ Icon: Cpu,
+ title: "Python all the way down",
+ body:
+ "MicroPython on ESP32-S3. Apps are a manifest.json + main.py β write one in ~30 lines and it shows up in the drawer.",
+ },
+ {
+ Icon: Wifi,
+ title: "AirDrop, the open-hardware way",
+ body:
+ "WiFi-based file transfer with on-badge approval. 6-digit code, beacon handshake, RGB565 conversion in the browser.",
+ },
+ {
+ Icon: Bluetooth,
+ title: "Peer presence (soon)",
+ body:
+ "BT will return for proximity-based features β IR-quest assists, sync gestures, badge-to-badge nudges.",
+ },
+];
+
+export default function Home() {
+ return (
+ <>
+ {/* ββ Reactive canvas hero βββββββββββββββββββββββββββββββββββββββ */}
+
+
+ {/* ββ FEATURE TRIO βββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+
+
+ Three things make the badge feel alive
+
+
+
+ {FEATURES.map((f, i) => (
+
+
+
+
+
+ {f.title}
+
+ {f.body}
+
+
+
+
+ ))}
+
+
+
+ {/* ββ APPS CAROUSEL ββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+
+
+
+
+ Preloaded apps
+
+
+ Ship with the badge. Customise or replace any of them.
+
+
+
+ All apps β
+
+
+
+
+
+ {PRELOADED.map((app, i) => (
+
+ ))}
+
+
+
+ {/* ββ CTA ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */}
+
+
+
+
+
+
+
+ Build your own apps.
+ It's a manifest and a main.py.
+
+
+ The badge ships with 20 first-party apps and an on-device store
+ that pulls from GitHub at runtime. Fork the repo, drop your app
+ in apps_market/
+ {" "}and submit a PR β the next person to refresh the store will see it.
+
+
+
+ Read the contributing guide
+
+
+ Setup the hardware
+
+
+
+
+
+ >
+ );
+}
diff --git a/oreo.elixpo/src/app/upload/page.tsx b/oreo.elixpo/src/app/upload/page.tsx
new file mode 100644
index 0000000..11058bc
--- /dev/null
+++ b/oreo.elixpo/src/app/upload/page.tsx
@@ -0,0 +1,438 @@
+"use client";
+
+import { useEffect, useRef, useState } from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import {
+ ArrowRight, ShieldCheck, Wifi, RefreshCw, Lock, Loader2,
+} from "lucide-react";
+import { Reveal } from "@/components/MotionWrap";
+
+/* The /upload route is the public on-ramp to the badge's local file
+ * transfer flow. Browsers block HTTPS β HTTP fetches (mixed content),
+ * and the badge speaks HTTP only β so this page collects the 6-char
+ * code shown on the badge, then hands the user off to
+ * http://oreo.local/?prefill= in a new tab where the badge's
+ * own gated upload page picks up from there.
+ *
+ * The UI mirrors the badge's local page: six independent code cells
+ * with auto-advance, paste-friendly behaviour, and ambiguous-character
+ * filtering. The Open button sits below the cells (not beside them)
+ * so the card stays balanced at every viewport width.
+ */
+
+const CODE_LEN = 6;
+const CODE_CELL_OK = /^[A-HJ-NP-Z2-9]$/i; // single char accepted into a cell
+
+// mDNS on ESP32 MicroPython is unreliable in the wild (depends on IDF
+// build flags, router multicast forwarding, and the client OS's
+// happiness with multicast DNS). We default the badge address to
+// `oreo.local` for the lucky case but let the user type the raw IP
+// the badge prints on its own Send Files screen as a fallback.
+const DEFAULT_HOST = "oreo.local";
+
+// Accept hostnames OR bare IPv4 addresses with an optional port.
+// Examples that match: `oreo.local`, `192.168.1.42`, `192.168.1.42:80`.
+const ADDR_OK = /^[A-Za-z0-9.-]+(:\d{1,5})?$/;
+
+// The badge derives a short hash from its current rotating code and
+// expects `?prefill=` (NOT the raw code) on the local page.
+// Keeping the raw code out of the URL means it never lands in browser
+// history, referer headers, or shared screenshots. The hash is the
+// first 4 bytes of SHA-256(code.toUpperCase()), hex-encoded β matches
+// `code_hash()` in oreoOS/http_server.py exactly.
+async function codeHash(code: string): Promise {
+ const buf = new TextEncoder().encode(code.toUpperCase());
+ const hash = await crypto.subtle.digest("SHA-256", buf);
+ return Array.from(new Uint8Array(hash).slice(0, 4))
+ .map((b) => b.toString(16).padStart(2, "0"))
+ .join("");
+}
+
+export default function UploadPage() {
+ const [cells, setCells] = useState(() => Array(CODE_LEN).fill(""));
+ const [error, setError] = useState("");
+ const [phase, setPhase] = useState<"enter" | "loading" | "handoff">("enter");
+ const [host, setHost] = useState(DEFAULT_HOST);
+ const [hash, setHash] = useState("");
+ const refs = useRef>([]);
+ refs.current = refs.current.slice(0, CODE_LEN);
+
+ // Pull a last-used host from localStorage on first render so a
+ // returning user doesn't have to re-type their badge's IP every
+ // session. Only restored on the client; SSR sees DEFAULT_HOST.
+ useEffect(() => {
+ try {
+ const saved = localStorage.getItem("oreo-badge-host");
+ if (saved) setHost(saved);
+ } catch { /* private mode β fine */ }
+ }, []);
+
+ const code = cells.join("").toUpperCase();
+ const complete = code.length === CODE_LEN;
+ const hostValid = ADDR_OK.test(host.trim());
+
+ // Focus the first cell on mount.
+ useEffect(() => { refs.current[0]?.focus(); }, []);
+
+ // Pre-compute the hash whenever the code is complete so the click
+ // handler can use it synchronously β crypto.subtle.digest is async,
+ // and awaiting it inside handoff() would break the user-gesture
+ // flag that popup blockers rely on.
+ useEffect(() => {
+ if (!complete) { setHash(""); return; }
+ let cancelled = false;
+ codeHash(code).then((h) => { if (!cancelled) setHash(h); });
+ return () => { cancelled = true; };
+ }, [code, complete]);
+
+ function setCell(i: number, raw: string) {
+ const v = (raw || "").toUpperCase();
+
+ // Paste of multiple chars β distribute across cells starting at i.
+ if (v.length > 1) {
+ const parts = v.replace(/[^A-HJ-NP-Z2-9]/g, "").split("").slice(0, CODE_LEN - i);
+ const next = [...cells];
+ parts.forEach((c, k) => { next[i + k] = c; });
+ setCells(next);
+ const last = Math.min(CODE_LEN - 1, i + parts.length);
+ refs.current[last]?.focus();
+ setError("");
+ return;
+ }
+
+ // Single char β filter then auto-advance.
+ if (v && !CODE_CELL_OK.test(v)) return;
+ const next = [...cells];
+ next[i] = v;
+ setCells(next);
+ if (v && i < CODE_LEN - 1) refs.current[i + 1]?.focus();
+ setError("");
+ }
+
+ function onKeyDown(i: number, e: React.KeyboardEvent) {
+ if (e.key === "Backspace" && !cells[i] && i > 0) refs.current[i - 1]?.focus();
+ if (e.key === "ArrowLeft" && i > 0) refs.current[i - 1]?.focus();
+ if (e.key === "ArrowRight" && i < CODE_LEN - 1) refs.current[i + 1]?.focus();
+ if (e.key === "Enter" && complete) handoff();
+ }
+
+ // Computed once per render so the visible "Open transfer" link
+ // ALSO points at the live URL β that way if window.open is
+ // blocked, the user can right-click β "open in new tab" on the
+ // anchor we render.
+ const rawHost = host.trim();
+ const safeHost = ADDR_OK.test(rawHost) ? rawHost : DEFAULT_HOST;
+ const targetUrl = `http://${safeHost}/?prefill=${encodeURIComponent(hash)}`;
+
+ function handoff(e?: React.SyntheticEvent) {
+ // Prevent the default form submit so the page doesn't reload
+ // (which would otherwise wipe our state mid-handoff).
+ e?.preventDefault();
+ if (!complete) {
+ setError(`Code must be ${CODE_LEN} characters.`);
+ return;
+ }
+ if (!hash) {
+ // Hash hasn't finished computing yet β extremely unlikely since
+ // SHA-256 of 6 bytes is sub-millisecond, but guard anyway so we
+ // never open a URL with an empty prefill.
+ setError("Hashing code⦠try again.");
+ return;
+ }
+ const h = host.trim() || DEFAULT_HOST;
+ if (!ADDR_OK.test(h)) {
+ setError(`"${h}" isn't a valid hostname or IP.`);
+ return;
+ }
+ try { localStorage.setItem("oreo-badge-host", h); } catch {}
+
+ // Canonicalize the destination URL from a strictly validated host.
+ const normalizedHost = host.trim().toLowerCase();
+ if (!ADDR_OK.test(normalizedHost)) {
+ setError("Enter a valid badge address (hostname or IPv4, optional :port).");
+ return;
+ }
+ const url = new URL(`http://${normalizedHost}/`);
+ url.searchParams.set("prefill", hashHex);
+ const safeTargetUrl = url.toString();
+
+ // ββ Fire window.open SYNCHRONOUSLY inside the user gesture ββ
+ // Wrapping it in setTimeout (even with a tiny delay) makes
+ // browsers treat the call as scripted and block the popup. We
+ // open the new tab first; the "loading" UI is rendered after.
+ const opened = window.open(safeTargetUrl, "_blank", "noopener,noreferrer");
+ if (!opened) {
+ // Popup blocked anyway. Fall back to a top-level navigation β
+ // this loses the website tab but at least gets the user to
+ // the badge. They can use the browser's back button to return.
+ window.location.href = safeTargetUrl;
+ return;
+ }
+ // Show the loading state while the new tab is spinning up the
+ // FTP-style transfer on the badge. After a brief delay we clear
+ // the code cells and return to the empty entry form so the user
+ // can start a fresh transfer without manually wiping the input.
+ setPhase("loading");
+ window.setTimeout(() => {
+ setCells(Array(CODE_LEN).fill(""));
+ setHash("");
+ setError("");
+ setPhase("enter");
+ // Re-focus the first cell so the user can immediately type the
+ // next code if they're sending a second file.
+ refs.current[0]?.focus();
+ }, 1400);
+ }
+
+ return (
+
+
+
+
+ peer-to-peer Β· local network only
+
+
+ Send to your badge.
+
No accounts. No cloud.
+
+
+ Open Settings β WiFi β Send files on
+ the badge. Enter the 6-character code shown there to start a
+ gated, same-network transfer. Files never leave your LAN.
+
+
+
+
+
+
+ {phase === "enter" ? (
+
+
+
+ {/* Six code cells β independent inputs so the user can't
+ fat-finger more than one char per slot. Auto-advance
+ + paste-distribute logic lives in setCell(). */}
+
+ {cells.map((v, i) => (
+ { refs.current[i] = el; }}
+ value={v}
+ onChange={(e) => setCell(i, e.target.value)}
+ onKeyDown={(e) => onKeyDown(i, e)}
+ onFocus={(e) => e.target.select()}
+ maxLength={2}
+ inputMode="text"
+ autoComplete="off"
+ spellCheck={false}
+ aria-label={`Code character ${i + 1}`}
+ className="h-16 w-12 rounded-md border border-border bg-bg
+ text-center font-mono text-3xl font-semibold uppercase
+ text-primary outline-none transition-colors
+ placeholder:text-muted-deep
+ focus:border-primary focus:ring-2 focus:ring-primary/30
+ sm:h-20 sm:w-14 sm:text-4xl"
+ />
+ ))}
+
+
+ {/* Helper / error line β fixed-height so the layout
+ doesn't jump as the message changes. */}
+
+ {error ? (
+
+ {error}
+
+ ) : (
+
+ Six characters Β· skips ambiguous shapes (no 0/O/1/I/L)
+
+ )}
+
+
+ {/* Badge address. Default `oreo.local` works on networks
+ where multicast DNS resolves; otherwise the user
+ types the IP printed on the badge's Send Files page. */}
+
+
+ { setHost(e.target.value); setError(""); }}
+ spellCheck={false}
+ autoComplete="off"
+ autoCapitalize="off"
+ inputMode="url"
+ placeholder="oreo.local"
+ className={`mx-auto mt-2 block w-full max-w-xs rounded-md
+ border bg-bg px-3 py-2.5 text-center
+ font-mono text-base text-text outline-none
+ transition-colors placeholder:text-muted-deep
+ ${hostValid
+ ? "border-border focus:border-primary/70"
+ : "border-primary/50 focus:border-primary"}`}
+ />
+
+ Default oreo.local works
+ on networks where mDNS resolves. Otherwise type the IP
+ shown on the badge's Send Files page (e.g.{" "}
+ 192.168.1.42).
+
+
+
+
+
+ {/* Backup link β visible only after the form is valid.
+ Lets the user right-click β "open in new tab" if the
+ Submit button's window.open got blocked by their
+ browser (most common on iOS Safari + Firefox
+ strict-popup-blocking modes). */}
+ {complete && hostValid && hash && (
+
+ Button blocked?{" "}
+
+ Open this link manually
+ .
+
+ )}
+
+ {/* Three info tiles below β explain the model without
+ making the user read paragraphs. */}
+
+
+
+
+
+
+ ) : phase === "loading" ? (
+
+
+
+
+
+ Opening local page for FTP transferβ¦
+
+
+ A new tab is loading{" "}
+ http://{host || DEFAULT_HOST}.
+ Approve the session on the badge to start sending files.
+
+
+
+
+
+ ) : (
+
+
+
+
+
+ Transfer tab opened.
+
+
+ Make sure your device is on the same WiFi as the badge,
+ approve the session, and pick a file.
+
+
+
+ )}
+
+
+
+
+ Why two pages?
+
+ Browsers block HTTPS pages from talking to plain-HTTP
+ endpoints. Cloudflare serves this page over HTTPS; the
+ badge speaks HTTP on your LAN. The handoff puts you on
+ the badge's own page so the upload itself stays on the
+ local network β no cloud, no proxy, no metadata leakage.
+
+
+
+
+
+ );
+}
+
+function Tile({
+ Icon, title, body,
+}: {
+ Icon: React.ComponentType<{ className?: string }>;
+ title: string;
+ body: string;
+}) {
+ return (
+
+
+ {title}
+ {body}
+
+ );
+}
diff --git a/oreo.elixpo/src/components/AppCard.tsx b/oreo.elixpo/src/components/AppCard.tsx
new file mode 100644
index 0000000..22a26c3
--- /dev/null
+++ b/oreo.elixpo/src/components/AppCard.tsx
@@ -0,0 +1,122 @@
+"use client";
+
+import { useState } from "react";
+import Link from "next/link";
+import { motion } from "framer-motion";
+import {
+ Contact, Bird, Image as ImageIcon, Worm, Compass, BookOpen, Car,
+ Cloud, GitCommit, User, Gamepad2, HardDrive, Palette, PawPrint,
+ Cpu, Wifi, Bluetooth, RefreshCw, Settings, ArrowUpRight,
+ type LucideIcon,
+} from "lucide-react";
+import type { AppEntry, AppIconId } from "@/data/apps";
+
+const ICONS: Record = {
+ Contact, Bird, Image: ImageIcon, Worm, Compass, BookOpen, Car, Cloud,
+ GitCommit, User, Gamepad2, HardDrive, Palette, PawPrint, Cpu, Wifi,
+ Bluetooth, RefreshCw, Settings,
+};
+
+type Tint = { ring: string; glow: string; text: string };
+
+const TINT: Record = {
+ primary: { ring: "ring-primary/40", glow: "shadow-[0_0_36px_rgba(255,93,104,0.22)]", text: "text-primary" },
+ teal: { ring: "ring-teal/40", glow: "shadow-[0_0_36px_rgba(61,220,151,0.20)]", text: "text-teal" },
+ gold: { ring: "ring-gold/40", glow: "shadow-[0_0_36px_rgba(255,209,102,0.18)]",text: "text-gold" },
+ lilac: { ring: "ring-lilac/40", glow: "shadow-[0_0_36px_rgba(162,155,254,0.20)]",text: "text-lilac" },
+};
+
+/* Icon tile reused by AppCard + the detail-page related strip β keeps
+ * the "real PNG with letter fallback" logic in one place. */
+function IconTile({
+ app, tint, Icon,
+}: {
+ app: AppEntry;
+ tint: Tint;
+ Icon: LucideIcon;
+}) {
+ const [pngOk, setPngOk] = useState(true);
+ return (
+
+ {app.pngIcon && pngOk ? (
+ // eslint-disable-next-line @next/next/no-img-element
+ setPngOk(false)}
+ className="h-full w-full object-contain"
+ style={{ imageRendering: "pixelated" }}
+ loading="lazy"
+ decoding="async"
+ />
+ ) : (
+
+ )}
+
+ );
+}
+
+export default function AppCard({
+ app,
+ index = 0,
+}: {
+ app: AppEntry;
+ index?: number;
+}) {
+ const tint = TINT[app.tint] ?? TINT.primary;
+ const Icon = ICONS[app.icon] ?? Cpu;
+
+ return (
+
+
+
+
+
+
+
+ {app.name}
+
+ {app.category}
+
+
+ {app.blurb}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/components/BadgeMockup.tsx b/oreo.elixpo/src/components/BadgeMockup.tsx
new file mode 100644
index 0000000..31060be
--- /dev/null
+++ b/oreo.elixpo/src/components/BadgeMockup.tsx
@@ -0,0 +1,147 @@
+"use client";
+
+import { motion } from "framer-motion";
+
+/* SVG mockup of the actual hardware β portrait PCB with a screen
+ * top-60%, two rows of four tactile buttons below, IR transceiver at
+ * the top edge, four corner LEDs, and a USB-C cutout on the bottom.
+ *
+ * Pure SVG so the whole thing scales sharply at any resolution, and
+ * the animation is just ``/`framer-motion` over the on-screen
+ * app-tile grid β costs ~0% CPU after the initial paint.
+ *
+ * Drawing units are tuned so 1 SVG unit β 1 mm on the PCB; final
+ * artwork lives at viewBox="0 0 100 160".
+ */
+
+const APP_TILES: { x: number; y: number; tint: string; glyph: string }[] = [
+ { x: 6, y: 4, tint: "#FF5D68", glyph: "B" },
+ { x: 28, y: 4, tint: "#3DDC97", glyph: "S" },
+ { x: 50, y: 4, tint: "#FFD166", glyph: "G" },
+ { x: 72, y: 4, tint: "#A29BFE", glyph: "F" },
+ { x: 6, y: 26, tint: "#A29BFE", glyph: "R" },
+ { x: 28, y: 26, tint: "#FF5D68", glyph: "Q" },
+ { x: 50, y: 26, tint: "#3DDC97", glyph: "W" },
+ { x: 72, y: 26, tint: "#FFD166", glyph: "C" },
+];
+
+const BUTTON_LABELS = ["HOME", "A", "B", "C", "UP", "DOWN", "LEFT", "RIGHT"];
+
+export default function BadgeMockup({ className = "" }: { className?: string }) {
+ return (
+
+ );
+}
diff --git a/oreo.elixpo/src/components/Footer.tsx b/oreo.elixpo/src/components/Footer.tsx
new file mode 100644
index 0000000..6bf3c8d
--- /dev/null
+++ b/oreo.elixpo/src/components/Footer.tsx
@@ -0,0 +1,139 @@
+"use client";
+
+import Link from "next/link";
+import { Github, Heart, Star, GitFork } from "lucide-react";
+import { useGithubStats } from "@/lib/useGithubStats";
+
+function fmtCount(n: number | null): string {
+ if (n === null) return "β";
+ if (n >= 10_000) return (n / 1000).toFixed(1) + "k";
+ if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, "") + "k";
+ return String(n);
+}
+
+// One column row. `external` is optional; absent β internal Link.
+type FooterLink = { label: string; href: string; external?: boolean };
+type FooterColumn = { title: string; links: FooterLink[] };
+
+const COLUMNS: FooterColumn[] = [
+ {
+ title: "Project",
+ links: [
+ { label: "Get Started", href: "/get-started/" },
+ { label: "Badge", href: "/badge/" },
+ { label: "Apps", href: "/apps/" },
+ { label: "Hacks", href: "/hacks/" },
+ { label: "Contribute", href: "/contribute/" },
+ { label: "Upload", href: "/upload/" },
+ ],
+ },
+ {
+ title: "Source",
+ links: [
+ { label: "OreoOS", href: "https://github.com/elixpo/oreo", external: true },
+ { label: "Hardware", href: "https://github.com/elixpo/oreo/tree/main/docs", external: true },
+ { label: "Contributing", href: "https://github.com/elixpo/oreo/blob/main/CONTRIBUTING.md", external: true },
+ { label: "License", href: "https://github.com/elixpo/oreo/blob/main/LICENSE", external: true },
+ ],
+ },
+ {
+ title: "Community",
+ links: [
+ { label: "Contributors", href: "https://github.com/elixpo/oreo/graphs/contributors", external: true },
+ { label: "Issues", href: "https://github.com/elixpo/oreo/issues", external: true },
+ { label: "Changelog", href: "https://github.com/elixpo/oreo/blob/main/CHANGELOG.md", external: true },
+ { label: "Code of Conduct", href: "https://github.com/elixpo/oreo/blob/main/CODE_OF_CONDUCT.md", external: true },
+ ],
+ },
+];
+
+export default function Footer() {
+ const { stars, forks } = useGithubStats();
+ return (
+
+ );
+}
diff --git a/oreo.elixpo/src/components/Header.tsx b/oreo.elixpo/src/components/Header.tsx
new file mode 100644
index 0000000..98414bb
--- /dev/null
+++ b/oreo.elixpo/src/components/Header.tsx
@@ -0,0 +1,112 @@
+"use client";
+
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { motion } from "framer-motion";
+import {
+ Github, Star, GitFork, Home, Rocket, Cpu, LayoutGrid,
+ Wrench, GitPullRequest,
+} from "lucide-react";
+import { useGithubStats } from "@/lib/useGithubStats";
+
+const NAV = [
+ { href: "/", label: "Home", Icon: Home },
+ { href: "/get-started/",label: "Get Started", Icon: Rocket },
+ { href: "/badge/", label: "Badge", Icon: Cpu },
+ { href: "/apps/", label: "Apps", Icon: LayoutGrid },
+ { href: "/hacks/", label: "Hacks", Icon: Wrench },
+ { href: "/contribute/", label: "Contribute", Icon: GitPullRequest },
+];
+
+function fmtCount(n: number | null): string {
+ if (n === null) return "β";
+ if (n >= 10_000) return (n / 1000).toFixed(1) + "k";
+ if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, "") + "k";
+ return String(n);
+}
+
+export default function Header() {
+ const pathname = usePathname();
+ const { stars, forks } = useGithubStats();
+
+ return (
+
+
+ {/* Logo + wordmark β uses the real OreoOS mascot asset, the
+ same pixel-art panda baked into assets/sprites/optimized/
+ on the badge. Pixelated rendering keeps the chunky LCD
+ artwork crisp at 36 px. */}
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+
+
+ Oreo
+
+
+ {/* Centre nav with per-item icons */}
+
+
+ {/* Live GitHub stats chip */}
+
+
+
+ elixpo/oreo
+
+ {fmtCount(stars)}
+ {fmtCount(forks)}
+
+
+
+
+
+ );
+}
diff --git a/oreo.elixpo/src/components/MarkdownView.tsx b/oreo.elixpo/src/components/MarkdownView.tsx
new file mode 100644
index 0000000..8eb6110
--- /dev/null
+++ b/oreo.elixpo/src/components/MarkdownView.tsx
@@ -0,0 +1,223 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { motion } from "framer-motion";
+
+/* Hand-rolled minimal Markdown β HTML renderer.
+ *
+ * Why not react-markdown / marked / micromark?
+ * β’ ~30-80 KB gzipped β too much for what's effectively a
+ * CONTRIBUTING.md panel that renders once on one route.
+ * β’ Most of the bundle is feature-completeness we don't need
+ * (math, mermaid, smart quotes, footnotes).
+ *
+ * Supported subset (what CONTRIBUTING.md actually uses):
+ * β’ # / ## / ### / #### headings
+ * β’ bullet lists (`- ` and `* `)
+ * β’ numbered lists (`1. `)
+ * β’ bold `**`, italic `*`, inline code `` ` ``
+ * β’ fenced code blocks ``` lang
+ * β’ blockquotes (`> `)
+ * β’ links `[text](url)`
+ * β’ horizontal rules `---`
+ * β’ paragraphs
+ *
+ * Everything else falls through as a plain paragraph β safe because
+ * we sanitise raw HTML in the source on the way in.
+ */
+
+function escapeHtml(s: string): string {
+ return s
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+}
+
+function renderInline(s: string): string {
+ let out = escapeHtml(s);
+ // inline code first so its content isn't re-interpreted
+ out = out.replace(/`([^`]+)`/g,
+ '$1');
+ // bold (avoid clobbering italics underneath)
+ out = out.replace(/\*\*([^*]+)\*\*/g, "$1");
+ // italic
+ out = out.replace(/(^|[^*])\*([^*\n]+)\*/g, "$1$2");
+ // links β only inline form, [text](url)
+ out = out.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,
+ '$1');
+ return out;
+}
+
+function renderMarkdown(src: string): string {
+ const lines = src.replace(/\r\n/g, "\n").split("\n");
+ const out: string[] = [];
+ let inCode = false;
+ let codeLang = "";
+ let codeBuf: string[] = [];
+ let listType: "ul" | "ol" | null = null;
+ let para: string[] = [];
+
+ const closeList = () => {
+ if (listType) { out.push(`${listType}>`); listType = null; }
+ };
+ const flushPara = () => {
+ if (para.length) {
+ out.push(`${renderInline(para.join(" "))}
`);
+ para = [];
+ }
+ };
+
+ for (let raw of lines) {
+ // ββ fenced code blocks ββ
+ const fence = raw.match(/^```(\w*)\s*$/);
+ if (fence) {
+ if (inCode) {
+ out.push(
+ `` +
+ escapeHtml(codeBuf.join("\n")) +
+ `
`,
+ );
+ inCode = false;
+ codeBuf = [];
+ codeLang = "";
+ } else {
+ flushPara(); closeList();
+ inCode = true;
+ codeLang = fence[1] || "";
+ }
+ continue;
+ }
+ if (inCode) {
+ codeBuf.push(raw);
+ continue;
+ }
+
+ // ββ horizontal rule ββ
+ if (/^---+\s*$/.test(raw)) {
+ flushPara(); closeList();
+ out.push(`
`);
+ continue;
+ }
+
+ // ββ headings ββ
+ const h = raw.match(/^(#{1,4})\s+(.*)$/);
+ if (h) {
+ flushPara(); closeList();
+ const lvl = h[1].length;
+ const text = renderInline(h[2]);
+ const klass = {
+ 1: "mt-10 mb-4 font-display text-4xl tracking-tight text-text",
+ 2: "mt-10 mb-3 font-display text-2xl tracking-tight text-text",
+ 3: "mt-7 mb-2 font-display text-xl tracking-tight text-text",
+ 4: "mt-5 mb-2 font-display text-lg tracking-tight text-text-dim",
+ }[lvl as 1 | 2 | 3 | 4];
+ out.push(`${text} `);
+ continue;
+ }
+
+ // ββ blockquote ββ
+ const bq = raw.match(/^>\s?(.*)$/);
+ if (bq) {
+ flushPara(); closeList();
+ out.push(
+ `${renderInline(bq[1])}
`,
+ );
+ continue;
+ }
+
+ // ββ list items ββ
+ const ul = raw.match(/^[-*]\s+(.*)$/);
+ const ol = raw.match(/^\d+\.\s+(.*)$/);
+ if (ul || ol) {
+ flushPara();
+ const want: "ul" | "ol" = ul ? "ul" : "ol";
+ if (listType !== want) {
+ closeList();
+ const klass = want === "ul"
+ ? "my-3 list-disc space-y-1 pl-6 text-text-dim marker:text-primary/70"
+ : "my-3 list-decimal space-y-1 pl-6 text-text-dim marker:text-primary/70";
+ out.push(`<${want} class="${klass}">`);
+ listType = want;
+ }
+ out.push(`${renderInline((ul ?? ol)![1])} `);
+ continue;
+ }
+
+ // ββ blank line β paragraph break ββ
+ if (!raw.trim()) {
+ flushPara(); closeList();
+ continue;
+ }
+
+ // ββ plain paragraph text (join consecutive lines) ββ
+ para.push(raw);
+ }
+ flushPara(); closeList();
+ if (inCode) {
+ // Unclosed fence β best-effort flush so we don't drop content.
+ out.push(
+ `` +
+ escapeHtml(codeBuf.join("\n")) +
+ `
`,
+ );
+ }
+ return out.join("\n");
+}
+
+export default function MarkdownView({
+ url, fallback,
+}: {
+ url: string;
+ fallback?: string;
+}) {
+ const [html, setHtml] = useState(null);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ let aborted = false;
+ (async () => {
+ try {
+ const r = await fetch(url);
+ if (!r.ok) throw new Error("HTTP " + r.status);
+ const md = await r.text();
+ if (!aborted) setHtml(renderMarkdown(md));
+ } catch (e) {
+ if (!aborted) setError((e as Error).message);
+ }
+ })();
+ return () => { aborted = true; };
+ }, [url]);
+
+ if (error) {
+ return (
+
+ Couldn't load {url}: {error}.
+ {fallback && {fallback}
}
+
+ );
+ }
+ if (html === null) {
+ return (
+
+ {[...Array(8)].map((_, i) => (
+
+ ))}
+
+ );
+ }
+ return (
+
+ );
+}
diff --git a/oreo.elixpo/src/components/MotionWrap.tsx b/oreo.elixpo/src/components/MotionWrap.tsx
new file mode 100644
index 0000000..b1a98c6
--- /dev/null
+++ b/oreo.elixpo/src/components/MotionWrap.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { motion, type Variants } from "framer-motion";
+
+/* Shared motion presets so every page transition / reveal feels like
+ it came from the same product. Components import these directly
+ instead of redeclaring keyframes. The crisp-spring presets are tuned
+ for "snappy but not bouncy" β feels intentional, not gimmicky. */
+
+export const fadeUp: Variants = {
+ hidden: { opacity: 0, y: 16 },
+ visible: { opacity: 1, y: 0,
+ transition: { duration: 0.55, ease: [0.16, 1, 0.3, 1] } },
+};
+
+export const fadeIn: Variants = {
+ hidden: { opacity: 0 },
+ visible: { opacity: 1, transition: { duration: 0.4 } },
+};
+
+export const staggerContainer: Variants = {
+ hidden: {},
+ visible: {
+ transition: { staggerChildren: 0.06, delayChildren: 0.04 },
+ },
+};
+
+export function Reveal({
+ children, delay = 0, className = "",
+}: {
+ children: React.ReactNode;
+ delay?: number;
+ className?: string;
+}) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/oreo.elixpo/src/components/PageTransition.tsx b/oreo.elixpo/src/components/PageTransition.tsx
new file mode 100644
index 0000000..cf693e5
--- /dev/null
+++ b/oreo.elixpo/src/components/PageTransition.tsx
@@ -0,0 +1,32 @@
+"use client";
+
+import { motion } from "framer-motion";
+import { usePathname } from "next/navigation";
+
+/* Lightweight route-change reveal. Just an opacity + y-slide on the
+ * contents, keyed on pathname so Next remounts the wrapper
+ * each navigation. Deliberately minimal β Framer's `AnimatePresence`
+ * with `mode="wait"` adds a perceptible delay before the new page
+ * paints, which is the opposite of the "no-lag" feel the user wants.
+ *
+ * This is the simplest pattern that still gives the site some
+ * "transition feel" without ever blocking the new page from showing.
+ */
+
+export default function PageTransition({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const pathname = usePathname();
+ return (
+
+ {children}
+
+ );
+}
diff --git a/oreo.elixpo/src/components/WavesHero.tsx b/oreo.elixpo/src/components/WavesHero.tsx
new file mode 100644
index 0000000..1c642ae
--- /dev/null
+++ b/oreo.elixpo/src/components/WavesHero.tsx
@@ -0,0 +1,390 @@
+"use client";
+
+/*
+ * Reactive canvas hero β adapted from the shadcn `glowy-waves-hero`
+ * reference dropped in plan.md.
+ *
+ * Differences from the original:
+ * β’ Uses our brand palette + copy instead of shadcn's `--primary` etc.
+ * (theme tokens are still read from CSS vars so future theme tweaks
+ * reflow automatically).
+ * β’ Replaces the shadcn