Selaa lähdekoodia

feat: complete website overhaul with React/Vite, including new homepage design, i18n support (ZH/EN/JA), and Breakout game implementation

bob 5 kuukautta sitten
vanhempi
sitoutus
f1fbfa6ecf
17 muutettua tiedostoa jossa 1747 lisäystä ja 100 poistoa
  1. 8 8
      deploy.sh
  2. 10 1
      package.json
  3. 545 35
      pnpm-lock.yaml
  4. 6 0
      postcss.config.js
  5. 2 8
      src/App.css
  6. 11 24
      src/App.tsx
  7. 385 0
      src/NewHome.tsx
  8. 29 0
      src/OldHomeLayout.tsx
  9. 350 0
      src/components/BreakoutGame.tsx
  10. 69 0
      src/components/Logo.tsx
  11. 32 0
      src/i18n.ts
  12. 1 24
      src/index.css
  13. 96 0
      src/locales/en.json
  14. 96 0
      src/locales/ja.json
  15. 95 0
      src/locales/zh.json
  16. 1 0
      src/main.tsx
  17. 11 0
      tailwind.config.js

+ 8 - 8
deploy.sh

@@ -12,9 +12,9 @@ NC='\033[0m'
 
 echo -e "${GREEN}开始部署流程...${NC}"
 
-# 1. 本地构建 (Static Site Generation)
-echo -e "${GREEN}正在执行本地构建 (npm run generate)...${NC}"
-npm run generate
+# 1. 本地构建 (Vite Build)
+echo -e "${GREEN}正在执行本地构建 (npm run build)...${NC}"
+npm run build
 
 if [ $? -ne 0 ]; then
     echo "构建失败,请检查错误信息"
@@ -23,14 +23,14 @@ fi
 
 # 2. 压缩构建产物
 echo -e "${GREEN}正在打包构建产物...${NC}"
-if [ -d ".output/public" ]; then
-    cd .output/public
+if [ -d "dist" ]; then
+    cd dist
     # 打包所有文件到 release.tar.gz
-    tar -czf ../../release.tar.gz .
-    cd ../..
+    tar -czf ../release.tar.gz .
+    cd ..
     echo "打包完成: release.tar.gz"
 else
-    echo "错误: 未找到 .output/public 目录"
+    echo "错误: 未找到 dist 目录"
     exit 1
 fi
 

+ 10 - 1
package.json

@@ -10,11 +10,20 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "autoprefixer": "^10.4.23",
+    "i18next": "^25.8.0",
+    "i18next-browser-languagedetector": "^8.2.0",
+    "lucide-react": "^0.563.0",
+    "postcss": "^8.5.6",
     "react": "^19.2.0",
-    "react-dom": "^19.2.0"
+    "react-dom": "^19.2.0",
+    "react-i18next": "^16.5.4",
+    "react-router-dom": "^7.13.0",
+    "tailwindcss": "^4.1.18"
   },
   "devDependencies": {
     "@eslint/js": "^9.39.1",
+    "@tailwindcss/postcss": "^4.1.18",
     "@types/node": "^24.10.1",
     "@types/react": "^19.2.5",
     "@types/react-dom": "^19.2.3",

+ 545 - 35
pnpm-lock.yaml

@@ -8,16 +8,43 @@ importers:
 
   .:
     dependencies:
+      autoprefixer:
+        specifier: ^10.4.23
+        version: 10.4.23(postcss@8.5.6)
+      i18next:
+        specifier: ^25.8.0
+        version: 25.8.0(typescript@5.9.3)
+      i18next-browser-languagedetector:
+        specifier: ^8.2.0
+        version: 8.2.0
+      lucide-react:
+        specifier: ^0.563.0
+        version: 0.563.0(react@19.2.3)
+      postcss:
+        specifier: ^8.5.6
+        version: 8.5.6
       react:
         specifier: ^19.2.0
         version: 19.2.3
       react-dom:
         specifier: ^19.2.0
         version: 19.2.3(react@19.2.3)
+      react-i18next:
+        specifier: ^16.5.4
+        version: 16.5.4(i18next@25.8.0(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)
+      react-router-dom:
+        specifier: ^7.13.0
+        version: 7.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+      tailwindcss:
+        specifier: ^4.1.18
+        version: 4.1.18
     devDependencies:
       '@eslint/js':
         specifier: ^9.39.1
         version: 9.39.2
+      '@tailwindcss/postcss':
+        specifier: ^4.1.18
+        version: 4.1.18
       '@types/node':
         specifier: ^24.10.1
         version: 24.10.9
@@ -29,16 +56,16 @@ importers:
         version: 19.2.3(@types/react@19.2.8)
       '@vitejs/plugin-react':
         specifier: ^5.1.1
-        version: 5.1.2(vite@7.3.1(@types/node@24.10.9))
+        version: 5.1.2(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2))
       eslint:
         specifier: ^9.39.1
-        version: 9.39.2
+        version: 9.39.2(jiti@2.6.1)
       eslint-plugin-react-hooks:
         specifier: ^7.0.1
-        version: 7.0.1(eslint@9.39.2)
+        version: 7.0.1(eslint@9.39.2(jiti@2.6.1))
       eslint-plugin-react-refresh:
         specifier: ^0.4.24
-        version: 0.4.26(eslint@9.39.2)
+        version: 0.4.26(eslint@9.39.2(jiti@2.6.1))
       globals:
         specifier: ^16.5.0
         version: 16.5.0
@@ -47,13 +74,17 @@ importers:
         version: 5.9.3
       typescript-eslint:
         specifier: ^8.46.4
-        version: 8.53.0(eslint@9.39.2)(typescript@5.9.3)
+        version: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
       vite:
         specifier: ^7.2.4
-        version: 7.3.1(@types/node@24.10.9)
+        version: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)
 
 packages:
 
+  '@alloc/quick-lru@5.2.0':
+    resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+    engines: {node: '>=10'}
+
   '@babel/code-frame@7.28.6':
     resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==}
     engines: {node: '>=6.9.0'}
@@ -125,6 +156,10 @@ packages:
     peerDependencies:
       '@babel/core': ^7.0.0-0
 
+  '@babel/runtime@7.28.6':
+    resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
+    engines: {node: '>=6.9.0'}
+
   '@babel/template@7.28.6':
     resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
     engines: {node: '>=6.9.0'}
@@ -491,6 +526,94 @@ packages:
     cpu: [x64]
     os: [win32]
 
+  '@tailwindcss/node@4.1.18':
+    resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
+
+  '@tailwindcss/oxide-android-arm64@4.1.18':
+    resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [android]
+
+  '@tailwindcss/oxide-darwin-arm64@4.1.18':
+    resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@tailwindcss/oxide-darwin-x64@4.1.18':
+    resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@tailwindcss/oxide-freebsd-x64@4.1.18':
+    resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
+    resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==}
+    engines: {node: '>= 10'}
+    cpu: [arm]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
+    resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
+    resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
+    resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-x64-musl@4.1.18':
+    resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@tailwindcss/oxide-wasm32-wasi@4.1.18':
+    resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
+    engines: {node: '>=14.0.0'}
+    cpu: [wasm32]
+    bundledDependencies:
+      - '@napi-rs/wasm-runtime'
+      - '@emnapi/core'
+      - '@emnapi/runtime'
+      - '@tybys/wasm-util'
+      - '@emnapi/wasi-threads'
+      - tslib
+
+  '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
+    resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
+    resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [win32]
+
+  '@tailwindcss/oxide@4.1.18':
+    resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==}
+    engines: {node: '>= 10'}
+
+  '@tailwindcss/postcss@4.1.18':
+    resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==}
+
   '@types/babel__core@7.20.5':
     resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
 
@@ -605,6 +728,13 @@ packages:
   argparse@2.0.1:
     resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
 
+  autoprefixer@10.4.23:
+    resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==}
+    engines: {node: ^10 || ^12 || >=14}
+    hasBin: true
+    peerDependencies:
+      postcss: ^8.1.0
+
   balanced-match@1.0.2:
     resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
 
@@ -647,6 +777,10 @@ packages:
   convert-source-map@2.0.0:
     resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
 
+  cookie@1.1.1:
+    resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
+    engines: {node: '>=18'}
+
   cross-spawn@7.0.6:
     resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
     engines: {node: '>= 8'}
@@ -666,9 +800,17 @@ packages:
   deep-is@0.1.4:
     resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
 
+  detect-libc@2.1.2:
+    resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+    engines: {node: '>=8'}
+
   electron-to-chromium@1.5.267:
     resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
 
+  enhanced-resolve@5.18.4:
+    resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
+    engines: {node: '>=10.13.0'}
+
   esbuild@0.27.2:
     resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
     engines: {node: '>=18'}
@@ -768,6 +910,9 @@ packages:
   flatted@3.3.3:
     resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
 
+  fraction.js@5.3.4:
+    resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
+
   fsevents@2.3.3:
     resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
     engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -789,6 +934,9 @@ packages:
     resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==}
     engines: {node: '>=18'}
 
+  graceful-fs@4.2.11:
+    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
   has-flag@4.0.0:
     resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
     engines: {node: '>=8'}
@@ -799,6 +947,20 @@ packages:
   hermes-parser@0.25.1:
     resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
 
+  html-parse-stringify@3.0.1:
+    resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
+
+  i18next-browser-languagedetector@8.2.0:
+    resolution: {integrity: sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==}
+
+  i18next@25.8.0:
+    resolution: {integrity: sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==}
+    peerDependencies:
+      typescript: ^5
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
   ignore@5.3.2:
     resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
     engines: {node: '>= 4'}
@@ -826,6 +988,10 @@ packages:
   isexe@2.0.0:
     resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
 
+  jiti@2.6.1:
+    resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+    hasBin: true
+
   js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
 
@@ -859,6 +1025,76 @@ packages:
     resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
     engines: {node: '>= 0.8.0'}
 
+  lightningcss-android-arm64@1.30.2:
+    resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [android]
+
+  lightningcss-darwin-arm64@1.30.2:
+    resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [darwin]
+
+  lightningcss-darwin-x64@1.30.2:
+    resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [darwin]
+
+  lightningcss-freebsd-x64@1.30.2:
+    resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [freebsd]
+
+  lightningcss-linux-arm-gnueabihf@1.30.2:
+    resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm]
+    os: [linux]
+
+  lightningcss-linux-arm64-gnu@1.30.2:
+    resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  lightningcss-linux-arm64-musl@1.30.2:
+    resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  lightningcss-linux-x64-gnu@1.30.2:
+    resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  lightningcss-linux-x64-musl@1.30.2:
+    resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  lightningcss-win32-arm64-msvc@1.30.2:
+    resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [win32]
+
+  lightningcss-win32-x64-msvc@1.30.2:
+    resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [win32]
+
+  lightningcss@1.30.2:
+    resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
+    engines: {node: '>= 12.0.0'}
+
   locate-path@6.0.0:
     resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
     engines: {node: '>=10'}
@@ -869,6 +1105,14 @@ packages:
   lru-cache@5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
 
+  lucide-react@0.563.0:
+    resolution: {integrity: sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==}
+    peerDependencies:
+      react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+  magic-string@0.30.21:
+    resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
   minimatch@3.1.2:
     resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
 
@@ -921,6 +1165,9 @@ packages:
     resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
     engines: {node: '>=12'}
 
+  postcss-value-parser@4.2.0:
+    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
   postcss@8.5.6:
     resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
     engines: {node: ^10 || ^12 || >=14}
@@ -938,10 +1185,43 @@ packages:
     peerDependencies:
       react: ^19.2.3
 
+  react-i18next@16.5.4:
+    resolution: {integrity: sha512-6yj+dcfMncEC21QPhOTsW8mOSO+pzFmT6uvU7XXdvM/Cp38zJkmTeMeKmTrmCMD5ToT79FmiE/mRWiYWcJYW4g==}
+    peerDependencies:
+      i18next: '>= 25.6.2'
+      react: '>= 16.8.0'
+      react-dom: '*'
+      react-native: '*'
+      typescript: ^5
+    peerDependenciesMeta:
+      react-dom:
+        optional: true
+      react-native:
+        optional: true
+      typescript:
+        optional: true
+
   react-refresh@0.18.0:
     resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==}
     engines: {node: '>=0.10.0'}
 
+  react-router-dom@7.13.0:
+    resolution: {integrity: sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==}
+    engines: {node: '>=20.0.0'}
+    peerDependencies:
+      react: '>=18'
+      react-dom: '>=18'
+
+  react-router@7.13.0:
+    resolution: {integrity: sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==}
+    engines: {node: '>=20.0.0'}
+    peerDependencies:
+      react: '>=18'
+      react-dom: '>=18'
+    peerDependenciesMeta:
+      react-dom:
+        optional: true
+
   react@19.2.3:
     resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==}
     engines: {node: '>=0.10.0'}
@@ -967,6 +1247,9 @@ packages:
     engines: {node: '>=10'}
     hasBin: true
 
+  set-cookie-parser@2.7.2:
+    resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
+
   shebang-command@2.0.0:
     resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
     engines: {node: '>=8'}
@@ -987,6 +1270,13 @@ packages:
     resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
     engines: {node: '>=8'}
 
+  tailwindcss@4.1.18:
+    resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
+
+  tapable@2.3.0:
+    resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
+    engines: {node: '>=6'}
+
   tinyglobby@0.2.15:
     resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
     engines: {node: '>=12.0.0'}
@@ -1025,6 +1315,11 @@ packages:
   uri-js@4.4.1:
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
 
+  use-sync-external-store@1.6.0:
+    resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
   vite@7.3.1:
     resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
     engines: {node: ^20.19.0 || >=22.12.0}
@@ -1065,6 +1360,10 @@ packages:
       yaml:
         optional: true
 
+  void-elements@3.1.0:
+    resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
+    engines: {node: '>=0.10.0'}
+
   which@2.0.2:
     resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
     engines: {node: '>= 8'}
@@ -1092,6 +1391,8 @@ packages:
 
 snapshots:
 
+  '@alloc/quick-lru@5.2.0': {}
+
   '@babel/code-frame@7.28.6':
     dependencies:
       '@babel/helper-validator-identifier': 7.28.5
@@ -1181,6 +1482,8 @@ snapshots:
       '@babel/core': 7.28.6
       '@babel/helper-plugin-utils': 7.28.6
 
+  '@babel/runtime@7.28.6': {}
+
   '@babel/template@7.28.6':
     dependencies:
       '@babel/code-frame': 7.28.6
@@ -1282,9 +1585,9 @@ snapshots:
   '@esbuild/win32-x64@0.27.2':
     optional: true
 
-  '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2)':
+  '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))':
     dependencies:
-      eslint: 9.39.2
+      eslint: 9.39.2(jiti@2.6.1)
       eslint-visitor-keys: 3.4.3
 
   '@eslint-community/regexpp@4.12.2': {}
@@ -1435,6 +1738,75 @@ snapshots:
   '@rollup/rollup-win32-x64-msvc@4.55.1':
     optional: true
 
+  '@tailwindcss/node@4.1.18':
+    dependencies:
+      '@jridgewell/remapping': 2.3.5
+      enhanced-resolve: 5.18.4
+      jiti: 2.6.1
+      lightningcss: 1.30.2
+      magic-string: 0.30.21
+      source-map-js: 1.2.1
+      tailwindcss: 4.1.18
+
+  '@tailwindcss/oxide-android-arm64@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-darwin-arm64@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-darwin-x64@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-freebsd-x64@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-linux-x64-musl@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-wasm32-wasi@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
+    optional: true
+
+  '@tailwindcss/oxide@4.1.18':
+    optionalDependencies:
+      '@tailwindcss/oxide-android-arm64': 4.1.18
+      '@tailwindcss/oxide-darwin-arm64': 4.1.18
+      '@tailwindcss/oxide-darwin-x64': 4.1.18
+      '@tailwindcss/oxide-freebsd-x64': 4.1.18
+      '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18
+      '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18
+      '@tailwindcss/oxide-linux-arm64-musl': 4.1.18
+      '@tailwindcss/oxide-linux-x64-gnu': 4.1.18
+      '@tailwindcss/oxide-linux-x64-musl': 4.1.18
+      '@tailwindcss/oxide-wasm32-wasi': 4.1.18
+      '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
+      '@tailwindcss/oxide-win32-x64-msvc': 4.1.18
+
+  '@tailwindcss/postcss@4.1.18':
+    dependencies:
+      '@alloc/quick-lru': 5.2.0
+      '@tailwindcss/node': 4.1.18
+      '@tailwindcss/oxide': 4.1.18
+      postcss: 8.5.6
+      tailwindcss: 4.1.18
+
   '@types/babel__core@7.20.5':
     dependencies:
       '@babel/parser': 7.28.6
@@ -1472,15 +1844,15 @@ snapshots:
     dependencies:
       csstype: 3.2.3
 
-  '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)':
+  '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
     dependencies:
       '@eslint-community/regexpp': 4.12.2
-      '@typescript-eslint/parser': 8.53.0(eslint@9.39.2)(typescript@5.9.3)
+      '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
       '@typescript-eslint/scope-manager': 8.53.0
-      '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3)
-      '@typescript-eslint/utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3)
+      '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
+      '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
       '@typescript-eslint/visitor-keys': 8.53.0
-      eslint: 9.39.2
+      eslint: 9.39.2(jiti@2.6.1)
       ignore: 7.0.5
       natural-compare: 1.4.0
       ts-api-utils: 2.4.0(typescript@5.9.3)
@@ -1488,14 +1860,14 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3)':
+  '@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
     dependencies:
       '@typescript-eslint/scope-manager': 8.53.0
       '@typescript-eslint/types': 8.53.0
       '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3)
       '@typescript-eslint/visitor-keys': 8.53.0
       debug: 4.4.3
-      eslint: 9.39.2
+      eslint: 9.39.2(jiti@2.6.1)
       typescript: 5.9.3
     transitivePeerDependencies:
       - supports-color
@@ -1518,13 +1890,13 @@ snapshots:
     dependencies:
       typescript: 5.9.3
 
-  '@typescript-eslint/type-utils@8.53.0(eslint@9.39.2)(typescript@5.9.3)':
+  '@typescript-eslint/type-utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
     dependencies:
       '@typescript-eslint/types': 8.53.0
       '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3)
-      '@typescript-eslint/utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3)
+      '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
       debug: 4.4.3
-      eslint: 9.39.2
+      eslint: 9.39.2(jiti@2.6.1)
       ts-api-utils: 2.4.0(typescript@5.9.3)
       typescript: 5.9.3
     transitivePeerDependencies:
@@ -1547,13 +1919,13 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/utils@8.53.0(eslint@9.39.2)(typescript@5.9.3)':
+  '@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
     dependencies:
-      '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2)
+      '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
       '@typescript-eslint/scope-manager': 8.53.0
       '@typescript-eslint/types': 8.53.0
       '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3)
-      eslint: 9.39.2
+      eslint: 9.39.2(jiti@2.6.1)
       typescript: 5.9.3
     transitivePeerDependencies:
       - supports-color
@@ -1563,7 +1935,7 @@ snapshots:
       '@typescript-eslint/types': 8.53.0
       eslint-visitor-keys: 4.2.1
 
-  '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@24.10.9))':
+  '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2))':
     dependencies:
       '@babel/core': 7.28.6
       '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6)
@@ -1571,7 +1943,7 @@ snapshots:
       '@rolldown/pluginutils': 1.0.0-beta.53
       '@types/babel__core': 7.20.5
       react-refresh: 0.18.0
-      vite: 7.3.1(@types/node@24.10.9)
+      vite: 7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2)
     transitivePeerDependencies:
       - supports-color
 
@@ -1594,6 +1966,15 @@ snapshots:
 
   argparse@2.0.1: {}
 
+  autoprefixer@10.4.23(postcss@8.5.6):
+    dependencies:
+      browserslist: 4.28.1
+      caniuse-lite: 1.0.30001764
+      fraction.js: 5.3.4
+      picocolors: 1.1.1
+      postcss: 8.5.6
+      postcss-value-parser: 4.2.0
+
   balanced-match@1.0.2: {}
 
   baseline-browser-mapping@2.9.15: {}
@@ -1634,6 +2015,8 @@ snapshots:
 
   convert-source-map@2.0.0: {}
 
+  cookie@1.1.1: {}
+
   cross-spawn@7.0.6:
     dependencies:
       path-key: 3.1.1
@@ -1648,8 +2031,15 @@ snapshots:
 
   deep-is@0.1.4: {}
 
+  detect-libc@2.1.2: {}
+
   electron-to-chromium@1.5.267: {}
 
+  enhanced-resolve@5.18.4:
+    dependencies:
+      graceful-fs: 4.2.11
+      tapable: 2.3.0
+
   esbuild@0.27.2:
     optionalDependencies:
       '@esbuild/aix-ppc64': 0.27.2
@@ -1683,20 +2073,20 @@ snapshots:
 
   escape-string-regexp@4.0.0: {}
 
-  eslint-plugin-react-hooks@7.0.1(eslint@9.39.2):
+  eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)):
     dependencies:
       '@babel/core': 7.28.6
       '@babel/parser': 7.28.6
-      eslint: 9.39.2
+      eslint: 9.39.2(jiti@2.6.1)
       hermes-parser: 0.25.1
       zod: 4.3.5
       zod-validation-error: 4.0.2(zod@4.3.5)
     transitivePeerDependencies:
       - supports-color
 
-  eslint-plugin-react-refresh@0.4.26(eslint@9.39.2):
+  eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)):
     dependencies:
-      eslint: 9.39.2
+      eslint: 9.39.2(jiti@2.6.1)
 
   eslint-scope@8.4.0:
     dependencies:
@@ -1707,9 +2097,9 @@ snapshots:
 
   eslint-visitor-keys@4.2.1: {}
 
-  eslint@9.39.2:
+  eslint@9.39.2(jiti@2.6.1):
     dependencies:
-      '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2)
+      '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
       '@eslint-community/regexpp': 4.12.2
       '@eslint/config-array': 0.21.1
       '@eslint/config-helpers': 0.4.2
@@ -1743,6 +2133,8 @@ snapshots:
       minimatch: 3.1.2
       natural-compare: 1.4.0
       optionator: 0.9.4
+    optionalDependencies:
+      jiti: 2.6.1
     transitivePeerDependencies:
       - supports-color
 
@@ -1790,6 +2182,8 @@ snapshots:
 
   flatted@3.3.3: {}
 
+  fraction.js@5.3.4: {}
+
   fsevents@2.3.3:
     optional: true
 
@@ -1803,6 +2197,8 @@ snapshots:
 
   globals@16.5.0: {}
 
+  graceful-fs@4.2.11: {}
+
   has-flag@4.0.0: {}
 
   hermes-estree@0.25.1: {}
@@ -1811,6 +2207,20 @@ snapshots:
     dependencies:
       hermes-estree: 0.25.1
 
+  html-parse-stringify@3.0.1:
+    dependencies:
+      void-elements: 3.1.0
+
+  i18next-browser-languagedetector@8.2.0:
+    dependencies:
+      '@babel/runtime': 7.28.6
+
+  i18next@25.8.0(typescript@5.9.3):
+    dependencies:
+      '@babel/runtime': 7.28.6
+    optionalDependencies:
+      typescript: 5.9.3
+
   ignore@5.3.2: {}
 
   ignore@7.0.5: {}
@@ -1830,6 +2240,8 @@ snapshots:
 
   isexe@2.0.0: {}
 
+  jiti@2.6.1: {}
+
   js-tokens@4.0.0: {}
 
   js-yaml@4.1.1:
@@ -1855,6 +2267,55 @@ snapshots:
       prelude-ls: 1.2.1
       type-check: 0.4.0
 
+  lightningcss-android-arm64@1.30.2:
+    optional: true
+
+  lightningcss-darwin-arm64@1.30.2:
+    optional: true
+
+  lightningcss-darwin-x64@1.30.2:
+    optional: true
+
+  lightningcss-freebsd-x64@1.30.2:
+    optional: true
+
+  lightningcss-linux-arm-gnueabihf@1.30.2:
+    optional: true
+
+  lightningcss-linux-arm64-gnu@1.30.2:
+    optional: true
+
+  lightningcss-linux-arm64-musl@1.30.2:
+    optional: true
+
+  lightningcss-linux-x64-gnu@1.30.2:
+    optional: true
+
+  lightningcss-linux-x64-musl@1.30.2:
+    optional: true
+
+  lightningcss-win32-arm64-msvc@1.30.2:
+    optional: true
+
+  lightningcss-win32-x64-msvc@1.30.2:
+    optional: true
+
+  lightningcss@1.30.2:
+    dependencies:
+      detect-libc: 2.1.2
+    optionalDependencies:
+      lightningcss-android-arm64: 1.30.2
+      lightningcss-darwin-arm64: 1.30.2
+      lightningcss-darwin-x64: 1.30.2
+      lightningcss-freebsd-x64: 1.30.2
+      lightningcss-linux-arm-gnueabihf: 1.30.2
+      lightningcss-linux-arm64-gnu: 1.30.2
+      lightningcss-linux-arm64-musl: 1.30.2
+      lightningcss-linux-x64-gnu: 1.30.2
+      lightningcss-linux-x64-musl: 1.30.2
+      lightningcss-win32-arm64-msvc: 1.30.2
+      lightningcss-win32-x64-msvc: 1.30.2
+
   locate-path@6.0.0:
     dependencies:
       p-locate: 5.0.0
@@ -1865,6 +2326,14 @@ snapshots:
     dependencies:
       yallist: 3.1.1
 
+  lucide-react@0.563.0(react@19.2.3):
+    dependencies:
+      react: 19.2.3
+
+  magic-string@0.30.21:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.5
+
   minimatch@3.1.2:
     dependencies:
       brace-expansion: 1.1.12
@@ -1910,6 +2379,8 @@ snapshots:
 
   picomatch@4.0.3: {}
 
+  postcss-value-parser@4.2.0: {}
+
   postcss@8.5.6:
     dependencies:
       nanoid: 3.3.11
@@ -1925,8 +2396,33 @@ snapshots:
       react: 19.2.3
       scheduler: 0.27.0
 
+  react-i18next@16.5.4(i18next@25.8.0(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3):
+    dependencies:
+      '@babel/runtime': 7.28.6
+      html-parse-stringify: 3.0.1
+      i18next: 25.8.0(typescript@5.9.3)
+      react: 19.2.3
+      use-sync-external-store: 1.6.0(react@19.2.3)
+    optionalDependencies:
+      react-dom: 19.2.3(react@19.2.3)
+      typescript: 5.9.3
+
   react-refresh@0.18.0: {}
 
+  react-router-dom@7.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
+    dependencies:
+      react: 19.2.3
+      react-dom: 19.2.3(react@19.2.3)
+      react-router: 7.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+
+  react-router@7.13.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
+    dependencies:
+      cookie: 1.1.1
+      react: 19.2.3
+      set-cookie-parser: 2.7.2
+    optionalDependencies:
+      react-dom: 19.2.3(react@19.2.3)
+
   react@19.2.3: {}
 
   resolve-from@4.0.0: {}
@@ -1968,6 +2464,8 @@ snapshots:
 
   semver@7.7.3: {}
 
+  set-cookie-parser@2.7.2: {}
+
   shebang-command@2.0.0:
     dependencies:
       shebang-regex: 3.0.0
@@ -1982,6 +2480,10 @@ snapshots:
     dependencies:
       has-flag: 4.0.0
 
+  tailwindcss@4.1.18: {}
+
+  tapable@2.3.0: {}
+
   tinyglobby@0.2.15:
     dependencies:
       fdir: 6.5.0(picomatch@4.0.3)
@@ -1995,13 +2497,13 @@ snapshots:
     dependencies:
       prelude-ls: 1.2.1
 
-  typescript-eslint@8.53.0(eslint@9.39.2)(typescript@5.9.3):
+  typescript-eslint@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
     dependencies:
-      '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)
-      '@typescript-eslint/parser': 8.53.0(eslint@9.39.2)(typescript@5.9.3)
+      '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
+      '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
       '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3)
-      '@typescript-eslint/utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3)
-      eslint: 9.39.2
+      '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
+      eslint: 9.39.2(jiti@2.6.1)
       typescript: 5.9.3
     transitivePeerDependencies:
       - supports-color
@@ -2020,7 +2522,11 @@ snapshots:
     dependencies:
       punycode: 2.3.1
 
-  vite@7.3.1(@types/node@24.10.9):
+  use-sync-external-store@1.6.0(react@19.2.3):
+    dependencies:
+      react: 19.2.3
+
+  vite@7.3.1(@types/node@24.10.9)(jiti@2.6.1)(lightningcss@1.30.2):
     dependencies:
       esbuild: 0.27.2
       fdir: 6.5.0(picomatch@4.0.3)
@@ -2031,6 +2537,10 @@ snapshots:
     optionalDependencies:
       '@types/node': 24.10.9
       fsevents: 2.3.3
+      jiti: 2.6.1
+      lightningcss: 1.30.2
+
+  void-elements@3.1.0: {}
 
   which@2.0.2:
     dependencies:

+ 6 - 0
postcss.config.js

@@ -0,0 +1,6 @@
+export default {
+    plugins: {
+        "@tailwindcss/postcss": {},
+        autoprefixer: {},
+    },
+}

+ 2 - 8
src/App.css

@@ -1,15 +1,9 @@
 /* 全局样式和基本布局 */
-body {
+/* Body styles moved to .app-container to avoid global conflicts */
+.app-container {
   font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-  margin: 0;
-  display: flex;
-  flex-direction: column;
-  min-height: 100vh;
   color: #333;
   background-color: #fff;
-}
-
-.app-container {
   display: flex;
   flex-direction: column;
   min-height: 100vh;

+ 11 - 24
src/App.tsx

@@ -1,29 +1,16 @@
-import HomePage from './pages/HomePage';
-import './App.css';
+import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
+import NewHome from './NewHome';
+import OldHomeLayout from './OldHomeLayout';
 
 function App() {
-  const currentYear = new Date().getFullYear();
-
-  return (
-    <div className="app-container">
-      {/* 页头区域 */}
-      <header className="site-header">
-        <img src="/ccdw_logo_2025.5.png" alt="CCDW Logo" className="logo" />
-        <h1>CCDW = 纯粹的玩</h1>
-      </header>
-
-      {/* 主内容区域 */}
-      <main className="site-main">
-        <HomePage />
-      </main>
-
-      {/* 页脚区域 */}
-      <footer className="site-footer">
-        <p>&copy; {currentYear} CCDW (纯粹的玩). 不保留所有权利.</p>
-        <p>杭州纯粹的玩品牌科技有限公司 坐落于 浙江省杭州市西湖区转塘街道云腾丝路中心5号楼商业208室</p>
-      </footer>
-    </div>
-  );
+    return (
+        <Router>
+            <Routes>
+                <Route path="/" element={<NewHome />} />
+                <Route path="/old-home" element={<OldHomeLayout />} />
+            </Routes>
+        </Router>
+    );
 }
 
 export default App;

+ 385 - 0
src/NewHome.tsx

@@ -0,0 +1,385 @@
+import { useState, useEffect } from 'react';
+import {
+    Brain,
+    Database,
+    Zap,
+    ArrowRight,
+    CheckCircle,
+    Menu,
+    X,
+    Globe,
+    ChevronDown
+} from 'lucide-react';
+import BreakoutGame from './components/BreakoutGame';
+import Logo from './components/Logo';
+import { useTranslation } from 'react-i18next';
+
+const NewHome = () => {
+    const { t, i18n } = useTranslation();
+    const [isMenuOpen, setIsMenuOpen] = useState(false);
+    const [isLangDropdownOpen, setIsLangDropdownOpen] = useState(false);
+
+    // Language config
+    const languages = {
+        zh: { label: '中文', code: 'zh' },
+        en: { label: 'English', code: 'en' },
+        ja: { label: '日本語', code: 'ja' }
+    };
+
+    const currentLang = languages[i18n.language.split('-')[0] as keyof typeof languages] || languages.zh;
+
+    const changeLanguage = (lng: string) => {
+        i18n.changeLanguage(lng);
+        setIsLangDropdownOpen(false);
+        setIsMenuOpen(false);
+    };
+
+    const [scrolled, setScrolled] = useState(false);
+
+    // Handle scroll effect for navbar
+    useEffect(() => {
+        const handleScroll = () => {
+            setScrolled(window.scrollY > 50);
+        };
+        window.addEventListener('scroll', handleScroll);
+        return () => window.removeEventListener('scroll', handleScroll);
+    }, []);
+
+    const toggleMenu = () => setIsMenuOpen(!isMenuOpen);
+
+    return (
+        <div className="bg-[#0A192F] min-h-screen font-sans selection:bg-[#64FFDA] selection:text-[#0A192F] relative overflow-x-hidden">
+
+            {/* Navigation */}
+            <nav className={`fixed w-full z-50 transition-all duration-300 ${scrolled ? 'bg-[#0A192F]/90 backdrop-blur-md py-4 shadow-lg' : 'bg-transparent py-6'}`}>
+                <div className="max-w-7xl mx-auto px-6 flex justify-between items-center">
+                    <div className="flex items-center gap-2 cursor-pointer" onClick={() => window.location.href = '/'}>
+                        <Logo />
+                    </div>
+
+                    {/* Desktop Menu */}
+                    <div className="hidden md:flex items-center gap-8">
+                        <a href="#home" className="text-slate-300 hover:text-[#64FFDA] transition-colors text-sm font-medium">{t('nav.home')}</a>
+                        <a href="#services" className="text-slate-300 hover:text-[#64FFDA] transition-colors text-sm font-medium">{t('nav.services')}</a>
+                        <a href="#about" className="text-slate-300 hover:text-[#64FFDA] transition-colors text-sm font-medium">{t('nav.story')}</a>
+                        <a href="#contact" className="text-slate-300 hover:text-[#64FFDA] transition-colors text-sm font-medium">{t('nav.contact')}</a>
+
+                        {/* Language Switcher - Dropdown */}
+                        <div className="relative">
+                            <button
+                                onClick={() => setIsLangDropdownOpen(!isLangDropdownOpen)}
+                                className="flex items-center gap-2 text-xs font-mono text-slate-300 hover:text-[#64FFDA] transition-colors border border-slate-700 rounded px-3 py-2"
+                            >
+                                <Globe size={14} />
+                                <span>{currentLang.label}</span>
+                                <ChevronDown size={12} className={`transition-transform duration-200 ${isLangDropdownOpen ? 'rotate-180' : ''}`} />
+                            </button>
+
+                            {/* Dropdown Menu */}
+                            {isLangDropdownOpen && (
+                                <div className="absolute top-full right-0 mt-2 w-32 bg-[#112240] border border-[#233554] rounded shadow-xl py-1 flex flex-col z-50">
+                                    {Object.values(languages).map((lang) => (
+                                        <button
+                                            key={lang.code}
+                                            onClick={() => changeLanguage(lang.code)}
+                                            className={`w-full text-left px-4 py-2 text-xs font-mono hover:bg-[#233554] transition-colors ${i18n.language.startsWith(lang.code) ? 'text-[#64FFDA]' : 'text-slate-400'}`}
+                                        >
+                                            {lang.label}
+                                        </button>
+                                    ))}
+                                </div>
+                            )}
+                        </div>
+
+                        <button className="px-5 py-2 border border-[#64FFDA] text-[#64FFDA] rounded hover:bg-[#64FFDA]/10 transition-all text-sm font-medium">
+                            {t('nav.book')}
+                        </button>
+                    </div>
+
+                    {/* Mobile Menu Button */}
+                    <div className="flex items-center gap-4 md:hidden">
+                        <button className="text-white" onClick={toggleMenu}>
+                            {isMenuOpen ? <X /> : <Menu />}
+                        </button>
+                    </div>
+                </div>
+
+                {/* Mobile Menu Overlay */}
+                {
+                    isMenuOpen && (
+                        <div className="md:hidden absolute top-full left-0 w-full bg-[#112240] border-b border-[#233554] py-4 px-6 flex flex-col gap-4 shadow-xl">
+                            <a href="#home" className="block text-slate-300 hover:text-[#64FFDA]" onClick={toggleMenu}>{t('nav.home')}</a>
+                            <a href="#services" className="block text-slate-300 hover:text-[#64FFDA]" onClick={toggleMenu}>{t('nav.services')}</a>
+                            <a href="#about" className="block text-slate-300 hover:text-[#64FFDA]" onClick={toggleMenu}>{t('nav.story')}</a>
+
+                            {/* Mobile Language Selector (Simple Row for ease of use on mobile) */}
+                            <div className="flex items-center gap-4 py-2 border-t border-[#233554] mt-2 pt-4">
+                                <Globe size={16} className="text-slate-500" />
+                                <div className="flex gap-4">
+                                    {Object.values(languages).map((lang) => (
+                                        <button
+                                            key={lang.code}
+                                            onClick={() => changeLanguage(lang.code)}
+                                            className={`text-sm ${i18n.language.startsWith(lang.code) ? 'text-[#64FFDA] font-bold' : 'text-slate-400'}`}
+                                        >
+                                            {lang.label}
+                                        </button>
+                                    ))}
+                                </div>
+                            </div>
+
+                            <button className="w-full text-left text-[#64FFDA] font-medium mt-2">{t('nav.book')}</button>
+                        </div>
+                    )
+                }
+            </nav>
+
+            {/* Hero Section */}
+            <section id="home" className="relative pt-32 pb-20 md:pt-48 md:pb-32 px-6 overflow-hidden">
+                {/* Abstract Background Elements - Optimized removing heavy blur/pulse */}
+                <div className="absolute top-0 right-0 w-1/2 h-full bg-gradient-to-b from-[#112240] to-transparent opacity-50 -z-10 transform skew-x-12"></div>
+                {/* Replaced dynamic heavy blur with a static lighter gradient radial */}
+                <div className="absolute top-0 right-0 w-[500px] h-[500px] bg-[radial-gradient(circle_at_center,rgba(100,255,218,0.08)_0%,transparent_70%)] -z-10 pointer-events-none"></div>
+
+                <div className="max-w-7xl mx-auto grid md:grid-cols-2 gap-12 items-center">
+                    <div className="space-y-6">
+                        <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-[#64FFDA]/10 border border-[#64FFDA]/30 text-[#64FFDA] text-sm font-medium">
+                            <span className="w-2 h-2 rounded-full bg-[#64FFDA]"></span>
+                            {t('hero.badge')}
+                        </div>
+                        <h1 className="text-4xl md:text-6xl font-bold text-white leading-tight">
+                            {t('hero.title_prefix')}<span className="text-[#64FFDA]">{t('hero.title_highlight_1')}</span>{t('hero.title_middle')}<br />
+                            {t('hero.title_suffix')}<span className="text-[#64FFDA]">{t('hero.title_highlight_2')}</span>
+                        </h1>
+                        <p className="text-lg text-slate-400 max-w-xl leading-relaxed">
+                            {t('hero.subtitle')}
+                        </p>
+                        <div className="flex flex-col sm:flex-row gap-4 pt-4">
+                            <button className="px-8 py-4 bg-[#64FFDA] text-[#0A192F] font-bold rounded hover:bg-[#64FFDA]/90 transition-all flex items-center justify-center gap-2">
+                                {t('hero.btn_explore')} <ArrowRight size={20} />
+                            </button>
+                            <button className="px-8 py-4 border border-slate-600 text-white rounded hover:border-[#64FFDA] hover:text-[#64FFDA] transition-all">
+                                {t('hero.btn_philosophy')}
+                            </button>
+                        </div>
+
+                        <div className="pt-8 flex items-center gap-8 text-slate-500 text-sm">
+                            <div className="flex items-center gap-2">
+                                <CheckCircle size={16} className="text-[#64FFDA]" /> {t('hero.feature_1')}
+                            </div>
+                            <div className="flex items-center gap-2">
+                                <CheckCircle size={16} className="text-[#64FFDA]" /> {t('hero.feature_2')}
+                            </div>
+                        </div>
+                    </div>
+
+                    {/* Right Side Visual (Abstract Tech Illustration) */}
+                    <div className="relative hidden md:block">
+                        <div className="relative z-10 bg-[#112240] p-6 rounded-lg border border-[#233554] shadow-2xl transform rotate-3 hover:rotate-0 transition-all duration-500">
+                            <div className="flex items-center justify-between mb-4 border-b border-[#233554] pb-2">
+                                <div className="flex gap-2">
+                                    <div className="w-3 h-3 rounded-full bg-red-500"></div>
+                                    <div className="w-3 h-3 rounded-full bg-yellow-500"></div>
+                                    <div className="w-3 h-3 rounded-full bg-green-500"></div>
+                                </div>
+                                <div className="text-xs text-slate-500 font-mono">CCDW_Intelligence_Core.py</div>
+                            </div>
+                            <div className="space-y-3 font-mono text-sm">
+                                <div className="flex gap-2">
+                                    <span className="text-purple-400">import</span>
+                                    <span className="text-white">{t('code.import_1')}</span>
+                                    <span className="text-purple-400">as</span>
+                                    <span className="text-yellow-400">{t('code.as_1')}</span>
+                                </div>
+                                <div className="flex gap-2">
+                                    <span className="text-purple-400">import</span>
+                                    <span className="text-white">{t('code.import_2')}</span>
+                                    <span className="text-purple-400">as</span>
+                                    <span className="text-yellow-400">{t('code.as_2')}</span>
+                                </div>
+                                <div className="h-4"></div>
+                                <div className="text-slate-400">{t('code.comment')}</div>
+                                <div className="text-[#64FFDA]">
+                                    def future_of_work(): <br />
+                                    &nbsp;&nbsp; await {t('code.as_1')}.execute(all_boring_tasks) <br />
+                                    &nbsp;&nbsp; return {t('code.as_2')}.enjoy(creativity = True)
+                                </div>
+                                <div className="mt-4 p-3 bg-[#0A192F] rounded border-l-2 border-[#64FFDA] text-xs text-slate-300">
+                                    {t('code.efficiency')} <br />
+                                    {t('code.freedom')} <br />
+                                    {t('code.mode')}
+                                </div>
+                            </div>
+                        </div>
+                        {/* Background decorative box */}
+                        <div className="absolute top-4 left-4 w-full h-full border-2 border-[#64FFDA]/20 rounded-lg -z-10"></div>
+                    </div>
+                </div>
+            </section>
+
+            {/* Services Section */}
+            <section id="services" className="py-20 px-6 bg-[#112240]">
+                <div className="max-w-7xl mx-auto">
+                    <div className="text-center mb-16">
+                        <h2 className="text-3xl md:text-4xl font-bold text-white mb-4">{t('services.title')}</h2>
+                        <div className="w-16 h-1 bg-[#64FFDA] mx-auto rounded-full mb-4"></div>
+                        <p className="text-slate-400 max-w-2xl mx-auto">
+                            {t('services.subtitle')}
+                        </p>
+                    </div>
+
+                    <div className="grid md:grid-cols-3 gap-8">
+                        {/* Service 1 */}
+                        <div className="bg-[#0A192F] p-8 rounded-xl border border-[#233554] hover:border-[#64FFDA] transition-all group hover:-translate-y-2">
+                            <div className="w-14 h-14 bg-[#112240] rounded-lg flex items-center justify-center mb-6 group-hover:bg-[#64FFDA]/10 transition-colors">
+                                <Brain className="text-[#64FFDA] w-8 h-8" />
+                            </div>
+                            <h3 className="text-xl font-bold text-white mb-3">{t('services.card_1.title')}</h3>
+                            <p className="text-slate-400 text-sm leading-relaxed mb-6">
+                                {t('services.card_1.desc')}
+                            </p>
+                            <ul className="space-y-2 text-sm text-slate-500">
+                                <li className="flex items-center gap-2"><CheckCircle size={14} className="text-[#64FFDA]" /> {t('services.card_1.list_1')}</li>
+                                <li className="flex items-center gap-2"><CheckCircle size={14} className="text-[#64FFDA]" /> {t('services.card_1.list_2')}</li>
+                            </ul>
+                        </div>
+
+                        {/* Service 2 */}
+                        <div className="bg-[#0A192F] p-8 rounded-xl border border-[#233554] hover:border-[#64FFDA] transition-all group hover:-translate-y-2">
+                            <div className="w-14 h-14 bg-[#112240] rounded-lg flex items-center justify-center mb-6 group-hover:bg-[#64FFDA]/10 transition-colors">
+                                <Database className="text-[#64FFDA] w-8 h-8" />
+                            </div>
+                            <h3 className="text-xl font-bold text-white mb-3">{t('services.card_2.title')}</h3>
+                            <p className="text-slate-400 text-sm leading-relaxed mb-6">
+                                {t('services.card_2.desc')}
+                            </p>
+                            <ul className="space-y-2 text-sm text-slate-500">
+                                <li className="flex items-center gap-2"><CheckCircle size={14} className="text-[#64FFDA]" /> {t('services.card_2.list_1')}</li>
+                                <li className="flex items-center gap-2"><CheckCircle size={14} className="text-[#64FFDA]" /> {t('services.card_2.list_2')}</li>
+                            </ul>
+                        </div>
+
+                        {/* Service 3 */}
+                        <div className="bg-[#0A192F] p-8 rounded-xl border border-[#233554] hover:border-[#64FFDA] transition-all group hover:-translate-y-2">
+                            <div className="w-14 h-14 bg-[#112240] rounded-lg flex items-center justify-center mb-6 group-hover:bg-[#64FFDA]/10 transition-colors">
+                                <Zap className="text-[#64FFDA] w-8 h-8" />
+                            </div>
+                            <h3 className="text-xl font-bold text-white mb-3">{t('services.card_3.title')}</h3>
+                            <p className="text-slate-400 text-sm leading-relaxed mb-6">
+                                {t('services.card_3.desc')}
+                            </p>
+                            <ul className="space-y-2 text-sm text-slate-500">
+                                <li className="flex items-center gap-2"><CheckCircle size={14} className="text-[#64FFDA]" /> {t('services.card_3.list_1')}</li>
+                                <li className="flex items-center gap-2"><CheckCircle size={14} className="text-[#64FFDA]" /> {t('services.card_3.list_2')}</li>
+                            </ul>
+                        </div>
+                    </div>
+                </div>
+            </section>
+
+            {/* Brand Story Section */}
+            <section id="about" className="py-20 px-6 max-w-7xl mx-auto">
+                <div className="grid md:grid-cols-2 gap-16 items-center">
+                    <div className="relative">
+                        <div className="aspect-square rounded-2xl overflow-hidden bg-slate-800 relative group shadow-2xl border border-[#233554]">
+                            <BreakoutGame />
+                        </div>
+                    </div>
+
+                    <div>
+                        <span className="text-[#64FFDA] font-mono text-sm tracking-wider">{t('story.label')}</span>
+                        <h2 className="text-3xl md:text-4xl font-bold text-white mt-4 mb-6">
+                            {t('story.title_prefix')}<br />
+                            {t('story.title_suffix')}<span className="text-[#64FFDA]">{t('story.title_highlight')}</span>
+                        </h2>
+                        <div className="space-y-4 text-slate-400 leading-relaxed">
+                            <p>
+                                {t('story.p1')}
+                            </p>
+                            <p>
+                                <strong>{t('story.p2')}</strong>
+                            </p>
+                            <p>
+                                {t('story.p3')}
+                            </p>
+                            <p>
+                                {t('story.p4_prefix')}
+                                <br />
+                                {t('story.p4_part1')}
+                                <br />
+                                {t('story.p4_part2')}
+                            </p>
+                        </div>
+
+                        <div className="mt-8 grid grid-cols-2 gap-4">
+                            <div className="p-4 bg-[#112240] rounded border-l-4 border-[#64FFDA]">
+                                <h4 className="text-white font-bold">{t('story.box_1_title')}</h4>
+                                <p className="text-xs text-slate-500 mt-1">{t('story.box_1_desc')}</p>
+                            </div>
+                            <div className="p-4 bg-[#112240] rounded border-l-4 border-slate-600">
+                                <h4 className="text-white font-bold">{t('story.box_2_title')}</h4>
+                                <p className="text-xs text-slate-500 mt-1">{t('story.box_2_desc')}</p>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </section>
+
+            {/* CTA Section */}
+            <section id="contact" className="py-20 px-6">
+                <div className="max-w-4xl mx-auto bg-gradient-to-r from-[#112240] to-[#0A192F] border border-[#233554] rounded-2xl p-8 md:p-12 text-center relative overflow-hidden">
+                    <div className="absolute top-0 right-0 w-64 h-64 bg-[#64FFDA] rounded-full filter blur-[100px] opacity-5"></div>
+
+                    <h2 className="text-3xl font-bold text-white mb-4">{t('cta.title')}</h2>
+                    <p className="text-slate-400 mb-8 max-w-xl mx-auto">
+                        {t('cta.desc')}
+                    </p>
+
+                    <div className="flex flex-col sm:flex-row justify-center gap-4">
+                        <button className="px-8 py-4 bg-[#64FFDA] text-[#0A192F] font-bold rounded hover:bg-[#64FFDA]/90 transition-all shadow-lg shadow-[#64FFDA]/20">
+                            {t('cta.btn_demo')}
+                        </button>
+                        <button className="px-8 py-4 border border-slate-600 text-white rounded hover:bg-white/5 transition-all">
+                            {t('cta.btn_contact')}
+                        </button>
+                    </div>
+                </div>
+            </section>
+
+            {/* Footer */}
+            {/* Footer */}
+            <footer className="bg-[#020c1b] py-12 px-6 border-t border-[#233554]">
+                <div className="max-w-7xl mx-auto">
+                    <div className="flex flex-col md:flex-row justify-between items-start gap-8 mb-12">
+                        <div className="flex flex-col items-center md:items-start">
+                            <div className="mb-2">
+                                <Logo />
+                            </div>
+                            <p className="text-slate-500 text-sm mt-4 max-w-xs leading-relaxed">
+                                {t('footer.company')}<br />
+                                {t('footer.slogan')}
+                            </p>
+                        </div>
+
+                        <div className="flex gap-8 text-slate-400 text-sm font-medium">
+                            <a href="#" className="hover:text-[#64FFDA] transition-colors">{t('footer.privacy')}</a>
+                            <a href="#" className="hover:text-[#64FFDA] transition-colors">{t('footer.terms')}</a>
+                            <a href="#" className="hover:text-[#64FFDA] transition-colors">{t('footer.join')}</a>
+                        </div>
+                    </div>
+
+                    <div className="border-t border-[#112240] pt-8 flex flex-col md:flex-row justify-between items-center gap-4 text-xs">
+                        <span className="text-slate-600">&copy; 2026 {t('footer.company')} {t('footer.rights')}</span>
+
+                        <a href="/old-home" className="flex items-center gap-2 text-slate-500 hover:text-[#64FFDA] transition-colors group">
+                            <span>{t('footer.letter')}</span>
+                            <ArrowRight size={12} className="group-hover:translate-x-1 transition-transform" />
+                        </a>
+                    </div>
+                </div>
+            </footer>
+        </div>
+    );
+};
+
+export default NewHome;

+ 29 - 0
src/OldHomeLayout.tsx

@@ -0,0 +1,29 @@
+import HomePage from './pages/HomePage';
+import './App.css';
+
+function OldHomeLayout() {
+  const currentYear = new Date().getFullYear();
+
+  return (
+    <div className="app-container">
+      {/* 页头区域 */}
+      <header className="site-header">
+        <img src="/ccdw_logo_2025.5.png" alt="CCDW Logo" className="logo" />
+        <h1>CCDW = 纯粹的玩</h1>
+      </header>
+
+      {/* 主内容区域 */}
+      <main className="site-main">
+        <HomePage />
+      </main>
+
+      {/* 页脚区域 */}
+      <footer className="site-footer">
+        <p>&copy; {currentYear} CCDW (纯粹的玩). 不保留所有权利.</p>
+        <p>杭州纯粹的玩品牌科技有限公司 坐落于 浙江省杭州市西湖区转塘街道云腾丝路中心5号楼商业208室</p>
+      </footer>
+    </div>
+  );
+}
+
+export default OldHomeLayout;

+ 350 - 0
src/components/BreakoutGame.tsx

@@ -0,0 +1,350 @@
+import React, { useRef, useEffect, useState } from 'react';
+import { Play, RotateCcw } from 'lucide-react';
+import { useTranslation } from 'react-i18next';
+
+interface GameState {
+    isPlaying: boolean;
+    isGameOver: boolean;
+    score: number;
+    lives: number;
+}
+
+const BreakoutGame: React.FC = () => {
+    const { t } = useTranslation();
+    const canvasRef = useRef<HTMLCanvasElement>(null);
+    const [gameState, setGameState] = useState<GameState>({
+        isPlaying: false,
+        isGameOver: false,
+        score: 0,
+        lives: 3
+    });
+
+    // Game constants
+    const PADDLE_HEIGHT = 10;
+    const PADDLE_WIDTH = 75;
+    const BALL_RADIUS = 6;
+    const BRICK_ROW_COUNT = 5;
+
+    const BRICK_PADDING = 10;
+    const BRICK_OFFSET_TOP = 30;
+    const BRICK_OFFSET_LEFT = 30;
+    const BRICK_HEIGHT = 20;
+
+    // Refs to hold mutable game state without triggering re-renders
+    const gameRef = useRef({
+        x: 0,
+        y: 0,
+        dx: 4,
+        dy: -4,
+        paddleX: 0,
+        bricks: [] as { x: number; y: number; status: number }[],
+        animationId: 0,
+        score: 0,
+        rightPressed: false,
+        leftPressed: false
+    });
+
+    const initGame = (canvas: HTMLCanvasElement) => {
+        const { width, height } = canvas;
+        const state = gameRef.current;
+
+        state.x = width / 2;
+        state.y = height - 30;
+        state.dx = 4; // Speed
+        state.dy = -4;
+        state.paddleX = (width - PADDLE_WIDTH) / 2;
+        state.score = 0;
+
+        // Initialize bricks
+        let actualCols = Math.floor((width - 2 * BRICK_OFFSET_LEFT) / (70 + BRICK_PADDING)); // Approx brick width 70
+        if (actualCols < 1) actualCols = 1;
+
+        const totalPadding = (actualCols - 1) * BRICK_PADDING;
+        const availableWidth = width - 2 * BRICK_OFFSET_LEFT - totalPadding;
+        const brickWidth = availableWidth / actualCols;
+
+        state.bricks = [];
+        for (let c = 0; c < actualCols; c++) {
+            for (let r = 0; r < BRICK_ROW_COUNT; r++) {
+                // Determine brick color/value? For now just status=1
+                state.bricks.push({
+                    x: (c * (brickWidth + BRICK_PADDING)) + BRICK_OFFSET_LEFT,
+                    y: (r * (BRICK_HEIGHT + BRICK_PADDING)) + BRICK_OFFSET_TOP,
+                    status: 1
+                });
+            }
+        }
+
+        return { brickWidth, actualCols };
+    };
+
+    useEffect(() => {
+        const canvas = canvasRef.current;
+        if (!canvas) return;
+
+        const ctx = canvas.getContext('2d');
+        if (!ctx) return;
+
+        const drawBall = () => {
+            ctx.beginPath();
+            ctx.arc(gameRef.current.x, gameRef.current.y, BALL_RADIUS, 0, Math.PI * 2);
+            ctx.fillStyle = '#64FFDA';
+            ctx.fill();
+            ctx.closePath();
+
+            // Add glow
+            ctx.shadowBlur = 10;
+            ctx.shadowColor = "#64FFDA";
+        };
+
+        const drawPaddle = () => {
+            ctx.beginPath();
+            ctx.rect(gameRef.current.paddleX, canvas.height - PADDLE_HEIGHT - 10, PADDLE_WIDTH, PADDLE_HEIGHT);
+            ctx.fillStyle = '#64FFDA';
+            ctx.fill();
+            ctx.closePath();
+            ctx.shadowBlur = 0;
+        };
+
+        const drawBricks = (bWidth: number) => {
+            gameRef.current.bricks.forEach(brick => {
+                if (brick.status === 1) {
+                    ctx.beginPath();
+                    ctx.rect(brick.x, brick.y, bWidth, BRICK_HEIGHT);
+                    ctx.fillStyle = 'rgba(100, 255, 218, 0.6)'; // Transparent teal
+                    ctx.fill();
+                    ctx.closePath();
+                }
+            });
+        };
+
+        const collisionDetection = (bWidth: number) => {
+            const state = gameRef.current;
+            state.bricks.forEach(brick => {
+                if (brick.status === 1) {
+                    if (state.x > brick.x && state.x < brick.x + bWidth && state.y > brick.y && state.y < brick.y + BRICK_HEIGHT) {
+                        state.dy = -state.dy;
+                        brick.status = 0;
+                        state.score++;
+                        setGameState(prev => ({ ...prev, score: state.score }));
+
+                        // Check win (simple)
+                        if (state.score === state.bricks.length) {
+                            // Win logic, maybe reset bricks
+                        }
+                    }
+                }
+            });
+        };
+
+        const draw = (context: CanvasRenderingContext2D, cvs: HTMLCanvasElement, bWidth: number) => {
+            context.clearRect(0, 0, cvs.width, cvs.height);
+
+            drawBricks(bWidth);
+            drawBall();
+            drawPaddle();
+
+            if (gameState.isPlaying && !gameState.isGameOver) {
+                collisionDetection(bWidth);
+
+                const state = gameRef.current;
+
+                if (state.x + state.dx > cvs.width - BALL_RADIUS || state.x + state.dx < BALL_RADIUS) {
+                    state.dx = -state.dx;
+                }
+
+                // Paddle movement logic
+                if (state.rightPressed && state.paddleX < cvs.width - PADDLE_WIDTH) {
+                    state.paddleX += 7;
+                } else if (state.leftPressed && state.paddleX > 0) {
+                    state.paddleX -= 7;
+                }
+
+                if (state.y + state.dy < BALL_RADIUS) {
+                    state.dy = -state.dy;
+                } else if (state.y + state.dy > cvs.height - BALL_RADIUS) {
+                    if (state.x > state.paddleX && state.x < state.paddleX + PADDLE_WIDTH) {
+                        // Paddle hit
+                        // Add some English based on where it hit the paddle
+                        const hitPoint = state.x - (state.paddleX + PADDLE_WIDTH / 2);
+                        state.dx = hitPoint * 0.15; // Influence x speed
+                        state.dy = -Math.abs(state.dy * 1.05); // Speed up slightly?
+                        if (Math.abs(state.dx) < 2) state.dx = state.dx > 0 ? 2 : -2; // Min X speed
+                    } else {
+                        // Game Over
+                        setGameState(prev => ({ ...prev, isGameOver: true, isPlaying: false }));
+                        cancelAnimationFrame(state.animationId);
+                        return;
+                    }
+                }
+
+                state.x += state.dx;
+                state.y += state.dy;
+
+                state.animationId = requestAnimationFrame(() => draw(context, cvs, bWidth));
+            } else if (!gameState.isPlaying) {
+                // Just draw static if not playing
+            }
+        };
+
+        // Set canvas size to match container
+        const resizeCanvas = () => {
+            const parent = canvas.parentElement;
+            if (parent) {
+                // Ensure non-zero dimensions to avoid division by zero or negative math
+                canvas.width = parent.clientWidth || 300;
+                canvas.height = parent.clientHeight || 300;
+
+                if (!gameState.isPlaying) {
+                    try {
+                        const { brickWidth } = initGame(canvas);
+                        draw(ctx, canvas, brickWidth);
+                    } catch (e) {
+                        console.error("Error drawing canvas:", e);
+                    }
+                }
+            }
+        };
+
+        window.addEventListener('resize', resizeCanvas);
+        resizeCanvas();
+
+        // Keyboard event handlers
+        const keyDownHandler = (e: KeyboardEvent) => {
+            if (e.key === 'Right' || e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') {
+                gameRef.current.rightPressed = true;
+            } else if (e.key === 'Left' || e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') {
+                gameRef.current.leftPressed = true;
+            }
+        };
+
+        const keyUpHandler = (e: KeyboardEvent) => {
+            if (e.key === 'Right' || e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') {
+                gameRef.current.rightPressed = false;
+            } else if (e.key === 'Left' || e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') {
+                gameRef.current.leftPressed = false;
+            }
+        };
+
+        window.addEventListener('keydown', keyDownHandler);
+        window.addEventListener('keyup', keyUpHandler);
+
+        let { brickWidth } = initGame(canvas); // Initial draw
+
+        // Initial static draw if not playing
+        // Initial draw or start loop
+        draw(ctx, canvas, brickWidth);
+
+        return () => {
+            window.removeEventListener('resize', resizeCanvas);
+            window.removeEventListener('keydown', keyDownHandler);
+            window.removeEventListener('keyup', keyUpHandler);
+            cancelAnimationFrame(gameRef.current.animationId);
+        };
+    }, [gameState.isPlaying, gameState.isGameOver]); // Re-run effect when play state changes
+
+    const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
+        if (!gameState.isPlaying || gameState.isGameOver) return;
+        const canvas = canvasRef.current;
+        if (!canvas) return;
+
+        const rect = canvas.getBoundingClientRect();
+        const relativeX = e.clientX - rect.left;
+
+        if (relativeX > 0 && relativeX < canvas.width) {
+            gameRef.current.paddleX = relativeX - PADDLE_WIDTH / 2;
+        }
+    };
+
+    // Also support touch
+    const handleTouchMove = (e: React.TouchEvent<HTMLDivElement>) => {
+        if (!gameState.isPlaying || gameState.isGameOver) return;
+        const canvas = canvasRef.current;
+        if (!canvas) return;
+
+        const rect = canvas.getBoundingClientRect();
+        const touch = e.touches[0];
+        const relativeX = touch.clientX - rect.left;
+
+        if (relativeX > 0 && relativeX < canvas.width) {
+            gameRef.current.paddleX = relativeX - PADDLE_WIDTH / 2;
+        }
+    }
+
+    const startGame = () => {
+        const canvas = canvasRef.current;
+        if (canvas) {
+            initGame(canvas);
+            setGameState({ isPlaying: true, isGameOver: false, score: 0, lives: 3 });
+        }
+    };
+
+    return (
+        <div
+            className="w-full h-full relative group cursor-none"
+            onMouseMove={handleMouseMove}
+            onTouchMove={handleTouchMove}
+        >
+            <canvas
+                ref={canvasRef}
+                className="block w-full h-full bg-[#112240] rounded-2xl"
+            />
+
+            {/* Overlay UI */}
+            {(!gameState.isPlaying || gameState.isGameOver) && (
+                <div className="absolute inset-0 bg-[#0A192F]/80 backdrop-blur-sm flex flex-col items-center justify-center z-10 transition-all duration-300">
+                    {/* Game Over State */}
+                    {gameState.isGameOver ? (
+                        <div className="text-center">
+                            <h3 className="text-2xl font-bold text-white mb-2">{t('game.over')}</h3>
+                            <p className="text-[#64FFDA] mb-4 text-xl">{t('game.score')}: {gameState.score}</p>
+                            <button
+                                onClick={startGame}
+                                className="flex items-center gap-2 px-6 py-3 bg-[#64FFDA] text-[#0A192F] font-bold rounded-full hover:bg-[#64FFDA]/90 transition-all mx-auto cursor-pointer"
+                            >
+                                <RotateCcw size={20} />
+                                {t('game.try_again')}
+                            </button>
+                        </div>
+                    ) : (
+                        /* Initial Start State - Matches original design */
+                        <div className="w-full h-full flex flex-col justify-end p-8 relative">
+                            {/* Play hint overlay in center */}
+                            <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-center group-hover:scale-110 transition-transform duration-300">
+                                <button
+                                    onClick={startGame}
+                                    className="w-20 h-20 bg-[#64FFDA] rounded-full flex items-center justify-center shadow-[0_0_30px_rgba(100,255,218,0.3)] animate-pulse hover:animate-none"
+                                >
+                                    <Play size={32} className="text-[#0A192F] ml-1" fill="currentColor" />
+                                </button>
+                                <p className="text-[#64FFDA] text-sm mt-4 font-bold tracking-widest uppercase">{t('game.click')}</p>
+                            </div>
+
+                            {/* Statistic Card Style */}
+                            <div className="bg-[#0A192F]/90 backdrop-blur border border-[#64FFDA]/30 p-6 rounded-xl w-full">
+                                <div className="flex justify-between items-end">
+                                    <div>
+                                        <p className="text-slate-400 text-xs uppercase tracking-wider mb-1">{t('game.saved')}</p>
+                                        <p className="text-2xl font-bold text-white">∞ <span className="text-[#64FFDA] text-sm font-normal">{t('game.hours')}</span></p>
+                                    </div>
+                                    <div className="text-[#64FFDA] font-mono text-xs border border-[#64FFDA] px-2 py-1 rounded">
+                                        {t('game.level')}
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    )}
+                </div>
+            )}
+
+            {/* Stats Overlay Corner */}
+            {gameState.isPlaying && (
+                <div className="absolute top-4 right-4 text-[#64FFDA] font-mono font-bold text-lg select-none pointer-events-none">
+                    {gameState.score}
+                </div>
+            )}
+        </div>
+    );
+};
+
+export default BreakoutGame;

+ 69 - 0
src/components/Logo.tsx

@@ -0,0 +1,69 @@
+import React from 'react';
+
+interface LogoProps {
+    className?: string;
+    showText?: boolean;
+}
+
+const Logo: React.FC<LogoProps> = ({ className = "", showText = true }) => {
+    return (
+        <div className={`flex items-center gap-3 group select-none ${className}`}>
+            <div className="relative w-10 h-10 flex items-center justify-center">
+                {/* Logo Icon: A stylized abstract shape representing 'Dimensions' and 'C' */}
+                <svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-full h-full transform group-hover:scale-105 transition-transform duration-300">
+                    <defs>
+                        <linearGradient id="logo_gradient" x1="0" y1="0" x2="40" y2="40" gradientUnits="userSpaceOnUse">
+                            <stop offset="0%" stopColor="#64FFDA" />
+                            <stop offset="100%" stopColor="#0A192F" />
+                        </linearGradient>
+                        <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
+                            <feGaussianBlur stdDeviation="2" result="blur" />
+                            <feComposite in="SourceGraphic" in2="blur" operator="over" />
+                        </filter>
+                    </defs>
+
+                    {/* Background Shape (Hexagon-ish / Cube profile) */}
+                    <path
+                        d="M20 4L36 12V28L20 36L4 28V12L20 4Z"
+                        stroke="#64FFDA"
+                        strokeWidth="1.5"
+                        strokeOpacity="0.3"
+                        fill="transparent"
+                    />
+
+                    {/* Central Element: The 'C' / Core Logic */}
+                    {/* A tech-style path forming a C shape connected to the center */}
+                    <path
+                        d="M26 14L20 10L10 15V25L20 30L26 26"
+                        stroke="#64FFDA"
+                        strokeWidth="2.5"
+                        strokeLinecap="round"
+                        strokeLinejoin="round"
+                        filter="url(#glow)"
+                        className="group-hover:stroke-[#64FFDA] transition-colors"
+                    />
+
+                    {/* The 'Spark' / Data Point */}
+                    <rect x="24" y="19" width="3" height="3" fill="#64FFDA" className="animate-pulse">
+                        <animate attributeName="opacity" values="1;0.3;1" dur="2s" repeatCount="indefinite" />
+                    </rect>
+                </svg>
+            </div>
+
+            {showText && (
+                <div className="flex flex-col">
+                    <div className="flex items-baseline">
+                        <span className="text-white font-bold text-xl tracking-wide leading-none font-sans">CCDW</span>
+                        {/* Dot accent */}
+                        <span className="w-1.5 h-1.5 bg-[#64FFDA] rounded-full ml-1 mb-0.5"></span>
+                    </div>
+                    <span className="text-slate-400 text-[10px] font-medium tracking-[0.35em] leading-none mt-1.5 uppercase group-hover:text-[#64FFDA] transition-colors duration-300">
+                        乘策达维
+                    </span>
+                </div>
+            )}
+        </div>
+    );
+};
+
+export default Logo;

+ 32 - 0
src/i18n.ts

@@ -0,0 +1,32 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+import LanguageDetector from 'i18next-browser-languagedetector';
+
+import en from './locales/en.json';
+import zh from './locales/zh.json';
+import ja from './locales/ja.json';
+
+i18n
+    .use(LanguageDetector)
+    .use(initReactI18next)
+    .init({
+        resources: {
+            en: { translation: en },
+            zh: { translation: zh },
+            ja: { translation: ja }
+        },
+        supportedLngs: ['zh', 'en', 'ja'],
+        load: 'languageOnly', // matches 'en-US' -> 'en', 'zh-CN' -> 'zh'
+        fallbackLng: 'zh',
+        detection: {
+            // order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag', 'path', 'subdomain'],
+            order: ['localStorage', 'navigator'],
+            caches: ['localStorage'],
+        },
+        debug: false,
+        interpolation: {
+            escapeValue: false // not needed for react as it escapes by default
+        }
+    });
+
+export default i18n;

+ 1 - 24
src/index.css

@@ -1,24 +1 @@
-/* 重置和基础样式 */
-* {
-  box-sizing: border-box;
-}
-
-html {
-  line-height: 1.6;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-body {
-  margin: 0;
-  padding: 0;
-}
-
-a {
-  color: #108775;
-  text-decoration: none;
-}
-
-a:hover {
-  text-decoration: underline;
-}
+@import 'tailwindcss';

+ 96 - 0
src/locales/en.json

@@ -0,0 +1,96 @@
+{
+    "nav": {
+        "home": "Home",
+        "services": "Services",
+        "story": "Philosophy",
+        "contact": "Contact",
+        "book": "Book Demo"
+    },
+    "hero": {
+        "badge": "Efficiency Experts in Financial Consulting",
+        "title_full": "Computing Strategy, Delivering Dimensions.",
+        "title_prefix": "Computing Strategy,",
+        "title_middle": " ",
+        "title_suffix": "Delivering Dimensions.",
+        "title_highlight_1": "",
+        "title_highlight_2": "",
+        "subtitle": "CCDW empowers businesses by delegating complex mental labor to AI. We provide not just strategy, but a digital engine that drives transformation, letting business run on algorithms.",
+        "btn_explore": "Explore Solutions",
+        "btn_philosophy": "Our Philosophy",
+        "feature_1": "Unleash Human Capital",
+        "feature_2": "Return to Creativity"
+    },
+    "code": {
+        "import_1": "AI_Workforce",
+        "as_1": "Labor",
+        "import_2": "Human_Life",
+        "as_2": "Pure_Play",
+        "comment": "# Our Vision: AI Works, Humans Live",
+        "efficiency": "> Efficiency: Maximized",
+        "freedom": "> Human Freedom: Restored",
+        "mode": "> Mode: Pure Play"
+    },
+    "services": {
+        "title": "Core Services",
+        "subtitle": "Leave repetition to machines, keep wisdom for humans.",
+        "card_1": {
+            "title": "Strategy · AI Consulting",
+            "desc": "Digital transformation diagnosis for financial institutions. We restructure business processes with algorithmic thinking to identify inefficiencies and provide actionable AI roadmaps.",
+            "list_1": "Process Automation Audit",
+            "list_2": "Digital Transformation Roadmap"
+        },
+        "card_2": {
+            "title": "Dimension · Data Intelligence",
+            "desc": "See through the noise. We simplify unstructured data (reports, news) cleaning, extraction, and knowledge base construction.",
+            "list_1": "Auto-Cleaning of Financial Reports",
+            "list_2": "Industry Knowledge Graph"
+        },
+        "card_3": {
+            "title": "Efficacy · IT Solutions",
+            "desc": "Beyond talk, we deliver. RPA automation tools, custom AI Agents, and data visualization dashboards to directly boost human efficiency.",
+            "list_1": "Custom AI Agent Development",
+            "list_2": "Intelligent Data Dashboards"
+        }
+    },
+    "story": {
+        "label": "PHILOSOPHY",
+        "title_prefix": "AI's ",
+        "title_suffix": " for Human's ",
+        "title_highlight": "\"Play\"",
+        "title_highlight_pre": "\"Key\"",
+        "p1": "People often ask, why keep the name \"Pure Play\"?",
+        "p2": "Our answer is: Because that is the ultimate goal of humanity.",
+        "p3": "In the digital age, tedious data labor should no longer bind human minds. We believe AI should shoulder the burden, freeing humans to create, experience, and enjoy life.",
+        "p4_prefix": "Thus, CCDW has two sides:",
+        "p4_part1": "In method, we \"Compute Strategy\" — solving business problems with hardcore AI;",
+        "p4_part2": "In vision, we remain \"Pure Play\" — using tech to restore freedom and fun.",
+        "box_1_title": "AI Takes Responsibility",
+        "box_1_desc": "Handling massive data & logic",
+        "box_2_title": "Humans Enjoy Freedom",
+        "box_2_desc": "Returning to creativity & experience"
+    },
+    "cta": {
+        "title": "Give Work to AI, Keep Time for Yourself",
+        "desc": "Book a free AI efficiency assessment and see how much time we can save you.",
+        "btn_demo": "Book Demo",
+        "btn_contact": "Contact Advisor"
+    },
+    "footer": {
+        "company": "Pure Play Brand Tech Co., Ltd.",
+        "slogan": "Computing Strategy, Delivering Dimensions",
+        "privacy": "Privacy Policy",
+        "terms": "Terms of Service",
+        "join": "Join Us",
+        "rights": "All rights reserved.",
+        "letter": "A Letter to Players (2025)"
+    },
+    "game": {
+        "saved": "Human Time Saved",
+        "hours": "Hours for Play",
+        "level": "LEVEL 1",
+        "click": "Click to Play",
+        "over": "Game Over",
+        "score": "Score",
+        "try_again": "Try Again"
+    }
+}

+ 96 - 0
src/locales/ja.json

@@ -0,0 +1,96 @@
+{
+    "nav": {
+        "home": "ホーム",
+        "services": "サービス",
+        "story": "ブランド物語",
+        "contact": "お問い合わせ",
+        "book": "予約相談"
+    },
+    "hero": {
+        "badge": "金融コンサルティング業界の効率化エキスパート",
+        "title_full": "知恵で策を乗じ、次元を切り拓く。",
+        "title_prefix": "知恵で",
+        "title_middle": "策を乗じ、",
+        "title_suffix": "次元を切り拓く。",
+        "title_highlight_1": "",
+        "title_highlight_2": "",
+        "subtitle": "CCDWは、AIを活用して複雑な知的労働を担うことに専念しています。単なる戦略だけでなく、変革を推進するデジタルエンジンを提供し、ビジネスをアルゴリズム上で走らせます。",
+        "btn_explore": "ソリューションを探索",
+        "btn_philosophy": "私たちの哲学",
+        "feature_1": "人的資本の解放",
+        "feature_2": "創造の本質へ回帰"
+    },
+    "code": {
+        "import_1": "AI_Workforce",
+        "as_1": "労力",
+        "import_2": "Human_Life",
+        "as_2": "純粋な遊び",
+        "comment": "# 私たちのビジョン:AIが働き、人間が生きる",
+        "efficiency": "> Efficiency: Maximized",
+        "freedom": "> Human Freedom: Restored",
+        "mode": "> Mode: Pure Play"
+    },
+    "services": {
+        "title": "コアサービス体系",
+        "subtitle": "繰り返しは機械に、知恵は人間に。",
+        "card_1": {
+            "title": "智策 · AI Consulting",
+            "desc": "金融機関やコンサルティング会社向けのDX診断。アルゴリズム的思考で業務プロセスを再構築し、非効率な部分を特定、実現可能なAI導入計画を提供します。",
+            "list_1": "業務プロセス自動化監査",
+            "list_2": "DXロードマップ策定"
+        },
+        "card_2": {
+            "title": "数維 · Data Intelligence",
+            "desc": "複雑な情報を見通し、ビジネスの本質を洞察。非構造化データ(レポート、ニュースなど)のクレンジング、抽出、ナレッジベース構築サービスを提供します。",
+            "list_1": "金融レポート自動クレンジング",
+            "list_2": "業界ナレッジグラフ構築"
+        },
+        "card_3": {
+            "title": "効能 · IT Solutions",
+            "desc": "空論を拒絶し、技術を実装。RPA自動化ツール、カスタマイズされたAIエージェント開発、データ可視化ダッシュボードを提供し、人的効率を直接向上させます。",
+            "list_1": "AIアシスタント開発",
+            "list_2": "インテリジェントダッシュボード構築"
+        }
+    },
+    "story": {
+        "label": "私たちの哲学 · PHILOSOPHY",
+        "title_prefix": "AIの「勤勉」で",
+        "title_suffix": "人間の",
+        "title_highlight": "「遊び」を",
+        "title_highlight_pre": "取り戻す",
+        "p1": "以前、なぜ「純粋な遊び」という名前を残したのかと聞かれました。",
+        "p2": "私たちの答えは:それが人類の究極の目標だからです。",
+        "p3": "デジタル時代において、煩雑で反復的なデータ労働は、もはや人間の頭脳を縛るべきではありません。私たちは、AIが「苦役」を担い、人間はそこから解放され、創造し、体験し、生活を楽しむべきだと信じています。",
+        "p4_prefix": "だから、CCDWは表裏一体なのです:",
+        "p4_part1": "手段としては、「乗策達維(CCDW)」—— 最先端のAI技術でビジネスの難題を解決します;",
+        "p4_part2": "ビジョンとしては、依然として「純粋な遊び」—— 技術で自由を解放し、純粋な楽しみへ回帰します。",
+        "box_1_title": "AIが責任を担う",
+        "box_1_desc": "膨大なデータとロジックを処理",
+        "box_2_title": "人類は自由を享受",
+        "box_2_desc": "創造性と純粋な体験へ回帰"
+    },
+    "cta": {
+        "title": "仕事をAIに任せ、時間を自分のために",
+        "desc": "無料のAI効率化診断を予約して、どれだけの時間を節約できるか確認してください。",
+        "btn_demo": "デモを予約",
+        "btn_contact": "コンサルタントに連絡"
+    },
+    "footer": {
+        "company": "杭州純粋的玩ブランド技術有限会社",
+        "slogan": "Computing Strategy, Delivering Dimensions",
+        "privacy": "プライバシーポリシー",
+        "terms": "利用規約",
+        "join": "採用情報",
+        "rights": "All rights reserved.",
+        "letter": "プレイヤーへの手紙(2025)"
+    },
+    "game": {
+        "saved": "節約された人間の時間",
+        "hours": "時間(遊びのために)",
+        "level": "レベル 1",
+        "click": "クリックして開始",
+        "over": "ゲームオーバー",
+        "score": "スコア",
+        "try_again": "もう一度"
+    }
+}

+ 95 - 0
src/locales/zh.json

@@ -0,0 +1,95 @@
+{
+    "nav": {
+        "home": "首页",
+        "services": "核心服务",
+        "story": "品牌故事",
+        "contact": "联系我们",
+        "book": "预约咨询"
+    },
+    "hero": {
+        "badge": "金融咨询行业的效能专家",
+        "title_prefix": "以智",
+        "title_highlight_1": "乘",
+        "title_middle": "策,",
+        "title_suffix": "升维通",
+        "title_highlight_2": "达",
+        "title_full": "以智乘策,升维通达。",
+        "subtitle": "CCDW 致力于用 AI 承担繁杂的脑力劳动。我们不仅仅提供策略,更提供驱动变革的数字化引擎,让业务跑在算法之上。",
+        "btn_explore": "探索解决方案",
+        "btn_philosophy": "了解我们的哲学",
+        "feature_1": "释放人力资本",
+        "feature_2": "回归创造本质"
+    },
+    "code": {
+        "import_1": "AI_Workforce",
+        "as_1": "劳力",
+        "import_2": "Human_Life",
+        "as_2": "纯粹的玩",
+        "comment": "# 我们的愿景:AI工作,人类生活",
+        "efficiency": "> Efficiency: Maximized",
+        "freedom": "> Human Freedom: Restored",
+        "mode": "> Mode: Pure Play"
+    },
+    "services": {
+        "title": "核心服务体系",
+        "subtitle": "把重复留给机器,把智慧留给人类。",
+        "card_1": {
+            "title": "智策 · AI Consulting",
+            "desc": "针对金融机构与咨询公司的数字化转型诊断。我们运用算法思维重构业务流程,识别低效环节,提供可落地的 AI 实施蓝图。",
+            "list_1": "业务流程自动化审计",
+            "list_2": "数字化转型路径规划"
+        },
+        "card_2": {
+            "title": "数维 · Data Intelligence",
+            "desc": "透过繁杂信息,洞察商业本质。我们提供非结构化数据(如研报、新闻)的清洗、提取与知识库搭建服务。",
+            "list_1": "金融研报自动清洗",
+            "list_2": "行业知识图谱构建"
+        },
+        "card_3": {
+            "title": "效能 · IT Solutions",
+            "desc": "拒绝空谈,技术落地。提供 RPA 自动化工具、定制化 AI Agent 开发以及数据可视化大屏,直接提升人效。",
+            "list_1": "定制化 AI 助手开发",
+            "list_2": "智能数据看板搭建"
+        }
+    },
+    "story": {
+        "label": "我们的哲学 · PHILOSOPHY",
+        "title_prefix": "用 AI 的“勤”",
+        "title_suffix": "换人类的",
+        "title_highlight": "“玩”",
+        "p1": "曾经,有人问我们为什么保留“纯粹的玩”这个名字?",
+        "p2": "我们的回答是:因为这才是人类的终极目标。",
+        "p3": "在数智化时代,繁琐、重复、枯燥的数据劳动不应再束缚人类的头脑。我们坚信,AI 应该去承担那些“苦活累活”,而人类应该从中解放出来,去创造、去体验、去享受生活。",
+        "p4_prefix": "所以,CCDW 是一体两面的:",
+        "p4_part1": "在手段上,我们是“乘策达维” —— 用最硬核的 AI 技术解决商业难题;",
+        "p4_part2": "在愿景上,我们依然是“纯粹的玩” —— 用技术释放自由,回归纯粹的乐趣。",
+        "box_1_title": "AI 承担责任",
+        "box_1_desc": "处理海量数据与逻辑",
+        "box_2_title": "人类享受自由",
+        "box_2_desc": "回归创意与纯粹体验"
+    },
+    "cta": {
+        "title": "把工作交给 AI,把时间留给自己",
+        "desc": "立即预约一次免费的 AI 效能评估,看看我们可以为您节省多少时间。",
+        "btn_demo": "预约演示 Demo",
+        "btn_contact": "联系我们的顾问"
+    },
+    "footer": {
+        "company": "杭州纯粹的玩品牌科技有限公司",
+        "slogan": "Computing Strategy, Delivering Dimensions",
+        "privacy": "隐私政策",
+        "terms": "服务条款",
+        "join": "加入我们",
+        "rights": "All rights reserved.",
+        "letter": "给玩家的一封信(2025)"
+    },
+    "game": {
+        "saved": "节省的人类时间",
+        "hours": "小时用于玩乐",
+        "level": "第 1 关",
+        "click": "点击开始游戏",
+        "over": "游戏结束",
+        "score": "得分",
+        "try_again": "再试一次"
+    }
+}

+ 1 - 0
src/main.tsx

@@ -1,6 +1,7 @@
 import { StrictMode } from 'react'
 import { createRoot } from 'react-dom/client'
 import './index.css'
+import './i18n'
 import App from './App.tsx'
 
 createRoot(document.getElementById('root')!).render(

+ 11 - 0
tailwind.config.js

@@ -0,0 +1,11 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+    content: [
+        "./index.html",
+        "./src/**/*.{js,ts,jsx,tsx}",
+    ],
+    theme: {
+        extend: {},
+    },
+    plugins: [],
+}