From 797efd37606d2fd5d1d4906efc8fc5142d1eb460 Mon Sep 17 00:00:00 2001 From: Sam Rolfe Date: Wed, 26 Aug 2026 13:19:25 +1000 Subject: [PATCH] Initial commit: sam-pursuits --- .gitignore | 8 + about.md | 17 + bun.lock | 367 +++++++++++ index.html | 12 + package.json | 30 + src/App.tsx | 23 + src/components/AiChatBox.tsx | 76 +++ src/components/ContentBlocks.tsx | 158 +++++ src/components/ExternalLinkCard.tsx | 41 ++ src/components/HorizontalTabs.tsx | 39 ++ src/components/Layout.tsx | 299 +++++++++ src/components/PageHeader.tsx | 25 + src/components/PursuitCard.tsx | 56 ++ src/components/PursuitHero.tsx | 23 + src/components/SectionCard.tsx | 41 ++ src/components/StatBadge.tsx | 22 + src/data/navItems.ts | 40 ++ src/data/pursuitsData.ts | 933 ++++++++++++++++++++++++++++ src/index.css | 93 +++ src/main.tsx | 10 + src/pages/AiChat.tsx | 49 ++ src/pages/Contact.tsx | 97 +++ src/pages/Home.tsx | 95 +++ src/pages/Interests.tsx | 81 +++ src/pages/PursuitPage.tsx | 65 ++ tsconfig.json | 18 + vite.config.ts | 16 + 27 files changed, 2734 insertions(+) create mode 100644 .gitignore create mode 100644 about.md create mode 100644 bun.lock create mode 100644 index.html create mode 100644 package.json create mode 100644 src/App.tsx create mode 100644 src/components/AiChatBox.tsx create mode 100644 src/components/ContentBlocks.tsx create mode 100644 src/components/ExternalLinkCard.tsx create mode 100644 src/components/HorizontalTabs.tsx create mode 100644 src/components/Layout.tsx create mode 100644 src/components/PageHeader.tsx create mode 100644 src/components/PursuitCard.tsx create mode 100644 src/components/PursuitHero.tsx create mode 100644 src/components/SectionCard.tsx create mode 100644 src/components/StatBadge.tsx create mode 100644 src/data/navItems.ts create mode 100644 src/data/pursuitsData.ts create mode 100644 src/index.css create mode 100644 src/main.tsx create mode 100644 src/pages/AiChat.tsx create mode 100644 src/pages/Contact.tsx create mode 100644 src/pages/Home.tsx create mode 100644 src/pages/Interests.tsx create mode 100644 src/pages/PursuitPage.tsx create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad05e2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +build/ +dist/ +coverage/ +.DS_Store +*.log +.env* +!.env.example \ No newline at end of file diff --git a/about.md b/about.md new file mode 100644 index 0000000..acc6243 --- /dev/null +++ b/about.md @@ -0,0 +1,17 @@ +#Major pursuits +This website covers all my major personal interests and hobbies. +#pages +- Music +- Fine Art +- Philosphy +- Sport - Skiing +- Camping +- Canoeing +- Surfing +- Hiking +- Global Politics +- Reading +- Cooking +- Gardening +- Food Production - Salami, Cheese, Honey, Salt +- Italy Ski, Restraurant diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..5639ecc --- /dev/null +++ b/bun.lock @@ -0,0 +1,367 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "pursuits-hub", + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "@vitejs/plugin-react": "^5.0.4", + "lucide-react": "^0.546.0", + "motion": "^12.23.24", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^7.13.2", + "vite": "^6.2.0", + }, + "devDependencies": { + "@types/node": "^25.6.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "tailwindcss": "^4.1.14", + "typescript": "~5.8.2", + }, + }, + }, + "packages": { + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], + + "@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], + + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.2", "", { "os": "android", "cpu": "arm" }, "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.2", "", { "os": "android", "cpu": "arm64" }, "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.2", "", { "os": "linux", "cpu": "arm" }, "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.2", "", { "os": "linux", "cpu": "arm" }, "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.2", "", { "os": "linux", "cpu": "none" }, "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.2", "", { "os": "linux", "cpu": "x64" }, "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.2", "", { "os": "linux", "cpu": "x64" }, "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.2", "", { "os": "none", "cpu": "arm64" }, "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.2", "", { "os": "win32", "cpu": "x64" }, "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.2", "", { "os": "win32", "cpu": "x64" }, "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.2.4", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.4" } }, "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.4", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.4", "@tailwindcss/oxide-darwin-arm64": "4.2.4", "@tailwindcss/oxide-darwin-x64": "4.2.4", "@tailwindcss/oxide-freebsd-x64": "4.2.4", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.4", "@tailwindcss/oxide-linux-arm64-musl": "4.2.4", "@tailwindcss/oxide-linux-x64-gnu": "4.2.4", "@tailwindcss/oxide-linux-x64-musl": "4.2.4", "@tailwindcss/oxide-wasm32-wasi": "4.2.4", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.4", "@tailwindcss/oxide-win32-x64-msvc": "4.2.4" } }, "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.4", "", { "os": "android", "cpu": "arm64" }, "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.4", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.4", "", { "os": "win32", "cpu": "x64" }, "sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw=="], + + "@tailwindcss/vite": ["@tailwindcss/vite@4.2.4", "", { "dependencies": { "@tailwindcss/node": "4.2.4", "@tailwindcss/oxide": "4.2.4", "tailwindcss": "4.2.4" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw=="], + + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], + + "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + + "@vitejs/plugin-react": ["@vitejs/plugin-react@5.2.0", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.23", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-xwVXGqevyKPsiuQdLj+dZMVjidjJV508TBqexND5HrF89cGdCYCJFB3qhcxRHSeMctdCfbR1jrxBajhDy7o29g=="], + + "browserslist": ["browserslist@4.28.2", "", { "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" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001791", "", {}, "sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.344", "", {}, "sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg=="], + + "enhanced-resolve": ["enhanced-resolve@5.21.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA=="], + + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "lucide-react": ["lucide-react@0.546.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="], + + "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="], + + "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "node-releases": ["node-releases@2.0.38", "", {}, "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "postcss": ["postcss@8.5.12", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA=="], + + "react": ["react@19.2.5", "", {}, "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA=="], + + "react-dom": ["react-dom@19.2.5", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.5" } }, "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag=="], + + "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], + + "react-router": ["react-router@7.14.2", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-yCqNne6I8IB6rVCH7XUvlBK7/QKyqypBFGv+8dj4QBFJiiRX+FG7/nkdAvGElyvVZ/HQP5N19wzteuTARXi5Gw=="], + + "react-router-dom": ["react-router-dom@7.14.2", "", { "dependencies": { "react-router": "7.14.2" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-YZcM5ES8jJSM+KrJ9BdvHHqlnGTg5tH3sC5ChFRj4inosKctdyzBDhOyyHdGk597q2OT6NTrCA1OvB/YDwfekQ=="], + + "rollup": ["rollup@4.60.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.2", "@rollup/rollup-android-arm64": "4.60.2", "@rollup/rollup-darwin-arm64": "4.60.2", "@rollup/rollup-darwin-x64": "4.60.2", "@rollup/rollup-freebsd-arm64": "4.60.2", "@rollup/rollup-freebsd-x64": "4.60.2", "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", "@rollup/rollup-linux-arm-musleabihf": "4.60.2", "@rollup/rollup-linux-arm64-gnu": "4.60.2", "@rollup/rollup-linux-arm64-musl": "4.60.2", "@rollup/rollup-linux-loong64-gnu": "4.60.2", "@rollup/rollup-linux-loong64-musl": "4.60.2", "@rollup/rollup-linux-ppc64-gnu": "4.60.2", "@rollup/rollup-linux-ppc64-musl": "4.60.2", "@rollup/rollup-linux-riscv64-gnu": "4.60.2", "@rollup/rollup-linux-riscv64-musl": "4.60.2", "@rollup/rollup-linux-s390x-gnu": "4.60.2", "@rollup/rollup-linux-x64-gnu": "4.60.2", "@rollup/rollup-linux-x64-musl": "4.60.2", "@rollup/rollup-openbsd-x64": "4.60.2", "@rollup/rollup-openharmony-arm64": "4.60.2", "@rollup/rollup-win32-arm64-msvc": "4.60.2", "@rollup/rollup-win32-ia32-msvc": "4.60.2", "@rollup/rollup-win32-x64-gnu": "4.60.2", "@rollup/rollup-win32-x64-msvc": "4.60.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "tailwindcss": ["tailwindcss@4.2.4", "", {}, "sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA=="], + + "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + + "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "vite": ["vite@6.4.2", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ=="], + + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..099bac7 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + Latte Pursuit Hub + + +
+ + + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..9adb2b4 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "pursuits-hub", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite --port=3001 --host=0.0.0.0", + "build": "vite build", + "preview": "vite preview", + "clean": "rm -rf dist", + "lint": "tsc --noEmit" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "@vitejs/plugin-react": "^5.0.4", + "lucide-react": "^0.546.0", + "motion": "^12.23.24", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^7.13.2", + "vite": "^6.2.0" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "tailwindcss": "^4.1.14", + "typescript": "~5.8.2" + } +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..ce5c1df --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,23 @@ +import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import Layout from "./components/Layout"; +import Home from "./pages/Home"; +import Interests from "./pages/Interests"; +import PursuitPage from "./pages/PursuitPage"; +import AiChat from "./pages/AiChat"; +import Contact from "./pages/Contact"; + +export default function App() { + return ( + + + + } /> + } /> + } /> + } /> + } /> + + + + ); +} \ No newline at end of file diff --git a/src/components/AiChatBox.tsx b/src/components/AiChatBox.tsx new file mode 100644 index 0000000..441a44c --- /dev/null +++ b/src/components/AiChatBox.tsx @@ -0,0 +1,76 @@ +import React, { useState } from "react"; +import { Send, Bot, Sparkles } from "lucide-react"; + +export default function AiChatBox() { + const [input, setInput] = useState(""); + const [messages, setMessages] = useState<{ role: string; text: string }[]>([ + { role: "ai", text: "Hi there! I'm your personal pursuits assistant. Ask me about my interests, hobbies, or anything you'd like to know!" }, + ]); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (!input.trim()) return; + setMessages([...messages, { role: "user", text: input }]); + setInput(""); + setTimeout(() => { + setMessages((prev) => [...prev, { + role: "ai", + text: "That's a great question! I'm currently set up as a static demo — my local AI backend will power responses once deployed.", + }]); + }, 800); + }; + + return ( +
+
+
+ +
+
+
AI Assistant
+
powered by local LLM
+
+ +
+ +
+ {messages.map((msg, i) => ( +
+ {msg.role === "ai" && ( +
+ +
+ )} +
+ {msg.text} +
+
+ ))} +
+ +
+
+ setInput(e.target.value)} + placeholder="Ask me anything..." + className="flex-1 bg-surface-container-highest text-on-surface placeholder-on-surface-variant/50 rounded-xl px-4 py-3 text-sm font-sans border border-outline-variant/50 focus:outline-none focus:border-primary/50 focus:glow-primary transition-all" + /> + +
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/ContentBlocks.tsx b/src/components/ContentBlocks.tsx new file mode 100644 index 0000000..89bb37a --- /dev/null +++ b/src/components/ContentBlocks.tsx @@ -0,0 +1,158 @@ +import React from "react"; +import { CheckSquare, Square, Clock, Circle, Calendar } from "lucide-react"; +import type { ContentBlock } from "../data/pursuitsData"; + +interface ContentBlocksProps { + blocks: ContentBlock[]; +} + +export default function ContentBlocks({ blocks }: ContentBlocksProps) { + return ( +
+ {blocks.map((block, index) => ( +
+ {block.title && ( +

{block.title}

+ )} + +
+ ))} +
+ ); +} + +function BlockRenderer({ block }: { block: ContentBlock }) { + switch (block.type) { + case "text": + return ; + case "timeline": + return ; + case "checklist": + return ; + case "cards": + return ; + case "gallery": + return ; + case "list": + return ; + default: + return null; + } +} + +function TextBlock({ paragraphs }: { paragraphs: string[] }) { + return ( +
+ {paragraphs.map((p, i) => ( +

{p}

+ ))} +
+ ); +} + +function TimelineBlock({ items }: { items: NonNullable }) { + return ( +
+ {items.map((item, i) => ( +
+
+
+ {i < items.length - 1 &&
} +
+
+
+ {item.date} + {item.status && ( + + {item.status} + + )} +
+
{item.title}
+
{item.description}
+
+
+ ))} +
+ ); +} + +function ChecklistBlock({ items }: { items: NonNullable }) { + const categories = [...new Set(items.map((item) => item.category || "General"))]; + + return ( +
+ {categories.map((category) => ( +
+
{category}
+
+ {items.filter((item) => (item.category || "General") === category).map((item, i) => ( +
+
+ {item.checked ? ( + + ) : ( + + )} +
+ + {item.label} + +
+ ))} +
+
+ ))} +
+ ); +} + +function CardsBlock({ items }: { items: NonNullable }) { + return ( +
+ {items.map((item, i) => ( +
+
+
{item.title}
+
{item.description}
+
+ ))} +
+ ); +} + +function GalleryBlock({ items }: { items: NonNullable }) { + return ( +
+ {items.map((item, i) => ( +
+
+
+
{item.title}
+
+
+ ))} +
+ ); +} + +function ListBlock({ items }: { items: NonNullable }) { + return ( +
    + {items.map((item, i) => ( +
  • + + {item} +
  • + ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/ExternalLinkCard.tsx b/src/components/ExternalLinkCard.tsx new file mode 100644 index 0000000..65e9c5a --- /dev/null +++ b/src/components/ExternalLinkCard.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { ExternalLink, ArrowUpRight } from "lucide-react"; + +interface ExternalLinkCardProps { + title: string; + description: string; + url: string; + icon?: React.ReactNode; +} + +export default function ExternalLinkCard({ title, description, url, icon }: ExternalLinkCardProps) { + return ( + +
+ {icon && ( +
+ {icon} +
+ )} +
+
+

+ {title} +

+ +
+

{description}

+
+ + {url} +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/HorizontalTabs.tsx b/src/components/HorizontalTabs.tsx new file mode 100644 index 0000000..285c77a --- /dev/null +++ b/src/components/HorizontalTabs.tsx @@ -0,0 +1,39 @@ +import React from "react"; + +export interface Tab { + id: string; + label: string; + icon: React.ReactNode; +} + +interface HorizontalTabsProps { + tabs: Tab[]; + activeTab: string; + onTabChange: (tabId: string) => void; +} + +export default function HorizontalTabs({ tabs, activeTab, onTabChange }: HorizontalTabsProps) { + return ( +
+
+ {tabs.map((tab) => ( + + ))} +
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx new file mode 100644 index 0000000..51a6842 --- /dev/null +++ b/src/components/Layout.tsx @@ -0,0 +1,299 @@ +import React, { useState } from "react"; +import { Link, useLocation, useNavigate } from "react-router-dom"; +import { Menu, X, Github, Linkedin, Twitter, ChevronDown, Globe, Briefcase, Server, Cpu, Compass } from "lucide-react"; +import { motion, AnimatePresence } from "motion/react"; +import { navItems } from "@/src/data/navItems"; + +const externalSites = [ + { url: "https://sam-developer.lab.audasmedia.com.au/", label: "Portfolio", icon: Briefcase }, + { url: "https://sam-devops.lab.audasmedia.com.au/", label: "DevOps Hub", icon: Server }, + { url: "https://sam-iot-electronics.lab.audasmedia.com.au/", label: "IoT & Electronics", icon: Cpu }, +]; + +export default function Layout({ children }: { children: React.ReactNode }) { + const location = useLocation(); + const navigate = useNavigate(); + const [mobileOpen, setMobileOpen] = useState(false); + const [expandedAccordion, setExpandedAccordion] = useState( + location.pathname.startsWith("/interests") ? "/interests" : null + ); + + const handleNavClick = (item: typeof navItems[0]) => { + if (item.children) { + const isExpanded = expandedAccordion === item.path; + setExpandedAccordion(isExpanded ? null : item.path); + if (!isExpanded) { + navigate(item.path); + } + } + }; + + return ( +
+ {/* Mobile Header */} +
+
+
+
+ P +
+ Pursuit Hub +
+ +
+
+ + {/* Mobile Sidebar Overlay */} + + {mobileOpen && ( + setMobileOpen(false)} + /> + )} + + + {/* Mobile Sidebar */} + + {mobileOpen && ( + + + + {/* My Sites */} + + + {/* Social Footer */} +
+
+ + + +
+
+
+ )} +
+ + {/* Desktop Sidebar */} + + + {/* Main Content */} +
+
+
+ +
+ +
+ {children} +
+
+
+ ); +} diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx new file mode 100644 index 0000000..88ef473 --- /dev/null +++ b/src/components/PageHeader.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +interface PageHeaderProps { + title: string; + description: string; + tag?: string; +} + +export default function PageHeader({ title, description, tag }: PageHeaderProps) { + return ( +
+ {tag && ( +
+ {tag} +
+ )} +

+ {title} +

+

+ {description} +

+
+ ); +} \ No newline at end of file diff --git a/src/components/PursuitCard.tsx b/src/components/PursuitCard.tsx new file mode 100644 index 0000000..48ecc29 --- /dev/null +++ b/src/components/PursuitCard.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import { motion } from "motion/react"; + +interface PursuitCardProps { + name: string; + description: string; + icon: React.ReactNode; + color?: "primary" | "secondary" | "tertiary"; +} + +const colorConfig = { + primary: { + bg: "bg-primary-fixed/40", + border: "border-primary-container/20", + icon: "text-primary-container", + badge: "bg-primary-container/10 text-primary", + }, + secondary: { + bg: "bg-secondary-fixed/40", + border: "border-secondary-container/20", + icon: "text-secondary-container", + badge: "bg-secondary-container/10 text-secondary", + }, + tertiary: { + bg: "bg-tertiary-fixed/40", + border: "border-tertiary-container/20", + icon: "text-tertiary-container", + badge: "bg-tertiary-container/10 text-tertiary", + }, +}; + +export default function PursuitCard({ + name, + description, + icon, + color = "primary", +}: PursuitCardProps) { + const c = colorConfig[color]; + + return ( + +
+
+ {icon} +
+
+

{name}

+

{description}

+
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/PursuitHero.tsx b/src/components/PursuitHero.tsx new file mode 100644 index 0000000..72d6feb --- /dev/null +++ b/src/components/PursuitHero.tsx @@ -0,0 +1,23 @@ +import React from "react"; + +interface PursuitHeroProps { + title: string; + description: string; + icon: React.ReactNode; +} + +export default function PursuitHero({ title, description, icon }: PursuitHeroProps) { + return ( +
+
+
+ {icon} +
+

+ {title} +

+
+

{description}

+
+ ); +} \ No newline at end of file diff --git a/src/components/SectionCard.tsx b/src/components/SectionCard.tsx new file mode 100644 index 0000000..ab3307f --- /dev/null +++ b/src/components/SectionCard.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import { motion } from "motion/react"; +import { ArrowUpRight } from "lucide-react"; + +interface SectionCardProps { + title: string; + children: React.ReactNode; + icon?: React.ReactNode; + action?: { label: string; href: string }; +} + +export default function SectionCard({ title, children, icon, action }: SectionCardProps) { + return ( + +
+
+ {icon &&
{icon}
} +

{title}

+
+ {action && ( + + {action.label} + + + )} +
+
+ {children} +
+
+ ); +} \ No newline at end of file diff --git a/src/components/StatBadge.tsx b/src/components/StatBadge.tsx new file mode 100644 index 0000000..cd2341f --- /dev/null +++ b/src/components/StatBadge.tsx @@ -0,0 +1,22 @@ +import React from "react"; + +interface StatBadgeProps { + label: string; + value: string | number; + color?: "primary" | "secondary" | "tertiary"; +} + +const colorMap = { + primary: "bg-primary-fixed/40 text-primary border-primary-container/20", + secondary: "bg-secondary-fixed/40 text-secondary border-secondary-container/20", + tertiary: "bg-tertiary-fixed/40 text-tertiary border-tertiary-container/20", +}; + +export default function StatBadge({ label, value, color = "primary" }: StatBadgeProps) { + return ( +
+
{value}
+
{label}
+
+ ); +} \ No newline at end of file diff --git a/src/data/navItems.ts b/src/data/navItems.ts new file mode 100644 index 0000000..c0c54bc --- /dev/null +++ b/src/data/navItems.ts @@ -0,0 +1,40 @@ +import { + LayoutDashboard, + Heart, + Bot, + Mail, +} from "lucide-react"; + +export interface NavItem { + path: string; + icon: typeof LayoutDashboard; + label: string; + children?: { path: string; label: string }[]; +} + +export const navItems: NavItem[] = [ + { path: "/", icon: LayoutDashboard, label: "Home" }, + { + path: "/interests", + icon: Heart, + label: "Interests", + children: [ + { path: "/interests/camping", label: "Camping" }, + { path: "/interests/skiing", label: "Skiing" }, + { path: "/interests/hiking", label: "Hiking" }, + { path: "/interests/canoeing", label: "Canoeing" }, + { path: "/interests/surfing", label: "Surfing" }, + { path: "/interests/music", label: "Music" }, + { path: "/interests/fine-art", label: "Fine Art" }, + { path: "/interests/philosophy", label: "Philosophy" }, + { path: "/interests/reading", label: "Reading" }, + { path: "/interests/cooking", label: "Cooking" }, + { path: "/interests/gardening", label: "Gardening" }, + { path: "/interests/food-production", label: "Food Production" }, + { path: "/interests/italy-travel", label: "Italy Travel" }, + { path: "/interests/global-politics", label: "Global Politics" }, + ], + }, + { path: "/ai-chat", icon: Bot, label: "AI Chat" }, + { path: "/contact", icon: Mail, label: "Contact" }, +]; \ No newline at end of file diff --git a/src/data/pursuitsData.ts b/src/data/pursuitsData.ts new file mode 100644 index 0000000..5e14adc --- /dev/null +++ b/src/data/pursuitsData.ts @@ -0,0 +1,933 @@ +import React from "react"; +import { + Music, Palette, BookOpen, Mountain, Tent, Sailboat, Waves, Map, + Globe, CookingPot, Sprout, Utensils, Plane, Backpack, Compass, + Guitar, Mic, Headphones, Calendar, CheckSquare, Image, Type, List, +} from "lucide-react"; + +export type ContentBlockType = "text" | "timeline" | "checklist" | "cards" | "gallery" | "list"; + +export interface TimelineItem { + date: string; + title: string; + description: string; + status?: "completed" | "upcoming" | "planning"; +} + +export interface ChecklistItem { + label: string; + checked: boolean; + category?: string; +} + +export interface CardItem { + title: string; + description: string; + color?: string; +} + +export interface GalleryItem { + title: string; + color: string; +} + +export interface ContentBlock { + type: ContentBlockType; + title?: string; + paragraphs?: string[]; + timelineItems?: TimelineItem[]; + checklistItems?: ChecklistItem[]; + cardItems?: CardItem[]; + galleryItems?: GalleryItem[]; + listItems?: string[]; +} + +export interface Section { + id: string; + title: string; + icon: React.ReactNode; + blocks: ContentBlock[]; +} + +export interface Pursuit { + slug: string; + title: string; + description: string; + icon: React.ReactNode; + color: "primary" | "secondary" | "tertiary"; + sections: Section[]; +} + +export const pursuits: Pursuit[] = [ + { + slug: "camping", + title: "Camping", + description: "Weekend camping trips and multi-day expeditions. Bushcraft and outdoor living skills.", + icon: React.createElement(Tent, { size: 24 }), + color: "tertiary", + sections: [ + { + id: "trips", + title: "Trips", + icon: React.createElement(Calendar, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024-11", title: "Blue Mountains Base Camp", description: "3-day hike-in camping at Govetts Leap. Explored waterfalls and rock formations.", status: "completed" }, + { date: "2024-08", title: "Kangaroo Valley Riverside", description: "Weekend riverside camping with kayaking. Perfect weather and star gazing.", status: "completed" }, + { date: "2025-03", title: "Barrington Tops Adventure", description: "Planning a 5-day backcountry expedition. Route mapped via topographic guides.", status: "planning" }, + { date: "2025-06", title: "Jervis Bay Coastal", description: "Beachfront camping planned for winter. Whale watching season.", status: "upcoming" }, + ], + }, + ], + }, + { + id: "gear", + title: "Gear", + icon: React.createElement(Backpack, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "4-season tent (MSR Hubba Hubba)", checked: true, category: "Shelter" }, + { label: "Sleeping bag (-10°C rated)", checked: true, category: "Sleep" }, + { label: "Inflatable sleeping pad", checked: true, category: "Sleep" }, + { label: "Jetboil stove system", checked: true, category: "Cooking" }, + { label: "Titanium cookware set", checked: false, category: "Cooking" }, + { label: "Water filter (Sawyer Squeeze)", checked: true, category: "Hydration" }, + { label: "Headlamp + backup", checked: true, category: "Lighting" }, + { label: "GPS device + maps", checked: true, category: "Navigation" }, + { label: "First aid kit", checked: true, category: "Safety" }, + { label: "Multi-tool", checked: true, category: "Tools" }, + { label: "Camp chair (Helinox)", checked: false, category: "Comfort" }, + { label: "Solar panel charger", checked: false, category: "Electronics" }, + ], + }, + ], + }, + { + id: "albums", + title: "Albums", + icon: React.createElement(Image, { size: 18 }), + blocks: [ + { + type: "gallery", + galleryItems: [ + { title: "Blue Mountains Sunrise", color: "#7FB3D5" }, + { title: "Valley Fog Morning", color: "#A2D9D1" }, + { title: "Campfire Cooking", color: "#F5B041" }, + { title: "Starry Night Tent", color: "#5D6D7E" }, + { title: "River Crossing", color: "#85C1E2" }, + { title: "Mountain Vista", color: "#A9DFBF" }, + ], + }, + ], + }, + ], + }, + { + slug: "skiing", + title: "Skiing", + description: "Alpine and backcountry skiing. Annual trips to Italy and local resorts.", + icon: React.createElement(Mountain, { size: 24 }), + color: "primary", + sections: [ + { + id: "trips", + title: "Trips", + icon: React.createElement(Calendar, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024-01", title: "Dolomites Super Ski", description: "10-day trip across Sella Ronda. 800km of linked slopes.", status: "completed" }, + { date: "2023-12", title: "Perisher Blue Cow", description: "Weekend powder chasing in NSW Snowy Mountains. Fresh 30cm overnight.", status: "completed" }, + { date: "2025-01", title: "Zermatt Matterhorn", description: "Planning Switzerland trip. Highest summer skiing in Europe.", status: "planning" }, + ], + }, + ], + }, + { + id: "gear", + title: "Gear", + icon: React.createElement(Backpack, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "All-mountain skis (Volkl)", checked: true, category: "Skis" }, + { label: "Ski boots (Lange)", checked: true, category: "Boots" }, + { label: "Helmet with visor", checked: true, category: "Safety" }, + { label: "Goggles (photochromic)", checked: true, category: "Safety" }, + { label: "Gore-Tex jacket", checked: true, category: "Clothing" }, + { label: "Insulated pants", checked: true, category: "Clothing" }, + { label: "Avalanche beacon", checked: false, category: "Safety" }, + { label: "Ski touring bindings", checked: false, category: "Skis" }, + ], + }, + ], + }, + { + id: "resorts", + title: "Resorts", + icon: React.createElement(Map, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Dolomiti Superski", description: "Italy - 1,200km of slopes across 12 ski areas", color: "#C0392B" }, + { title: "Perisher", description: "Australia - Largest resort in Southern Hemisphere", color: "#2980B9" }, + { title: "Zermatt", description: "Switzerland - Ski under the Matterhorn year-round", color: "#8E44AD" }, + { title: "Thredbo", description: "Australia - Longest runs and best terrain parks", color: "#27AE60" }, + { title: "Val d'Isère", description: "France - High-altitude resort with glacier skiing", color: "#D35400" }, + { title: "Niseko", description: "Japan - Best powder snow in the world", color: "#16A085" }, + ], + }, + ], + }, + ], + }, + { + slug: "hiking", + title: "Hiking", + description: "Trail hiking through national parks and wilderness areas. Day hikes and multi-day treks.", + icon: React.createElement(Map, { size: 24 }), + color: "secondary", + sections: [ + { + id: "trails", + title: "Trails", + icon: React.createElement(Compass, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024-10", title: "Six Foot Track", description: "44km historic trail through Blue Mountains. 3-day trek.", status: "completed" }, + { date: "2024-05", title: "Royal National Park", description: "Coastal track from Bundeena to Otford. 26km day hike.", status: "completed" }, + { date: "2025-04", title: "Overland Track", description: "Planning Tasmania's 65km iconic trek. Cradle Mountain to Lake St Clair.", status: "planning" }, + ], + }, + ], + }, + { + id: "gear", + title: "Gear", + icon: React.createElement(Backpack, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "Hiking boots (Salomon)", checked: true, category: "Footwear" }, + { label: "Daypack 32L", checked: true, category: "Bags" }, + { label: "Trekking poles", checked: true, category: "Accessories" }, + { label: "Hydration bladder 3L", checked: true, category: "Hydration" }, + { label: "Rain jacket (packable)", checked: true, category: "Clothing" }, + { label: "Merino base layers", checked: true, category: "Clothing" }, + { label: "GPS watch (Garmin)", checked: false, category: "Electronics" }, + ], + }, + ], + }, + { + id: "albums", + title: "Albums", + icon: React.createElement(Image, { size: 18 }), + blocks: [ + { + type: "gallery", + galleryItems: [ + { title: "Summit Views", color: "#85C1E2" }, + { title: "Forest Path", color: "#A9DFBF" }, + { title: "Coastal Cliffs", color: "#F5B041" }, + { title: "Waterfall Base", color: "#5D6D7E" }, + { title: "Wildflowers", color: "#D7BDE2" }, + { title: "Mountain Lake", color: "#7FB3D5" }, + ], + }, + ], + }, + ], + }, + { + slug: "canoeing", + title: "Canoeing", + description: "River and lake canoeing. Flatwater and gentle whitewater routes.", + icon: React.createElement(Sailboat, { size: 24 }), + color: "tertiary", + sections: [ + { + id: "trips", + title: "Trips", + icon: React.createElement(Calendar, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024-09", title: "Shoalhaven River", description: "2-day paddle from Bundanon to Nowra. 35km of pristine river.", status: "completed" }, + { date: "2024-04", title: "Lane Cove National Park", description: "Day paddle through Sydney's hidden waterway. Saw water dragons.", status: "completed" }, + { date: "2025-02", title: "Murray River Expedition", description: "Planning 5-day Murray River section. Camping on sandbars.", status: "planning" }, + ], + }, + ], + }, + { + id: "gear", + title: "Gear", + icon: React.createElement(Backpack, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "Canadian canoe", checked: true, category: "Boat" }, + { label: "Carbon fiber paddles", checked: true, category: "Paddles" }, + { label: "PFD (life jacket)", checked: true, category: "Safety" }, + { label: "Dry bags (various sizes)", checked: true, category: "Storage" }, + { label: "Spray deck", checked: false, category: "Accessories" }, + { label: "Portable bilge pump", checked: true, category: "Safety" }, + ], + }, + ], + }, + { + id: "routes", + title: "Routes", + icon: React.createElement(Map, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Shoalhaven River", description: "NSW - 35km of flatwater through national park", color: "#2980B9" }, + { title: "Lane Cove", description: "Sydney - Urban wilderness paddle, easy access", color: "#27AE60" }, + { title: "Murray River", description: "VIC/NSW - Australia's longest river, multi-day trips", color: "#D35400" }, + { title: "Hawkesbury River", description: "NSW - Coastal estuary with campsites", color: "#8E44AD" }, + ], + }, + ], + }, + ], + }, + { + slug: "surfing", + title: "Surfing", + description: "Chasing waves along the coast. Longboard and shortboard riding.", + icon: React.createElement(Waves, { size: 24 }), + color: "secondary", + sections: [ + { + id: "trips", + title: "Trips", + icon: React.createElement(Calendar, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024-07", title: "Byron Bay Winter Swell", description: "Chasing 6ft+ swells at The Pass. Water was chilly but worth it.", status: "completed" }, + { date: "2024-02", title: "Bells Beach Road Trip", description: "Great Ocean Road surf safari. 5 days of waves and coastal camping.", status: "completed" }, + { date: "2025-08", title: "Indonesia Boat Trip", description: "Planning Mentawai Islands surf charter. 10 days of perfection.", status: "upcoming" }, + ], + }, + ], + }, + { + id: "gear", + title: "Gear", + icon: React.createElement(Backpack, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "7'6 funboard", checked: true, category: "Boards" }, + { label: "9'0 longboard", checked: true, category: "Boards" }, + { label: "3/2mm wetsuit", checked: true, category: "Wetsuits" }, + { label: "5/4mm winter suit", checked: true, category: "Wetsuits" }, + { label: "Leash (competition)", checked: true, category: "Accessories" }, + { label: "Board bag (travel)", checked: true, category: "Storage" }, + { label: "Surf wax", checked: true, category: "Accessories" }, + { label: "Roof racks", checked: true, category: "Transport" }, + ], + }, + ], + }, + { + id: "breaks", + title: "Breaks", + icon: React.createElement(Map, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "The Pass - Byron Bay", description: "Long peeling right-hand point break. Best at 4-6ft.", color: "#2980B9" }, + { title: "Bells Beach", description: "Victoria's iconic reef break. Home of the Rip Curl Pro.", color: "#C0392B" }, + { title: "Manly Beach", description: "Sydney's most consistent beach break. All skill levels.", color: "#27AE60" }, + { title: "Snapper Rocks", description: "Gold Coast super bank. World-class right-handers.", color: "#F39C12" }, + ], + }, + ], + }, + ], + }, + { + slug: "music", + title: "Music", + description: "Guitar playing, music production, and live performance. Building a home studio setup.", + icon: React.createElement(Music, { size: 24 }), + color: "primary", + sections: [ + { + id: "gigs", + title: "Gigs", + icon: React.createElement(Mic, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024-08", title: "The Lansdowne Hotel", description: "Acoustic set opening for local folk band. 45-minute set.", status: "completed" }, + { date: "2024-05", title: "Factory Theatre", description: "Band gig with full lineup. Sold out 200-capacity venue.", status: "completed" }, + { date: "2025-01", title: "Enmore Theatre", description: "Supporting act for touring indie band. Dream venue.", status: "upcoming" }, + ], + }, + ], + }, + { + id: "instruments", + title: "Instruments", + icon: React.createElement(Guitar, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Fender Stratocaster", description: "American Pro II. Main electric for gigs and recording.", color: "#C0392B" }, + { title: "Martin D-28", description: "Acoustic workhorse. Rich, balanced tone for folk and blues.", color: "#2980B9" }, + { title: "Fender Jazz Bass", description: "For recording sessions and band gigs when needed.", color: "#27AE60" }, + { title: "Korg Minilogue", description: "Analog synthesizer for production and sound design.", color: "#8E44AD" }, + ], + }, + ], + }, + { + id: "songs", + title: "Songs to Learn", + icon: React.createElement(CheckSquare, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "Blackbird - The Beatles", checked: true, category: "Acoustic" }, + { label: "Stairway to Heaven - Led Zeppelin", checked: false, category: "Classic Rock" }, + { label: "Neon - John Mayer", checked: false, category: "Fingerstyle" }, + { label: "Wish You Were Here - Pink Floyd", checked: true, category: "Classic Rock" }, + { label: "Dust in the Wind - Kansas", checked: false, category: "Fingerstyle" }, + { label: "Tears in Heaven - Eric Clapton", checked: true, category: "Acoustic" }, + { label: "Cannonball - Damien Rice", checked: false, category: "Contemporary" }, + ], + }, + ], + }, + ], + }, + { + slug: "fine-art", + title: "Fine Art", + description: "Painting, sketching, and digital art creation. Exploring various mediums from watercolor to acrylic.", + icon: React.createElement(Palette, { size: 24 }), + color: "secondary", + sections: [ + { + id: "mediums", + title: "Mediums", + icon: React.createElement(Palette, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Watercolor", description: "Transparent washes and wet-on-wet techniques. Winsor & Newton paints.", color: "#85C1E2" }, + { title: "Acrylic", description: "Bold colors and layering. Golden Heavy Body acrylics.", color: "#F5B041" }, + { title: "Charcoal Sketching", description: "Life drawing and gesture sketches. Nitram charcoal.", color: "#5D6D7E" }, + { title: "Digital Art", description: "Procreate on iPad Pro. Concept art and illustration.", color: "#D7BDE2" }, + ], + }, + ], + }, + { + id: "gallery", + title: "Gallery", + icon: React.createElement(Image, { size: 18 }), + blocks: [ + { + type: "gallery", + galleryItems: [ + { title: "Mountain Landscape", color: "#85C1E2" }, + { title: "Portrait Study", color: "#F5B041" }, + { title: "Still Life", color: "#A9DFBF" }, + { title: "Abstract Composition", color: "#D7BDE2" }, + { title: "Coastal Scene", color: "#5D6D7E" }, + { title: "Figure Drawing", color: "#C0392B" }, + ], + }, + ], + }, + { + id: "inspiration", + title: "Inspiration", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "Current Projects", + paragraphs: [ + "Working on a series of landscapes inspired by the Blue Mountains region. Focusing on capturing the interplay of light and shadow during golden hour.", + "Exploring portraiture in charcoal. Weekly life drawing sessions at the community art center. Challenging myself to capture gesture and expression in quick 5-minute sketches.", + "Digital illustration project: Creating a visual narrative of a fictional coastal town. Developing character designs and environmental concepts.", + ], + }, + ], + }, + ], + }, + { + slug: "philosophy", + title: "Philosophy", + description: "Deep exploration of stoicism, existentialism, and ethics. Reading and reflecting on life's big questions.", + icon: React.createElement(BookOpen, { size: 24 }), + color: "tertiary", + sections: [ + { + id: "reading", + title: "Reading List", + icon: React.createElement(BookOpen, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024", title: "Meditations - Marcus Aurelius", description: "Daily stoic reflections. Translated by Gregory Hays.", status: "completed" }, + { date: "2024", title: "Being and Nothingness - Sartre", description: "Existentialism explored. Heavy but rewarding read.", status: "completed" }, + { date: "2025", title: "The Republic - Plato", description: "Revisiting the classics. Focus on justice and the ideal state.", status: "planning" }, + { date: "2025", title: "Nicomachean Ethics - Aristotle", description: "Virtue ethics and the good life. Next on the reading list.", status: "upcoming" }, + ], + }, + ], + }, + { + id: "concepts", + title: "Key Concepts", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Stoicism", description: "Focus on what you can control. Amor fati - love of fate.", color: "#27AE60" }, + { title: "Existentialism", description: "Existence precedes essence. We create our own meaning.", color: "#2980B9" }, + { title: "Virtue Ethics", description: "Character over rules. Developing practical wisdom.", color: "#8E44AD" }, + { title: "Phenomenology", description: "Studying consciousness and lived experience.", color: "#D35400" }, + ], + }, + ], + }, + { + id: "reflections", + title: "Reflections", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "Recent Thoughts", + paragraphs: [ + "The tension between determinism and free will continues to fascinate me. Reading compatibilist perspectives has shifted my thinking on responsibility and choice.", + "Applying Stoic principles to modern life: The dichotomy of control is a powerful framework for reducing anxiety about uncertain outcomes.", + ], + }, + ], + }, + ], + }, + { + slug: "reading", + title: "Reading", + description: "Avid reader across fiction, non-fiction, and technical literature. Building a personal library.", + icon: React.createElement(BookOpen, { size: 24 }), + color: "primary", + sections: [ + { + id: "current", + title: "Currently Reading", + icon: React.createElement(BookOpen, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Dune - Frank Herbert", description: "Sci-fi epic. Political intrigue meets ecology. 60% complete.", color: "#D35400" }, + { title: "The Pragmatic Programmer", description: "Technical. Revisiting classic software development wisdom.", color: "#2980B9" }, + { title: "Sapiens - Yuval Noah Harari", description: "Non-fiction. History of humankind. Fascinating perspective.", color: "#27AE60" }, + ], + }, + ], + }, + { + id: "favorites", + title: "Favorites", + icon: React.createElement(List, { size: 18 }), + blocks: [ + { + type: "list", + listItems: [ + "1984 - George Orwell", + "The Great Gatsby - F. Scott Fitzgerald", + "Slaughterhouse-Five - Kurt Vonnegut", + "Neuromancer - William Gibson", + "The Catcher in the Rye - J.D. Salinger", + "Brave New World - Aldous Huxley", + "Fahrenheit 451 - Ray Bradbury", + ], + }, + ], + }, + { + id: "to-read", + title: "To Read", + icon: React.createElement(CheckSquare, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "Project Hail Mary - Andy Weir", checked: false, category: "Fiction" }, + { label: "The Three-Body Problem - Liu Cixin", checked: false, category: "Sci-Fi" }, + { label: "Atomic Habits - James Clear", checked: true, category: "Self-Help" }, + { label: "Thinking, Fast and Slow - Kahneman", checked: false, category: "Psychology" }, + { label: "Clean Code - Robert Martin", checked: true, category: "Technical" }, + { label: "The Design of Everyday Things - Norman", checked: false, category: "Design" }, + ], + }, + ], + }, + ], + }, + { + slug: "cooking", + title: "Cooking", + description: "From everyday meals to elaborate dinner parties. Exploring cuisines from around the world.", + icon: React.createElement(CookingPot, { size: 24 }), + color: "tertiary", + sections: [ + { + id: "recipes", + title: "Recipes", + icon: React.createElement(List, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Beef Bourguignon", description: "Classic French stew. Red wine braised beef with mushrooms.", color: "#C0392B" }, + { title: "Pad Thai", description: "Thai street food classic. Tamarind, peanuts, and fresh herbs.", color: "#F39C12" }, + { title: "Homemade Pasta", description: "Fresh egg pasta from scratch. Simple tomato basil sauce.", color: "#E74C3C" }, + { title: "Ramen", description: "Tonkotsu broth with chashu pork. 12-hour broth.", color: "#D35400" }, + ], + }, + ], + }, + { + id: "techniques", + title: "Techniques", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "Mastering the Basics", + paragraphs: [ + "Knife skills: Working on julienne and brunoise cuts. Speed and consistency improving with weekly practice.", + "Sourdough bread: Maintaining a 3-year-old starter. Experimenting with hydration levels and fermentation times.", + "Temperature control: Perfecting reverse-sear for steaks. Investing in a quality instant-read thermometer.", + ], + }, + ], + }, + { + id: "ingredients", + title: "Ingredients", + icon: React.createElement(List, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "Cold-pressed olive oil (Italian)", checked: true, category: "Pantry" }, + { label: "Maldon sea salt", checked: true, category: "Pantry" }, + { label: "Szechuan peppercorns", checked: true, category: "Spices" }, + { label: "Kombu and bonito flakes", checked: true, category: "Japanese" }, + { label: "00 Flour for pasta", checked: true, category: "Baking" }, + { label: "Aged balsamic vinegar", checked: false, category: "Pantry" }, + ], + }, + ], + }, + ], + }, + { + slug: "gardening", + title: "Gardening", + description: "Growing vegetables, herbs, and flowers. Sustainable and organic practices.", + icon: React.createElement(Sprout, { size: 24 }), + color: "secondary", + sections: [ + { + id: "plants", + title: "Plants", + icon: React.createElement(Sprout, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Tomatoes", description: " heirloom varieties. Brandywine and Cherokee Purple doing well.", color: "#E74C3C" }, + { title: "Herbs", description: "Basil, rosemary, thyme, and oregano. Mediterranean herb garden.", color: "#27AE60" }, + { title: "Native Flowers", description: "Banksias, grevilleas, and waratahs. Attracting local birds.", color: "#F39C12" }, + { title: "Leafy Greens", description: "Kale, spinach, and silverbeet. Year-round harvest.", color: "#2ECC71" }, + ], + }, + ], + }, + { + id: "seasons", + title: "Seasons", + icon: React.createElement(Calendar, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "Spring 2024", title: "Planting Season", description: "Started tomatoes, peppers, and basil from seed. Added compost.", status: "completed" }, + { date: "Summer 2024", title: "Peak Harvest", description: "Daily harvests of zucchini, cucumbers, and beans. Made preserves.", status: "completed" }, + { date: "Autumn 2025", title: "Winter Prep", description: "Planning garlic and onion planting. Building raised beds.", status: "planning" }, + ], + }, + ], + }, + { + id: "projects", + title: "Projects", + icon: React.createElement(CheckSquare, { size: 18 }), + blocks: [ + { + type: "checklist", + checklistItems: [ + { label: "Build compost system", checked: true, category: "Infrastructure" }, + { label: "Install drip irrigation", checked: true, category: "Infrastructure" }, + { label: "Construct raised beds", checked: false, category: "Infrastructure" }, + { label: "Build greenhouse", checked: false, category: "Infrastructure" }, + { label: "Start worm farm", checked: true, category: "Composting" }, + ], + }, + ], + }, + ], + }, + { + slug: "food-production", + title: "Food Production", + description: "Artisanal food crafting including homemade salami, cheese making, honey harvesting, and salt production.", + icon: React.createElement(Utensils, { size: 24 }), + color: "primary", + sections: [ + { + id: "salami", + title: "Salami", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "Charcuterie Journey", + paragraphs: [ + "Started with basic sopressa using pork shoulder and back fat. Cured for 6 weeks in a DIY curing chamber (converted wine fridge with humidity control).", + "Currently experimenting with finocchiona (fennel salami) and chorizo with smoked paprika. Learning the importance of proper fermentation temperature.", + ], + }, + { + type: "checklist", + checklistItems: [ + { label: "Sopressa (mild)", checked: true, category: "Completed" }, + { label: "Finocchiona (fennel)", checked: true, category: "Completed" }, + { label: "Chorizo (spicy)", checked: false, category: "In Progress" }, + { label: "Coppa (dry-cured pork)", checked: false, category: "Planned" }, + ], + }, + ], + }, + { + id: "cheese", + title: "Cheese", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "From Milk to Magic", + paragraphs: [ + "Began with fresh cheeses: ricotta and mozzarella. Simple 30-minute processes with immediate gratification.", + "Progressed to aged cheeses. First attempt at cheddar is aging (3 months so far). Learning about affinage and proper humidity.", + ], + }, + { + type: "checklist", + checklistItems: [ + { label: "Ricotta", checked: true, category: "Fresh" }, + { label: "Mozzarella", checked: true, category: "Fresh" }, + { label: "Haloumi", checked: true, category: "Fresh" }, + { label: "Cheddar (aging)", checked: false, category: "Aged" }, + { label: "Camembert", checked: false, category: "Aged" }, + ], + }, + ], + }, + { + id: "honey", + title: "Honey", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "Urban Beekeeping", + paragraphs: [ + "Two hives in the backyard. Harvested 15kg of wildflower honey in the first season.", + "Learning about colony management, pest control (varroa mites), and seasonal hive management.", + ], + }, + ], + }, + { + id: "salt", + title: "Salt", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "Sea Salt Harvesting", + paragraphs: [ + "Collecting seawater from pristine coastal locations. Evaporating in greenhouse trays.", + "First batch yielded beautiful flaky crystals. Experimenting with infused salts (rosemary, lemon, chili).", + ], + }, + ], + }, + ], + }, + { + slug: "italy-travel", + title: "Italy Travel", + description: "Regular visits to Italy for skiing, dining, and cultural exploration. Favorite restaurants and hidden gems.", + icon: React.createElement(Plane, { size: 24 }), + color: "secondary", + sections: [ + { + id: "trips", + title: "Trips", + icon: React.createElement(Calendar, { size: 18 }), + blocks: [ + { + type: "timeline", + timelineItems: [ + { date: "2024-01", title: "Dolomites Ski Trip", description: "10 days in Alta Badia and Cortina. Skiing the Sella Ronda circuit.", status: "completed" }, + { date: "2023-06", title: "Tuscany Road Trip", description: "Drove from Florence to Siena. Wine tasting in Chianti region.", status: "completed" }, + { date: "2025-01", title: "Dolomites Return", description: "Planning another ski trip. Adding Venice day trip.", status: "planning" }, + ], + }, + ], + }, + { + id: "restaurants", + title: "Restaurants", + icon: React.createElement(List, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "El Celler de Can Roca", description: "Girona, Spain - World-class dining. 3 Michelin stars.", color: "#C0392B" }, + { title: "Osteria Francescana", description: "Modena, Italy - Italian avant-garde cuisine.", color: "#2980B9" }, + { title: "Trattoria al Pompiere", description: "Verona, Italy - Traditional Veronese. Bollito misto specialty.", color: "#27AE60" }, + { title: "Rifugio Scotoni", description: "Dolomites - Mountain hut with stunning views. Wild game menu.", color: "#D35400" }, + ], + }, + ], + }, + { + id: "favorites", + title: "Favorites", + icon: React.createElement(List, { size: 18 }), + blocks: [ + { + type: "list", + listItems: [ + "Favorite Region: Trentino-Alto Adige", + "Best Coffee: Triestino style in Trieste", + "Must-Try Dish: Bollito misto with pearà sauce", + "Hidden Gem: Lago di Braies in early morning", + "Best Gelato: Perche No! in Florence", + "Favorite Market: Mercato di Mezzo in Bologna", + ], + }, + ], + }, + ], + }, + { + slug: "global-politics", + title: "Global Politics", + description: "Following international relations, political theory, and current events across multiple regions.", + icon: React.createElement(Globe, { size: 24 }), + color: "tertiary", + sections: [ + { + id: "regions", + title: "Regions", + icon: React.createElement(Map, { size: 18 }), + blocks: [ + { + type: "cards", + cardItems: [ + { title: "Europe", description: "EU dynamics, Brexit aftermath, and Eastern European politics.", color: "#2980B9" }, + { title: "Asia-Pacific", description: "China-US relations, ASEAN dynamics, and Indo-Pacific strategy.", color: "#C0392B" }, + { title: "Middle East", description: "Israel-Palestine conflict, Iran nuclear deal, and Gulf diplomacy.", color: "#27AE60" }, + { title: "Americas", description: "US domestic politics, Latin American shifts, and trade policy.", color: "#D35400" }, + ], + }, + ], + }, + { + id: "reading", + title: "Reading", + icon: React.createElement(BookOpen, { size: 18 }), + blocks: [ + { + type: "list", + listItems: [ + "The Economist - Weekly analysis", + "Foreign Affairs - Quarterly deep dives", + "The Atlantic - Long-form journalism", + "Al Jazeera - Alternative perspectives", + "Financial Times - Global economics", + ], + }, + ], + }, + { + id: "topics", + title: "Topics", + icon: React.createElement(Type, { size: 18 }), + blocks: [ + { + type: "text", + title: "Current Focus", + paragraphs: [ + "The shifting global order: Analyzing the transition from unipolar to multipolar world. Impact on trade, security, and diplomacy.", + "Climate politics: How environmental policy is reshaping international alliances and economic strategies.", + "Technology governance: AI regulation, digital sovereignty, and the politics of emerging technologies.", + ], + }, + ], + }, + ], + }, +]; + +export function getPursuitBySlug(slug: string): Pursuit | undefined { + return pursuits.find((p) => p.slug === slug); +} + +export function getAllPursuitSlugs(): string[] { + return pursuits.map((p) => p.slug); +} \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..2e5d621 --- /dev/null +++ b/src/index.css @@ -0,0 +1,93 @@ +@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Be+Vietnam+Pro:wght@400;500;600;700&display=swap'); +@import "tailwindcss"; + +@theme { + --font-display: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif; + --font-sans: "Be Vietnam Pro", ui-sans-serif, system-ui, sans-serif; + --font-mono: "Be Vietnam Pro", ui-monospace, SFMono-Regular, monospace; + + --color-surface: #fbf8ff; + --color-surface-dim: #d6d8f7; + --color-surface-bright: #fbf8ff; + --color-surface-container-lowest: #ffffff; + --color-surface-container-low: #f4f2ff; + --color-surface-container: #edecff; + --color-surface-container-high: #e6e6ff; + --color-surface-container-highest: #dfe0ff; + --color-on-surface: #171a31; + --color-on-surface-variant: #444653; + --color-inverse-surface: #2c2f47; + --color-inverse-on-surface: #f0efff; + --color-outline: #757685; + --color-outline-variant: #c5c5d6; + --color-surface-tint: #3d53c7; + + --color-primary: #3a50c4; + --color-on-primary: #ffffff; + --color-primary-container: #556adf; + --color-on-primary-container: #fffbff; + --color-inverse-primary: #bac3ff; + --color-primary-fixed: #dee0ff; + --color-primary-fixed-dim: #bac3ff; + --color-on-primary-fixed: #00105b; + --color-on-primary-fixed-variant: #2038ae; + + --color-secondary: #7923e0; + --color-on-secondary: #ffffff; + --color-secondary-container: #9347fa; + --color-on-secondary-container: #fffbff; + --color-secondary-fixed: #eddcff; + --color-secondary-fixed-dim: #d7baff; + --color-on-secondary-fixed: #280056; + --color-on-secondary-fixed-variant: #6100be; + + --color-tertiary: #00685f; + --color-on-tertiary: #ffffff; + --color-tertiary-container: #008379; + --color-on-tertiary-container: #f4fffc; + --color-tertiary-fixed: #8cf4e7; + --color-tertiary-fixed-dim: #6fd8cb; + --color-on-tertiary-fixed: #00201d; + --color-on-tertiary-fixed-variant: #005049; + + --color-error: #ba1a1a; + --color-on-error: #ffffff; + --color-error-container: #ffdad6; + --color-on-error-container: #93000a; + + --color-background: #fbf8ff; + --color-on-background: #171a31; + --color-surface-variant: #dfe0ff; +} + +@layer base { + body { + @apply bg-background text-on-background font-sans antialiased; + } + * { + scrollbar-width: thin; + scrollbar-color: var(--color-surface-container-highest) transparent; + } +} + +@layer utilities { + .glass { + background: color-mix(in srgb, var(--color-surface-container-high) 70%, transparent); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + } + .shadow-ambient { + box-shadow: 0 4px 20px color-mix(in srgb, var(--color-primary) 8%, transparent); + } + .shadow-ambient-lg { + box-shadow: 0 8px 32px color-mix(in srgb, var(--color-primary) 10%, transparent); + } + .ghost-border { + border: 1px solid var(--color-outline-variant); + } + .glow-primary { + box-shadow: 0 0 16px color-mix(in srgb, var(--color-primary) 15%, transparent); + } + .no-scrollbar::-webkit-scrollbar { display: none; } + .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; } +} \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..d8956f9 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import {StrictMode} from 'react'; +import {createRoot} from 'react-dom/client'; +import App from './App.tsx'; +import './index.css'; + +createRoot(document.getElementById('root')!).render( + + + , +); \ No newline at end of file diff --git a/src/pages/AiChat.tsx b/src/pages/AiChat.tsx new file mode 100644 index 0000000..2c7cd06 --- /dev/null +++ b/src/pages/AiChat.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import PageHeader from "../components/PageHeader"; +import AiChatBox from "../components/AiChatBox"; +import SectionCard from "../components/SectionCard"; +import { Sparkles, Cpu } from "lucide-react"; + +export default function AiChat() { + return ( +
+ + +
+
+ +
+ +
+ }> +

+ This AI assistant knows about all my pursuits and interests. Ask about music recommendations, book suggestions, hiking trails, or cooking tips. +

+
+ + }> +
+ {[ + "Recommend music based on taste", + "Suggest hiking trails and routes", + "Share cooking recipes and tips", + "Discuss philosophy and books", + "Plan travel itineraries", + "Advise on gear and equipment", + ].map((cap, i) => ( +
+ + {cap} +
+ ))} +
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/pages/Contact.tsx b/src/pages/Contact.tsx new file mode 100644 index 0000000..2002069 --- /dev/null +++ b/src/pages/Contact.tsx @@ -0,0 +1,97 @@ +import React, { useState } from "react"; +import { Mail, Send, ExternalLink, Globe } from "lucide-react"; +import PageHeader from "../components/PageHeader"; +import SectionCard from "../components/SectionCard"; +import ExternalLinkCard from "../components/ExternalLinkCard"; + +export default function Contact() { + const [submitted, setSubmitted] = useState(false); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setSubmitted(true); + }; + + return ( +
+ + +
+ }> + {submitted ? ( +
+
Message Sent!
+
Thanks for reaching out. I'll get back to you soon.
+
+ ) : ( +
+
+ + +
+
+ + +
+
+ +