From ae0bfd2bb2b6c00a0927268e17e0496e2daec92f Mon Sep 17 00:00:00 2001
From: Yifei Chen
Date: Sat, 15 Nov 2025 21:15:07 -0800
Subject: [PATCH] UI redesign, new visualization, updated color scheme,
homepage
---
package-lock.json | 1519 +++++++++++++++++++++++++++++++++++++++--
package.json | 4 +-
public/geisel.jpg | Bin 0 -> 18976 bytes
src/App.jsx | 259 ++++++-
src/DataInput.jsx | 69 ++
src/Visualization.jsx | 97 +++
src/firebase.js | 25 +
src/index.css | 279 ++++++--
src/main.jsx | 17 +-
9 files changed, 2120 insertions(+), 149 deletions(-)
create mode 100644 public/geisel.jpg
create mode 100644 src/DataInput.jsx
create mode 100644 src/Visualization.jsx
create mode 100644 src/firebase.js
diff --git a/package-lock.json b/package-lock.json
index 8afc14e..6ce90d8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,18 @@
{
- "name": "package.json",
+ "name": "Geisel Occupancy Tracker",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "package.json",
+ "name": "Geisel Occupancy Tracker",
"version": "0.0.0",
"dependencies": {
+ "firebase": "^12.6.0",
"gh-pages": "^6.3.0",
"react": "^19.2.0",
- "react-dom": "^19.2.0"
+ "react-dom": "^19.2.0",
+ "recharts": "^3.4.1"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
@@ -906,6 +908,649 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@firebase/ai": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-2.6.0.tgz",
+ "integrity": "sha512-NGyE7NQDFznOv683Xk4+WoUv39iipa9lEfrwvvPz33ChzVbCCiB69FJQTK2BI/11pRtzYGbHo1/xMz7gxWWhJw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/app-check-interop-types": "0.3.3",
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x",
+ "@firebase/app-types": "0.x"
+ }
+ },
+ "node_modules/@firebase/analytics": {
+ "version": "0.10.19",
+ "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.19.tgz",
+ "integrity": "sha512-3wU676fh60gaiVYQEEXsbGS4HbF2XsiBphyvvqDbtC1U4/dO4coshbYktcCHq+HFaGIK07iHOh4pME0hEq1fcg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/installations": "0.6.19",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/analytics-compat": {
+ "version": "0.2.25",
+ "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.25.tgz",
+ "integrity": "sha512-fdzoaG0BEKbqksRDhmf4JoyZf16Wosrl0Y7tbZtJyVDOOwziE0vrFjmZuTdviL0yhak+Nco6rMsUUbkbD+qb6Q==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/analytics": "0.10.19",
+ "@firebase/analytics-types": "0.8.3",
+ "@firebase/component": "0.7.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/analytics-types": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz",
+ "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/app": {
+ "version": "0.14.6",
+ "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.14.6.tgz",
+ "integrity": "sha512-4uyt8BOrBsSq6i4yiOV/gG6BnnrvTeyymlNcaN/dKvyU1GoolxAafvIvaNP1RCGPlNab3OuE4MKUQuv2lH+PLQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "idb": "7.1.1",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@firebase/app-check": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.11.0.tgz",
+ "integrity": "sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/app-check-compat": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.4.0.tgz",
+ "integrity": "sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/app-check": "0.11.0",
+ "@firebase/app-check-types": "0.5.3",
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/app-check-interop-types": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz",
+ "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/app-check-types": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz",
+ "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/app-compat": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.5.6.tgz",
+ "integrity": "sha512-YYGARbutghQY4zZUWMYia0ib0Y/rb52y72/N0z3vglRHL7ii/AaK9SA7S/dzScVOlCdnbHXz+sc5Dq+r8fwFAg==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@firebase/app": "0.14.6",
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@firebase/app-types": {
+ "version": "0.9.3",
+ "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz",
+ "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/@firebase/auth": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.11.1.tgz",
+ "integrity": "sha512-Mea0G/BwC1D0voSG+60Ylu3KZchXAFilXQ/hJXWCw3gebAu+RDINZA0dJMNeym7HFxBaBaByX8jSa7ys5+F2VA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x",
+ "@react-native-async-storage/async-storage": "^1.18.1"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-async-storage/async-storage": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@firebase/auth-compat": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.6.1.tgz",
+ "integrity": "sha512-I0o2ZiZMnMTOQfqT22ur+zcGDVSAfdNZBHo26/Tfi8EllfR1BO7aTVo2rt/ts8o/FWsK8pOALLeVBGhZt8w/vg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/auth": "1.11.1",
+ "@firebase/auth-types": "0.13.0",
+ "@firebase/component": "0.7.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/auth-interop-types": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz",
+ "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/auth-types": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz",
+ "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@firebase/app-types": "0.x",
+ "@firebase/util": "1.x"
+ }
+ },
+ "node_modules/@firebase/component": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.7.0.tgz",
+ "integrity": "sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@firebase/data-connect": {
+ "version": "0.3.12",
+ "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.12.tgz",
+ "integrity": "sha512-baPddcoNLj/+vYo+HSJidJUdr5W4OkhT109c5qhR8T1dJoZcyJpkv/dFpYlw/VJ3dV66vI8GHQFrmAZw/xUS4g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/auth-interop-types": "0.2.4",
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/database": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.1.0.tgz",
+ "integrity": "sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/app-check-interop-types": "0.3.3",
+ "@firebase/auth-interop-types": "0.2.4",
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "faye-websocket": "0.11.4",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@firebase/database-compat": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.1.0.tgz",
+ "integrity": "sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/database": "1.1.0",
+ "@firebase/database-types": "1.0.16",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@firebase/database-types": {
+ "version": "1.0.16",
+ "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.16.tgz",
+ "integrity": "sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/app-types": "0.9.3",
+ "@firebase/util": "1.13.0"
+ }
+ },
+ "node_modules/@firebase/firestore": {
+ "version": "4.9.2",
+ "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.9.2.tgz",
+ "integrity": "sha512-iuA5+nVr/IV/Thm0Luoqf2mERUvK9g791FZpUJV1ZGXO6RL2/i/WFJUj5ZTVXy5pRjpWYO+ZzPcReNrlilmztA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "@firebase/webchannel-wrapper": "1.0.5",
+ "@grpc/grpc-js": "~1.9.0",
+ "@grpc/proto-loader": "^0.7.8",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/firestore-compat": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.4.2.tgz",
+ "integrity": "sha512-cy7ov6SpFBx+PHwFdOOjbI7kH00uNKmIFurAn560WiPCZXy9EMnil1SOG7VF4hHZKdenC+AHtL4r3fNpirpm0w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/firestore": "4.9.2",
+ "@firebase/firestore-types": "3.0.3",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/firestore-types": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz",
+ "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@firebase/app-types": "0.x",
+ "@firebase/util": "1.x"
+ }
+ },
+ "node_modules/@firebase/functions": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.13.1.tgz",
+ "integrity": "sha512-sUeWSb0rw5T+6wuV2o9XNmh9yHxjFI9zVGFnjFi+n7drTEWpl7ZTz1nROgGrSu472r+LAaj+2YaSicD4R8wfbw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/app-check-interop-types": "0.3.3",
+ "@firebase/auth-interop-types": "0.2.4",
+ "@firebase/component": "0.7.0",
+ "@firebase/messaging-interop-types": "0.2.3",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/functions-compat": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.4.1.tgz",
+ "integrity": "sha512-AxxUBXKuPrWaVNQ8o1cG1GaCAtXT8a0eaTDfqgS5VsRYLAR0ALcfqDLwo/QyijZj1w8Qf8n3Qrfy/+Im245hOQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/functions": "0.13.1",
+ "@firebase/functions-types": "0.6.3",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/functions-types": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz",
+ "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/installations": {
+ "version": "0.6.19",
+ "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.19.tgz",
+ "integrity": "sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/util": "1.13.0",
+ "idb": "7.1.1",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/installations-compat": {
+ "version": "0.2.19",
+ "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.19.tgz",
+ "integrity": "sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/installations": "0.6.19",
+ "@firebase/installations-types": "0.5.3",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/installations-types": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz",
+ "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@firebase/app-types": "0.x"
+ }
+ },
+ "node_modules/@firebase/logger": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.5.0.tgz",
+ "integrity": "sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@firebase/messaging": {
+ "version": "0.12.23",
+ "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.23.tgz",
+ "integrity": "sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/installations": "0.6.19",
+ "@firebase/messaging-interop-types": "0.2.3",
+ "@firebase/util": "1.13.0",
+ "idb": "7.1.1",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/messaging-compat": {
+ "version": "0.2.23",
+ "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.23.tgz",
+ "integrity": "sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/messaging": "0.12.23",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/messaging-interop-types": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz",
+ "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/performance": {
+ "version": "0.7.9",
+ "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.9.tgz",
+ "integrity": "sha512-UzybENl1EdM2I1sjYm74xGt/0JzRnU/0VmfMAKo2LSpHJzaj77FCLZXmYQ4oOuE+Pxtt8Wy2BVJEENiZkaZAzQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/installations": "0.6.19",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0",
+ "web-vitals": "^4.2.4"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/performance-compat": {
+ "version": "0.2.22",
+ "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.22.tgz",
+ "integrity": "sha512-xLKxaSAl/FVi10wDX/CHIYEUP13jXUjinL+UaNXT9ByIvxII5Ne5150mx6IgM8G6Q3V+sPiw9C8/kygkyHUVxg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/performance": "0.7.9",
+ "@firebase/performance-types": "0.2.3",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/performance-types": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz",
+ "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/remote-config": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.7.0.tgz",
+ "integrity": "sha512-dX95X6WlW7QlgNd7aaGdjAIZUiQkgWgNS+aKNu4Wv92H1T8Ue/NDUjZHd9xb8fHxLXIHNZeco9/qbZzr500MjQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/installations": "0.6.19",
+ "@firebase/logger": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/remote-config-compat": {
+ "version": "0.2.20",
+ "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.20.tgz",
+ "integrity": "sha512-P/ULS9vU35EL9maG7xp66uljkZgcPMQOxLj3Zx2F289baTKSInE6+YIkgHEi1TwHoddC/AFePXPpshPlEFkbgg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/logger": "0.5.0",
+ "@firebase/remote-config": "0.7.0",
+ "@firebase/remote-config-types": "0.5.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/remote-config-types": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.5.0.tgz",
+ "integrity": "sha512-vI3bqLoF14L/GchtgayMiFpZJF+Ao3uR8WCde0XpYNkSokDpAKca2DxvcfeZv7lZUqkUwQPL2wD83d3vQ4vvrg==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@firebase/storage": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.14.0.tgz",
+ "integrity": "sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app": "0.x"
+ }
+ },
+ "node_modules/@firebase/storage-compat": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.4.0.tgz",
+ "integrity": "sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/component": "0.7.0",
+ "@firebase/storage": "0.14.0",
+ "@firebase/storage-types": "0.8.3",
+ "@firebase/util": "1.13.0",
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "@firebase/app-compat": "0.x"
+ }
+ },
+ "node_modules/@firebase/storage-types": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz",
+ "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@firebase/app-types": "0.x",
+ "@firebase/util": "1.x"
+ }
+ },
+ "node_modules/@firebase/util": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.13.0.tgz",
+ "integrity": "sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@firebase/webchannel-wrapper": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.5.tgz",
+ "integrity": "sha512-+uGNN7rkfn41HLO0vekTFhTxk61eKa8mTpRGLO0QSqlQdKvIoGAvLp3ppdVIWbTGYJWM6Kp0iN+PjMIOcnVqTw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@grpc/grpc-js": {
+ "version": "1.9.15",
+ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz",
+ "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@grpc/proto-loader": "^0.7.8",
+ "@types/node": ">=12.12.47"
+ },
+ "engines": {
+ "node": "^8.13.0 || >=10.10.0"
+ }
+ },
+ "node_modules/@grpc/proto-loader": {
+ "version": "0.7.15",
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz",
+ "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "lodash.camelcase": "^4.3.0",
+ "long": "^5.0.0",
+ "protobufjs": "^7.2.5",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -1043,6 +1688,96 @@
"node": ">= 8"
}
},
+ "node_modules/@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/codegen": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/eventemitter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/fetch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.1",
+ "@protobufjs/inquire": "^1.1.0"
+ }
+ },
+ "node_modules/@protobufjs/float": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/inquire": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/utf8": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.10.1",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.10.1.tgz",
+ "integrity": "sha512-/U17EXQ9Do9Yx4DlNGU6eVNfZvFJfYpUtRRdLf19PbPjdWBxNlxGZXywQZ1p1Nz8nMkWplTI7iD/23m07nolDA==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^10.2.0",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.43",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.43.tgz",
@@ -1358,6 +2093,18 @@
"win32"
]
},
+ "node_modules/@standard-schema/spec": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
+ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1403,6 +2150,69 @@
"@babel/types": "^7.28.2"
}
},
+ "node_modules/@types/d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-ease": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-color": "*"
+ }
+ },
+ "node_modules/@types/d3-path": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-shape": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
+ "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-path": "*"
+ }
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-timer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -1417,11 +2227,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/node": {
+ "version": "24.10.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
+ "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
"node_modules/@types/react": {
"version": "19.2.2",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
@@ -1438,6 +2257,12 @@
"@types/react": "^19.2.0"
}
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
"node_modules/@vitejs/plugin-react": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.0.tgz",
@@ -1500,11 +2325,19 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
@@ -1661,76 +2494,218 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
+ "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "color-name": "~1.1.4"
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "license": "ISC",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "^3.1.0"
},
"engines": {
- "node": ">=7.0.0"
+ "node": ">=12"
}
},
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/commander": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
- "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
- "license": "MIT",
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
"engines": {
- "node": ">=18"
+ "node": ">=12"
}
},
- "node_modules/commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
- "license": "MIT"
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/convert-source-map": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
- "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/cross-spawn": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
- "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "dev": true,
- "license": "MIT",
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "license": "ISC",
"dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
+ "d3-time": "1 - 3"
},
"engines": {
- "node": ">= 8"
+ "node": ">=12"
}
},
- "node_modules/csstype": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
- "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
- "license": "MIT"
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
},
"node_modules/debug": {
"version": "4.4.3",
@@ -1750,6 +2725,12 @@
}
}
},
+ "node_modules/decimal.js-light": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
+ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
+ "license": "MIT"
+ },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -1782,6 +2763,22 @@
"integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
"license": "MIT"
},
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/es-toolkit": {
+ "version": "1.41.0",
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.41.0.tgz",
+ "integrity": "sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==",
+ "license": "MIT",
+ "workspaces": [
+ "docs",
+ "benchmarks"
+ ]
+ },
"node_modules/esbuild": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
@@ -1828,7 +2825,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -2025,6 +3021,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
+ "license": "MIT"
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2083,6 +3085,18 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/faye-websocket": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+ "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "websocket-driver": ">=0.5.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@@ -2186,6 +3200,42 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/firebase": {
+ "version": "12.6.0",
+ "resolved": "https://registry.npmjs.org/firebase/-/firebase-12.6.0.tgz",
+ "integrity": "sha512-8ZD1Gcv916Qp8/nsFH2+QMIrfX/76ti6cJwxQUENLXXnKlOX/IJZaU2Y3bdYf5r1mbownrQKfnWtrt+MVgdwLA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@firebase/ai": "2.6.0",
+ "@firebase/analytics": "0.10.19",
+ "@firebase/analytics-compat": "0.2.25",
+ "@firebase/app": "0.14.6",
+ "@firebase/app-check": "0.11.0",
+ "@firebase/app-check-compat": "0.4.0",
+ "@firebase/app-compat": "0.5.6",
+ "@firebase/app-types": "0.9.3",
+ "@firebase/auth": "1.11.1",
+ "@firebase/auth-compat": "0.6.1",
+ "@firebase/data-connect": "0.3.12",
+ "@firebase/database": "1.1.0",
+ "@firebase/database-compat": "2.1.0",
+ "@firebase/firestore": "4.9.2",
+ "@firebase/firestore-compat": "0.4.2",
+ "@firebase/functions": "0.13.1",
+ "@firebase/functions-compat": "0.4.1",
+ "@firebase/installations": "0.6.19",
+ "@firebase/installations-compat": "0.2.19",
+ "@firebase/messaging": "0.12.23",
+ "@firebase/messaging-compat": "0.2.23",
+ "@firebase/performance": "0.7.9",
+ "@firebase/performance-compat": "0.2.22",
+ "@firebase/remote-config": "0.7.0",
+ "@firebase/remote-config-compat": "0.2.20",
+ "@firebase/storage": "0.14.0",
+ "@firebase/storage-compat": "0.4.0",
+ "@firebase/util": "1.13.0"
+ }
+ },
"node_modules/flat-cache": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
@@ -2246,6 +3296,15 @@
"node": ">=6.9.0"
}
},
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
"node_modules/gh-pages": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.3.0.tgz",
@@ -2330,6 +3389,18 @@
"node": ">=8"
}
},
+ "node_modules/http-parser-js": {
+ "version": "0.5.10",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
+ "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
+ "license": "MIT"
+ },
+ "node_modules/idb": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz",
+ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
+ "license": "ISC"
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -2339,6 +3410,16 @@
"node": ">= 4"
}
},
+ "node_modules/immer": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
+ "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -2366,6 +3447,15 @@
"node": ">=0.8.19"
}
},
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2375,6 +3465,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -2522,6 +3621,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "license": "MIT"
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -2529,6 +3634,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/long": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
+ "license": "Apache-2.0"
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -2865,6 +3976,30 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/protobufjs": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz",
+ "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/node": ">=13.7.0",
+ "long": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -2910,6 +4045,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -2917,6 +4053,37 @@
"react": "^19.2.0"
}
},
+ "node_modules/react-is": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
+ "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/react-redux": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
+ "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-refresh": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
@@ -2927,6 +4094,67 @@
"node": ">=0.10.0"
}
},
+ "node_modules/recharts": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.4.1.tgz",
+ "integrity": "sha512-35kYg6JoOgwq8sE4rhYkVWwa6aAIgOtT+Ob0gitnShjwUwZmhrmy7Jco/5kJNF4PnLXgt9Hwq+geEMS+WrjU1g==",
+ "license": "MIT",
+ "workspaces": [
+ "www"
+ ],
+ "dependencies": {
+ "@reduxjs/toolkit": "1.x.x || 2.x.x",
+ "clsx": "^2.1.1",
+ "decimal.js-light": "^2.5.1",
+ "es-toolkit": "^1.39.3",
+ "eventemitter3": "^5.0.1",
+ "immer": "^10.1.1",
+ "react-redux": "8.x.x || 9.x.x",
+ "reselect": "5.1.1",
+ "tiny-invariant": "^1.3.3",
+ "use-sync-external-store": "^1.2.2",
+ "victory-vendor": "^37.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "license": "MIT"
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -3012,6 +4240,26 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/scheduler": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
@@ -3069,6 +4317,32 @@
"node": ">=0.10.0"
}
},
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -3116,6 +4390,12 @@
"node": ">=8"
}
},
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+ "license": "MIT"
+ },
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -3166,6 +4446,12 @@
"node": ">=0.8.0"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -3179,6 +4465,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "license": "MIT"
+ },
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
@@ -3229,6 +4521,37 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/victory-vendor": {
+ "version": "37.3.6",
+ "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz",
+ "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==",
+ "license": "MIT AND ISC",
+ "dependencies": {
+ "@types/d3-array": "^3.0.3",
+ "@types/d3-ease": "^3.0.0",
+ "@types/d3-interpolate": "^3.0.1",
+ "@types/d3-scale": "^4.0.2",
+ "@types/d3-shape": "^3.1.0",
+ "@types/d3-time": "^3.0.0",
+ "@types/d3-timer": "^3.0.0",
+ "d3-array": "^3.1.6",
+ "d3-ease": "^3.0.1",
+ "d3-interpolate": "^3.0.1",
+ "d3-scale": "^4.0.2",
+ "d3-shape": "^3.1.0",
+ "d3-time": "^3.0.0",
+ "d3-timer": "^3.0.1"
+ }
+ },
"node_modules/vite": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz",
@@ -3305,6 +4628,35 @@
}
}
},
+ "node_modules/web-vitals": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz",
+ "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/websocket-driver": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+ "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "http-parser-js": ">=0.5.1",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/websocket-extensions": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3331,6 +4683,32 @@
"node": ">=0.10.0"
}
},
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -3338,6 +4716,33 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index b1eb22c..c25b7b1 100644
--- a/package.json
+++ b/package.json
@@ -13,9 +13,11 @@
"deploy": "gh-pages -d dist"
},
"dependencies": {
+ "firebase": "^12.6.0",
"gh-pages": "^6.3.0",
"react": "^19.2.0",
- "react-dom": "^19.2.0"
+ "react-dom": "^19.2.0",
+ "recharts": "^3.4.1"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
diff --git a/public/geisel.jpg b/public/geisel.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a1339a5592f6b7438b8df877871eee04fa3cc481
GIT binary patch
literal 18976
zcmb@sbx>Tv(>A(TumFJ|!6C4~VhIGu;x4=R0!z>c5Zo5m;2u~O3$Ba1y9Fl%cemgK
zCqN({zxTa$-|tr4?~hw`yUwY3PWMwiea@Mhu9@k7bN@Cl=^(PQ?=@iR3J?`}00ssC
zfcezM#MTM(8315w=Zt_U$}qjt(`Uk60$>2B0aySKK=`AHlY_K|h6>>SC|5I&>_?g8
z`H!#vBklj)KwxU-Wb$bG`*<6hI3Sz>01U%NOz7t9@E>gPh{-=${}=ZD4@Nu&_^3zz
z2b=#l&igOUf8)mg;%LKUA2~lBv6T7$hClsp`2XtnkpjRn;r~zb|F1Zkxj)7a04T@+
z0RQ=>|Ly&MzSaNeuqYoxc=Px#^8QC>p927ZFCX>D|IvL)1^^m@0e}|^|D$8g0su&Y
z0D$^Y6BmT*fA;~Pd2EL<2C+AH-17KibVPQPM#KFbG
z#lyq`U_6=uIHXU=nE7y@zm(SeNbX3%!tWo8_eKVhT{TV#`{e9WUDL%XASmP%uucVJ
zlQRiKoyeZ%)OJ7mqs0JVV*Nk5`;SX(9NZ_5Mm|yiCME_JCKfIZ;F0v7fG{vgv9Ou>
z$R7J~#CiUb-#_~#wyJA{Fics*>wa%IXl{^ED{tRz8EdWyI4f$C8i0fgFCia9WTmLQqO0<3P
zA&)YjNTq&Z_9X1GZWc3^$E8S6Fl_^=rISz1p`%Ba-&WK-S0poA_fr3YVyrh_SzDe{
zQeWD}WGG)*c3Y_|x{WJ0hJ#WTl+i@KY;#%UMtz`~xbnszn`_M=U#_UUT{|L$ZYpOX
zk9^uXDr&<2#iPTQ%MefpR9^M6jPEl<>Vu{ns35|gIxo_BT0QQKw$S2{;k=rVrmIe=
zb!A(~9ak#ICt;+{2r#z#A;-;m$Ck>LL`n2(q%&+;1e9}F46x9Y=b5aI;2o-VArfup
zKsUQpj=SoN`^fSyKR2%vMC4g;L90
zS-&Dvj;)@71@H!P0*#(zW0G$&jq@op$g?SkOeZ5u@G$5l31~5!HEtdR$5mjbua)WX
zLFKjK78{vS3>1IH2|YxmfQnfRUpU99Yt4P1#_&WyR5u0U%cMVl^|TvgJGK3Ew(s_m
z5H*$*FR7hDB2L0SkpZ4a)l@Emk&B>ZpEQ^ZuxVO+sQ)7{-Pb&Ynw&`mr|g*wF&``N
zl)?yXoYa1`_u$!$G)nvct3GXcDO+TjN8(cG2MW$Vu%Ci&89M*nZ7}e>RSMg60o;;F
z3|@f++o`9gk99P@}_Qj@zAO
zrj;lQgNv=cg@(oO+-VXz|E+@*Jw7HyebST%6$IDF9T!fjXhqW4N_)3T@dLKVfff{bCK?uhnR7&511bd8(d=`;G574R
z|H_xw@{9V*-eRN&!Kdee%{I5-o0Axn8{!-WS_``;eH{b?nvLUdMnu`$7+pK3_dLv>r6|7i)#>=P$59uW1(C6l=C;hs2E%
zqOv@X@E9&pqZuRl-i{Tufnkxt%94bj8qddF9V
z+;6j={;8U`!pucCE~YNw|4w}&yd?Zy3}KNdl&(Y&q^nJF^DV#VQ0v{^j;)H7aAKh@
zR}0zp%a`QFMArmntRidJ6oqY56ejj;$#X4EM~v0h0j1}k-%5xXWxF1rqUvRo29B2q
zR-yv8N=bgr=6(Uu%i7;%EP2jw}#!A+*=0ao;*X-C6K%2J-@Ox`WVeoSKARYrp;gzXZ^DAA3!qm
z)+*`!up+E|Qf9i~;u7sOVQ5h73xDt(z|LbAe=~SdZrH(H2H_=3soOiiY5o)!6UOPQ
zHo2cTCF68E&nPm)q~__3ec~vd7;EQC07F((O0+_Kr-i8MW;#y+
zZ_)>0?q#%9(bKm24Bti7Tk=^9Rc7*-7wZzbPNNgDr7^DPyW^j?U|DuDDE^drT3GKR
zo}ahO-dkTsBMNdHd=(M~iqepRoW`|80aTp@<{Zo-5eYi>pNZ7G|Cq+JSguTg$1)T4
zzB_tBYeUCg6U~gxK_BcC*m0M#0`F-qT)$0I(%WNg*7|Hv>1RYLYW57=3>aDsz4}Rd`D^TnkM)?yFkF7-Uch{a^aR{K8x+E|;Nw9cO@4`I))^2p{=<-xs{X~)=xr;8glWuTs{_+k(hf5pS>Hs2)6C7h__zpi(8NIG-JJ=
zYA(EDbjjpo{#=ssy!MEFLDb7ReVTU^e`&iO>XmH!4{#K>$v7dcQG!4!AVhT48Qez<
zjlQ9y(*~MI}s0VIP+wUOA}`
zYs*aYnNpsTZdX{TG{A70RaGzZ`%?Q}Wd7F_A>-+J50++Rtw6|s+b6y5<;^>Fp_
z-$stKs7wD@y!d51u8wa|kVKM0#*fZ44b)?(INJLbW}vU8f~JaY}s{Rb#u{5zXD
zT{?u5r01ILs#4;lMbB?cy40lZ28K_RWt(^V0VK$Gw&8K!6k(
zzIX^s-bwM8UrC&}Mg5u-*@3qeFbgvQRpo==1*BC_F5a`}8~ExV&C}<7T+kVP+G-xr
z;{5Mnmu*M9Gv6B8KZ`mTl<+Sl@o?(83lnnKVp(AMi3#TGRUfcrEhrx~M81(FrhiJe
zk?L!Bd|>La=aas)q8vV1%`^MUL1($wsoC3q%cQAJ@7`!tBz}yFRv~Z(PuJ2YUAW}u
z6gt&(yLlqj*mpsH0e0p2Q7RhzEBEsKnI~{sRzW@OK93pL5koC{^Ydq@y~^`Id284K
zNw8A%(N@h;5yX*1GJ2OmiD}19Y1dJY#-_FsL4LO=Fob=P3L4mQ^tNsDU=k(u~G&?^SziFdOel
zoo7Jahs+LvC6TDcs$n{^BA+i#5=Ok-HPMg;$6Md7!&^cvD|k>O5y}MF^wOa74K+)-
z*AAW%!%dNbvv}gt?iaoN#5@o?uk2(YnPGp54$lw%m=v$k*uu!Vt83w>MA9!2?_ikU
z-jHt=EpBObbmL0MG!SI!c)_>IA!6MG^E&=3*x0
zZuX{MArtk7Nry@GKZh?M;nW$UdX;72rOl~ZZ=X9Q=1)}Wtb#0w?O23){vh0y=yXe+
zeQPRR{oPU>#*^mU=KAKTxwMFn9SM|2w|Htcr7>iKF{X4Q>)w7|poV+>orb7Jdn@;D
z=TnjXWkMH?qVwFW1{TQTSw93u!MVhz_gWUxYmDX4a_{);9EUcVea5ofSnvOA7UhqU
zSLPjw>ej4&A^-Rfuu~k5s-3iUsb9gZxr}!sT}ZOrg=wSK>P3k8uFCuw+dAg8#ig^3
zXlCAiaj3hVNHDeS`~2Fg04p~iF2?y&adDI)pzkPBlMl2vqK1&4kr5h51;&e<=MH;C
z{QT=dfvK3FV#zvsWTN@TYQ`vAX5wTC1Z8MU00)y%tlLs6Gkwi+k5CLV5$8gaSfKqs
zUAxZ4JfZdyGJep@P)pbz@aizT;-X)RTOb#Z{Se%6GET+j1iiqh!)A@yu~#4XR5A7s
z08&n`#-j03R&KMJUpul>9X3sl*rb(V$tsMQ(G$BY3sv)lv}Mdy@XdAbA*S!jRw;uG
zx8q;K8K4kll_Q86IWfLQnHzNOD8)+tVKv_tX%kD6K!*+^jiqPijF>%_VvjF8-%0sS
z5j$9WYu~xd-FOSLE^f8{qZoY2ZY^Fo_sW*=Vt6GvsjewJ;s9hyUdq9&Y;nwq4U{Eh
zFL+s}ihHBISny=S_3KjuBQWNXy-m4D+p>AW+jE8WL(aVgiL|=+qMw=!?2**z46bqY
zl66yO1Z+@?_(DWnFtK!n*vj2g_pU%u#St#YJL@?5NYF=Y$|0F<$|ocX0|fnQ`3)wM
z`^-2=B=%Y5I((oem#s_{%)WahJ8ZE#k-c!_
z725ZK)uQljXx_S9>q3RK_?+`!^GujEBYC`FX4&e|((2T7`FnzIVFXqvEg$y+#mBV&
zpOuejm3pMJ+Hp!X^@@mqKE;wouZQEVB8NsV#)u4N>PRxpBGF)jFn4#z>Y~qO5R;eb
zrNsA?tb_I`R?Fx!@m%$#_ulj!v_j9z`XCPhQcJ%#V$Vy_CB_X${E8DW^6T%}TpX$3
zkOdoTkg0&*>kKmAA;_fwlqY^cen%?jj4^@bNIc|C^OHSbuN%}-;}$ws0RL3+2@hD%ZSdU(DKxZB<#2Byh>`cL;5zD
zw1ez~4)-~VSP@nGWnQKeR2{h$3feBj_cKdY5?86}4v8AC<6_4$$SkH`y|%5+&byfn|LoAv=o}
z_IzDEi9x1@Ncl$2APa44QDTxL7!!)0E)L9>Hgyc~U#V1=co~spRJT28ptmMimU%ZLXh6GDR+3^O3C(TCJqsDpT{
zWukZB!hI8XP<8e)b9lz|A+e}~&VZ`l;X&Hq5T|*YjMsJin%Y*{ADIBBXvYjrf9IM*
zhvs36_hResmNi~s1`D4$z~c+IcnX?*dYtsDOcOIy`{RUcUQd0`H>B-R9-Smoeo$Dp
zvH#)uQR}loG5mQIK7^$ve
z{=7uOYs5YLAE4ro>f4+wDP;U0Y^RxxIj2C3gT)GR665sCN-F7*Ng~i!-_uh1tf1qkcrq-+1p!iLx1U`^J@{UhB%`
z_lj=+0GoCS($o(h2PA_PAv1YHaQ-QV
zC~>1Ujuo4KPDXJmhFMQ;w)}ifxnc33z)I0|FlpJg9{^+udKlU=QY<>cDOhOaM3^K{
z#(_YwH7vL|hG*cl>HdY+S_lVpL-}e3)9}2oF%TzKsG_eyXQw|qYi>cgaI&mDzIo!}
ztV=eW078E*F1=Bk(R=rP;vTj9N~oniP#F^A=#YPJ8#LxD)cVS#*dZ^z!1YP51M-z6aLMoz&c>HG>8zc#vlJcZzZDrZrHu0@KuiNAZ>k;E|15k
zF~7X|lr?h(0bk7YEzL#B(-iM$M3Q(?*@KOK9Yw})>1BI$v;5SL_8$kmGv46wDdYxn
zE0oT{%o~+gNJhp_LT{xegsjmY2XZf@D0dKY1P?%5exQ5Swmr6ROkUP7^=2RpWvKwc
zfoo(hc(xwcF*ExTinzHGq|!F4psr7@y=9f5p-e!%&d!||XGMX!Pp!~6`yHz%ZSY85
zbBCeXxXq(`{!_LQ`$jobvO{jOM3i4GY7PSVO%Gv;BF*5WJet@3L~j&fwTXt!M}IpD
zbzhyyt|ngpiJ`YoLP6GVIV!NQ5NjTF9uc)7HPNTGx1QflEiUKKCxgI)2D`rRbLQsv#rlcK
zo?rCzYuj=-SIwrD7_}QyHD2g$x
zeXzT?fc+YwWR;0y=tD-6VD8HUW2$DwTlx2YhPA_q?bZwOiWNxqvHW~xkX8ywelWdA
z=f-Oj0;pf~L`)S6lc}e!@UQ$^omX#)YnLG|ExypNi$)JHec#QBTq_?Qlja|CUa!WX
zcAkq7bd2PT%6@sJQAC}rF%v%(gbkFh>d?H7WrenTv8&+>*8I#(j9d$Q1ZvY*bss)p
zBE%ivDW9`iu}v~irhR6?*Mt9BhApxF0|?6jz7W*D%y-@K{a3Z}k=spC*+6vQ1uOPTUrO?ldbMXQ6(}
znYWqKuXNHkYfDu4q~iqog9^_EJVXt*&eCF@Nf=HmC|c+T48B^w*ko?B`)=q_wJkt7
z6;!yz!4=GOgoX60y)VH=c(N^-RU47@GYL3AOK}2iFw2so9QV%H
ztp7!R+Yw6@V}OdBL@M`;LHrc8DzyfqY#1R9GyDE@?N;KD()p9NnE51&~w3GPS?b$GT4sS
zCdFWxH1(N;wdX%)W-87onCVU_rOX;=q
z?1!~oq&n8&Y;e7TdT}QcLXia1Yh9--fdNm%iC}RKw<27zX`TinMaMU)Sq@1`_`FWj
z?*QgMwBost+!J+g?Hf`9D-s
z2jIqgKby6UbRvLqVGI$Mp8JarE=rvB2De)oYeTGQfv!KrhotbXmtU0A8!&SfQ92C?
z*iVif>Kyp(EiF6crR^2>gji2aQCOPeemZaIX#6)R`Q!+=tmC6a->>O?$xvCn!xquX
z496mnX6KM@G`YCr_F2iEQk^IbZE4hcK^lG^fo>?qUrWIyHc<7mGbBnxNGL+Yz_J(g
zw0U6w43_LhX_;|ABNQg)K%zBwoP~*sWgf;*H}i{V_?O_fhIt$xf8=5LQJ^IM6#SVi
zpmlUt{-`YenoK9|NVy@Wj&+NQW!}6o;}GmyVma?86QIueQ8w$munPK~^NF4bNphY7
zr!2>Q_JM!UL(kU30#{NJp&7>PRHjrl;BIh)FP7-fE(A4Mic_CZ&}x&5P?zBs#+^YP
zSGQsk#7GHCI%Hkj@YeP|tv%{CfLyZoDP4~|$wwE+AW<120_*CBd+PrHac|?hRJ#^U
zr=;OM**i2aSalAjj8oKBY!rz|Or}k;op+T}*x$EWX${P1rpvB7naE`b&ln-M>E4_2
z5v@())(yWiSlInMV|C<8HfX6W;sXA}>0JFJ-={kO<`k6RI3nJ#w^%m5C1}&2oVc+F
zo1p!u2!dcJg8ML7*jI{7;^wi>6gU@2wUHaz6ix1XNJ>e20qT@H+}DYX!|XjY4r~7a
zLl);eZ;o!L@K7uaU&Mw`Vy&mgVt;r2qtCGmShBFvGCTfE?OLNiMLf~v+aN-%B1eov
zlh&tSS8IJ2=R1D2KN25(v{S6je+zS@H-Oqum06?Ihd
zIq}inPT`DjvOZkxEYg2~0Vg;QFc-bwk6ly_9?9bf7NJ1h(8Ho`JWH~6`8|cln<-ja
z!qPogmMiJ9vmBZvyBO|u#vDhi`FS09NXN(%f`sOX>VtxSpvOHTzs+NEhu-Bt?sTL%
z{nyW7#vT~?aow=zgA(DFH#5p5m(Ho1KNTXfmSopCW$NSZ$!}w{cFqcq-j{A!QQH9v
zB**
zR3>e+7zKv{9SE}4bcm~wx!|j#=`x_>O_jIrHKjC;-W@JBaeD>or=VYJKR-l<8VJjv
z$o;a&MJ`Ipla79!GI!i9s&{*OJ2gVhE`=5&RI*ur+o!oVkPuV_GeUdH;5tCnj=Dbj
zP8O>OyuZRF*n3rnl>zbO+NHKq`|Tc`j|U!{lQBX{c4!5|W*cGGG_Aj<;#=rG8}T{nVYO+O*CXD8
zs)KI|6q@GBsknS5_%%XSwhNN+N9P^s6|?RW+Fa=?1kJwJ(F1K7_qnFmgUv!;3N!ce
zzrbgfS7oxrSL)(q0rlViT9-ZU{3FO
zeZr!-8qq)8p7Gbu#O}l7$zNs@@OB)|@YYy5G4nK1Z581A$Px`=+38R)g06yygT<1;<9F$rbv_bS(5hNJNP~ctYC~T5G&E(HJx^T@#Nb!tS@$gOT|xr
zC9O)QQ&>Ui04JMj4$=%Jg}Xi%2f9`>#$y6o>2DXGS&8*6a)!F$&jpJ-!3@XRPrqd8
zY?sCY=QJ}1?HzGhPt6J}=Itv898^4G;Z+vR<$1?$l}3P5gG8dFamA%OMR5KBDo2b8
zZ24IS4Mm$G^3b1X65oT41A`Ldk!n+y{bJ67kQq<2NTOqx_GOm_E3hrsch2WU`gGEJ
zNc`@qDbux^*g&{A`(k;;czylRo}6_FX+)GRFGjCepTTjrZ1_7Mvp8n8qLkFGZhf!T
zn`F%go(u=A3~~~t+lYuim`Rv$86{2)P4M1W-~l}RI?y+hb6tr0g?dNum+XGhZ;AlY
z8Zcm!eJO57lRuROVF;ZN>!ctrEKjB9KO=t`vW310_A4NNEC}#m=b_6a1ze{p`TlRsNgRt9;c9wYJk4{Ie#pV&;gmR*b?S^BTM8Q~OjFi~`?
zl$b-p&Tox>01=V8$Y2zqrFRBdLQTz8fV@S2$!Ivt%OjV~i1_J96VGbqh5&_?^}EWy
zH2G9?lrLVlwC_Q0XO=k~#iAU27S9zchA|Fnpw_EJHeM?HThj6a1|?HWHQ>Whc#dps;AG=5?{z;
zp$Rr#@B5i9TbS-TwmRXnArFw
z$*LHRFzb0kZ_U)g%w=ExgaD>)EOx-?1*3+-^5rc5p0;w-SA0+5_EGz0A)`rDjY~UI
zor61|wOKwwQT@K)Zp%EW#sRWue|dR!E~w)gviN#6hH{$k;WSi#xCBb}7G0H|E8Hc$
zxuioNk6z5%LrfE$m`XHgXUJ$Z#`*WFS%H?VnMVed+vd)=tK(y@QL1m;w1!-ya5MD>
z@iEj2k0oR+`c%ya3rCWEeW@xTP9i3Bc;94YoTd%l1BN_Pa3Fsh8$0?wfo8<+?T2Bf
zqtoXduK!f-Vulg
z*nR?(O8~==1fvqNSP}KEZ}J7?XC6lS>v%LRYWH^e1I!ke8i7S5fQ5tsTnB|MG`pQP
zv_8ruUpYthf+zTs$4ByW@l~_FP2V4P?9<}KM&Ii9-dRWgh;PnzNv1d@%JOqcf(76Y
zbSept8h)5gsx{~^zqM9V8NW49-XnadKqmAz?OQvM(SIcp?wcD%ZblgVB{P)9Q*h@L
z#?-3s82aqn5!A*q|DAKf6C<&mu71Loes2WhD;m`KG0K5Pos-e#yi&%M`bK<3)Y#`a
zIePBG3DT!^KD>l7Yv#DrDHok1O8jy@$#jNyn0qMrBXrx46)34>^j_)rFAmSmLm^4|s?PI4
z)>Jj*c)coafyq08gtiv5a$!!QtYfWc#@fwDu`+YI!t-lKEu(3yVJ}{6vtAJAi$w4i
zmQqpNXy(tyLabyP&(9HWgi({@l=*G$Hxowv4M&efVA*$HflFVcv=XHmj&gs%ZC#24
zZrpZ<1B)yt8>@f@lc?9^n9YvAz-yk`=_Pe#@&r>CPm&lknWuSGP}&c04-TMV?10iv
zxwQylZ?#YPRTg-IBB<3+7z$ViIQOSJZOGb(LId-jm0k>M;DbeZsu0guc0_5sG-u
zOTo;{On}F+;1G*^tu8&t;A6SnU%Tk=M0HVnnfE>Bl-ruX6brtU55Z}+9FHY4N+3Rb|zzWbee<(dGr=k^EVb#zP#^>DO~T^aD@M&pco)=0it=JgfNUgX(ezMC-qNi
zxB8q#=AM4X>zv?c3#*{tQiI)w_&{dgEILoEqUQE>ev^tN?Vf(ag(QiWZ>*P)LVgN>
zPI|tm4_X{UX1}(?rr!NveU_N2fe)>kav4=&Xm?Q)XuyYtnc03wcr8Qeamo_Yo&Wom
z_|AONbs54&Yqxio$^%~7Ef3YRRc1_m4-3HS8o+X+9+4H3W+2l-A!7Lc0icx@BR(!;
zn9_)JWfBZ-W%j3Y+SX;=8O^Z>{LA>K-=SHhCLva+T_xAQCTI`$9
zxQ)J2GBrWq0?(*5oDVm*4*~;2O`yJkyZj`C=%Aq-dSF}8u|K>faO&1;im?;(M20++
zG=nnO4*O5_n|(fg(P)W~8LBF-J5imD(L$y>ozI2>Jz7S?P>!V>@_AaVDWAA8C%FlO
zfC~SRl=_90DW2Xb?l!i?WjhZZF#}`Q^a6(+>K&{yJ>F(>dD`a<2F`E47q9sRix
zWkR%PmY8q)CXrXb1udQBoQmh2Hk4m{I<-RJZ#oT
zray(o{q)#mig4!d<4n1uMtmFuxv6#kZstt^tuC
zt1fHg1h^a+$%SkwdXmw?4Lus9IR>F90C>x#mv%Vj`ytPVp_cahe}D<`J2{)5|JOE)FE
zZwT9xCbGimy$O(pMZ_S_*|(twfi~kWRC$IJ{T`?hfZyeH
z#1NYMpM%e?&hvZa?FN4PAFZ4-^wQfwm`X8W^J1G*cjmt(bYhGv;x4%-P}&+g@d6}T
z`(N(-)$O!Qjq|CLcR80R8eG5plDyx{D$qpr$m9i?eZNY~4*0UC9N!!ekxgh8vmUo1
zd07!VOULT@WhQS)&w__E+1F%HZTl^Kf=HGG1eftmFPEJsT}zPCELWt^x9Ike)o*#A
zm2Dg;ibJ|IUy4F2wOQL{hG8xRSBZTx+Bk<#I)BMub(r;s^a|x|wmP-QD0(VPT_~}d
zlJn&^=j{;;CPE6k4DMbP1&_u!#yKMdkDs5=MU_Q{1A_(f)!qaI1Dpbgl?qh)<+M*;
z2gt}6P;;`b0dQI4Ii{MyT^0~;2C#{aFBSYU+evJ?5%hOd}
zF^?hoTaA?;MXG`ESSwG-oRA6_Pl{VK0-A`k>y=JHQUKiH2{iAl!Aj+nx=|fnQ*)rk
zG9y&EMA~tWmt&nrC@2~iWgyi_hhaQ)NO%VO-1%ugV}?bL^8%H`^lnNvN?Ket=8{-^
zH$x-39rz)y0&NG~_oDs>_|Sn$Yx}@t2OrnXb@X4z41*6Rn5h|
zL$SU)`BX)T?fOYBdO`nV2rW_l1fUZN0|SWtU_C`voO+y^`|9Zga`{_Ae3~L6x>Dr?
zM*ykCjM`+I^Jq(zS*HVdI$>U2~;`cHK0IOVUC9Fof79AXNVj}ks&&AL=T+9&QT
zS*)4e$>23697L8dJs|(UAp?SaLl6(GhBS4BY8+cN!Bm?WU^F0n
z7uf(UzlzL)QM5uR#=AANm^rzrnt?JgvoUk$PF8ljEiUE8pptH6dc@j~JGlni$y~bH
zgLedq4Z_$C{CG?^fhzfiL_^xix|qYTO!r1~zlFd&EGFgox|*6gfY=iQrtcG1Xq=3f
zCk*@+Ga@sCRFahfS&rr}W%!8ii)caAHj)TnJ^(BRov(j+ziR$Th@D_2KDBN2(?&ud
zqqsA%pP?@-Ra+NPDX{7+^qGHA1gaOsh|@qV2*08#CQc;C6f
zwP>(JoiuWR6y=VOou;i`WCJaiON$_n7n!*0GXyL9gGZ|_B&Ml(%<7sG!xXlOv%X;I
zMiOVnx3N35X8*C**G9|xWTC0_k@3GFb5ea;18{W;SmF#BoaWT@d1rCG5px~twpJ|6
z4JVJ;UG~-Uu?u|7iwlYOyoq{5pvp}<9H1-+29FN?!RT4oVIQ4Op0Oi=sfKuS*885V
z4p`6gQ(|XE96yO-V+Y6*bvx-WTs%P~I5`MQFb|T3#VuFlYa$`}F?!!^Gd5J>88zy@
z&?K~%S@Tq{2Da%fxtZrUX+SNv*4!dBE>}G6>ww_iX)-Pm$Vho?FnWLjZoKc0OupnOEN>gg5&<31T5D&JVR?$O`l{=&=3!%OHRjk
zlHur&(lL0LL-@KfIZi2gqP&~bzzY=@W$Ql7G?+h2+J_UTJ^gR)iA$Q&r$loD08{5Z
z^`PfeAdR7IH={(#OCW)++&WW?%|8IaC`04Vl)LiQN|}T-^1xA*xahhMv#&&qLtZT9
z6{&$Bun-IkCX*N$s|vcpxYYtXC8og4<_I@uZCD9~ZT)1^^1gDq+LEprc*!Awqw%g}
zn}>|7)H73h?*Qi7mx|EWkfHF?#_Z~1dLB{n4ROV5I0Z=fy6x46P!nN%#VgL?4jw1hrJjI-}~btF;&V&cJQO2#ooO(7u3bVPL2LupS01O
zjH8OD)~H1f(t{zz$@#9rwla-5CXR8gh-{~mB3~q?i*p-HGS&J5>tUt^E%2>)F=;JD
zH};PZFx{!q!~$Zk#9o72-#kZ$&}W
zvkhLt_ZU_WY0qqGT}9>^m*69JhM?-uoji({&ooX2so8sCqX~m>O3e@R9*erNS{E)J+lqTPW*!gt-`cYrs*tX;B3W6>`
zm-UCPL00f>I+99oiP5VVQD@h6TDXxJBr2Y{NF8Y5Qb5)=1OaxJRh0OC
zcb~g`Uf?2_2{&k$R2#K(cE||@;1CN`Dsed0eN@uL4aOLoDs%6z?il*S5TX%WcsP--
zw-o)Icr<$5SIf$lmu$269hZBN9mY_%fsB;8Y^I9v;w$sPu)p~(hSVy2>AiuiX-`J6
ziq?PKei5Bp|LVrc->zIoQ~3UBHcP`mC0+U?((T;R_xa$8WEvg>+iQpXA3*ae6YX4A
z*K{o!87;K;ou@BqGa4*56OR-FAav3^%vlLQp9XOdk;-Fe6q$2gvR$@L=AGQc?xf@8
z)8U-5t0G*YavNQfW*-SOWHsQmbRQnm4z7T8l0`FY+RkwMJ<}2m-pT^gpzM&lnQW)@
zf`^R%PL$KOGVv@h8N|s%oVTWfX>Qw=vG_|V{FSzx^69dc8g_jhAPc4Y
z3#7K0hM7lUk~zV8doDZGDs2-18{h<;U85u7Fep}F
zrgh}=en+$iv?$=w#Zjx-jehIgJT3E4Zp=`+j+enFzyicQE~Fe)376=|z?TJ9AvsHa
zn+USJYYQ1dISxclY2dZ5z%TJgvZr3D{I>lcH2&05;$xqb#>d4-q}@(AL4@R+NLFKG
zGir@bb^w=W6kJ^D{n4RQsX2_?rR@9PmXi4KMRi(+8GLh+`D|6tT#YV2gVrH3-b^lo
z?{K%Z3nx)D@uSMS{S3`eJF|;A0@-~HC?4|bAS>Ms1K+4xhYRU*
zS{I(@)@)kVeLcO5=5z>;v%TN)RFq}Sx0s7+g=vRZv<^A@cS+v9%wI(=9!Gz*sghat
zX!-JzHu*pZ#4;#`JPA3WAem7ad$+%B;=;5073NFci%==?HqEtyX(J1aGypDLGEV2k
zcOZ?{cc@CWgLo<2hcl;lXW*u0SF2th(NrqCahASthedkS0pdg7M=uYlrP~>dYkW0d
znbzNeInVYzx1Na~j4ihbXY6GM7`N~!zSw$8kAHtm(`lEAS|Rf`<-mO6f!w9v@Fd(dsisz79{~q0}eV4}C?{^xotch?=iN4b2WHkSU
zHV}OLi9fnMoMM+S)2vxrZ!23Uamhhe($L7s9f(Wt^AIbgr$xDXux8cFfQp$Q_C+oE
zftO#GjC$3sr;a6Css;CnC7XE?pn#Pn>PWc%2Mq6HPnutvC#IExn459h0Tk!5eh@Yl
z6c-fp=4_N5En)Rc9|q%(8w+@CaaQp)@atco&Kv{=b7OU857Z>vAUnmP%VUtZt%aO0
z)5eWC#w5rn{k_5VbNvUPnT`haj0)RH4M*oGz7tz>zPu{A8Fi>u0!yD=6i4L+zh3(Z
z4K`q0qIEZUAyac_dHNN$(t2inLqdQ)bJZ4>ICv`69S>{APv}Uz3e_r#aH>-Kk
z+7#{X5H2;2p?3T$gn~{b533J5Ela>U*YOkh;
zqe@MP16A0wgA94Y4VoMt3*cUyl(57YON;$2;*TDl`s7vBYEEdE{nMLJrUQo{ZQ4?I
zJhl&l7Y~ybesJZ)XS!DNdYicnCsLC+yu0c0sEcW(vGwLATqcFn`EWhsaA+V@d@$wE
zjxvuw3@hmvfxSCcX6DYav!utP=bJ1T4NQAs;I&G^Cfa&$7?SW0a8|&-Q7jN%77Uz7
zN~&V|BQ+=)lfbLFpHm(w8qFr&PV@AwQNY;3_d)jFsKD7Y^R$?j2z3)%S$;~aA&)!`
zc1x#bR#X~Sj+#h}qmoQ>8wLNnQ2GwyE&e9rc*?O_(x9~Ss1sp2^O;y}bV75Ib`AEFZAwKzH+ZMAc2Fsh{b_g{TP>gaBzFah(`j(&9?_K=7X(3`g&H^LE)9iV}M7kvnEd6pMA5}{iZ0(}S>4Kj6HfO(WDNlSrX
zz9<4z@~ZxL#)Tr9yOA>0{~tg}V;N{0Tm-_yKfwgQV0@@iW4iJe`uhW3KAG3TN#Ipa
z)skx_FVFP6^PqDrWrTEv8x57wvor)(u1Ia&{~1xv9{2|!q1VjAYay-jN-X8^ZQLpt
z%?Jr_h}4mnuU&kVtDJ)A@=3mb1zf}NF1Z(?O#Y&k0TeABF6cd!wfN{=uD;Sc@;
zOtI5Fb*A@(TeYGZqp3@ymUIUiOHHDz)uu)q-wWBl2l$Vo&c%*^zLxqFP^DHSe*c3!}KR)?Fda)_}h
z_8QK;y3vq0EEnY%I2+??MGDKoscpsRcjx6iy}LLseO+ke>ziMI5M-;E2`S5drO?!Y
zkiq-?ww9K23F_w5Buno!x&)HkCZi|(2avB9$^mmVJPkaEXFSVom}khb#HK!>A7w4@
z4F78pdAM*->*%VYCUOt^Q_!t1R`s*HTS-u$6dY^e@3U5wBbSM@`AP)X#a{3<A}R{&hSu&y<`3sp9{!QCjwXGO4N$sMPzasyP5y6OfDyEz4J!r
z_AHcf8VqQjiJzq|Jn_Mhm`Yv?yh-tmecTC|7-%7l6*^cjO%tXIDg{k``ex&V+g(DJ5(!NBE^F$MI&s6YwD0M(!kq
z@Sx{s$TxW3|+#2+?;(6V$f59ewlgYU8Ztt{=1F=U;-y9v`a
zfaEf~@458q6&jYtMkneIypK=BHol)w!`EA|(vvUu_Ee}oP9DA?FHqOJ>;Lq&F)V$>
zU6+B3uTvcpwUPNDUL|eB8$9VI{8dpCuAR8T$%No*nJvfdATNb*eLlBzFFWy<5LtmO
z6A%G;gDJ2J0Xlx_hkaZ+2{{)_$0r?T=KJ}S3)&v)bq$1P7^da{2^f;um0F=Dzk%97bCy
zaWVq{#9gyPMN|fL=_Gx=29RUqjdEc_v%aVzt|k1~`_@C}h(1Bj1k||KYQ-*FQRaV2
zQoC!(q2`W(zi)}x7PX+4m?z(^Zg7B%rvi3bb_#86eKfIi(xsYQ;$z&l2z{p>BpV9&V2i9^rIe5o2o7W??&RQB7{e-i
zNuZxoTaGl&ul`BhRdu&pb_(pV9
zX-k~PHoU0H+`%d%3R8Pd-bl_l08uJfk;9jVr9!-XRbEvqBMlfriH?)^ufJSWzfc@yeVxB27>w5zc@I@4uaYg2Ds
z*2_gGDrHesfKCFiqMkV&anw~J=V_f9V~O}zl#ou}2rApSfK|63biwk-KGiUYYHCi&
zwz-YUax$NAI>N(^6M#WU7z-nA4m0xS4AA=>!wQ8R`00GDB~CoFo$6i=#An7j;XX&6
zf}Mw5o-d`O{@=*C;!@nMt~AH+hGIxrTVce2+2tFE+EIg;`~8Z4M>WDFtX*8Q%vrsBsf#+>pYOgf`$MUD`py!j?yil0C;9oYGBBop+Aq(YeZl1nw*-yWTAb
zJY#0ilg4=@{IF^9_MSxkEPHzY0D`^6?3oF63U(tU0Bs0uN>&NlJx)2rLpIa$*6UH(
zeb-sZbtz?8ZwH)=apm~c^^3F@V9JjgOcY0L4VKjC&Q+7V6yqCs8$dbhp1f5b)Uz#e
z3wKAO7G6PhuIG)a!h!(=l&BN;@t+_mkJ>pT+KxZfg0S@R$c?2hCm@9(!W0isN3Cd6
zZkjQDlg_rtj^cHK2G00e)3k1uk`!cTaQd^3M_wwQ5!pACI^(veQ&Q5f^t4LaH+Mlw
z85rk+NF$8&8LMm=ZaW>h0t8EJMMLh^vf+KjBXK?=a8r;o=j3X$YoXG<7ir%s^Xwix
zb4}NCE^UzPha<;5>bCem;O*e#k1jmwX76sey<`oD64asH6NX6xs2`3ESjF=A(`_+l
z`WY`5JESt?VuF-yQ7)|f`T@8d#GGRkXCq(TM7OV+iKMn!-?|Y|bR6InDDmBbtekRB
z9&|6-GrCbq{9AAAiuXQcE+&${&Pu~Jd3Xs*_bI;YV}rp~0XRK9kD;xSi-)#-5p>dnS7_Jke(09m~%0ZKnt(4I*IahlDqEnXIq{g(SF)|7y
zQRHDGpuzO2Wa*dQ@z!RU`$;HYfkiIkt`9;y@;dc2KKDL)-YI==_dz6~dlz@Llt|-i
zx>rrIq>xHe4bjv_u{)Q>wNxZDl(}Vt;X+1GoD1@8P=V@iOqtAxx%VjDJpNmRD
z0*+4susYO*iS0XalP)Wsjj>j_MYawI#=0aHS|uc9oKP
zU?&+Q@mHHYyHneoOo!n`mVq4$F`hlsgsoWENF!>1IXk!ms5DZ|7`l_BTE{2BGpN{R
z(P@I~kH?!G`7iuBBdu+|k^*9cOKJFuQd;jzW4mqC6$KQjyzWm5N{0Z`Porjh82ESG
zY&yb<-wZ6NI8X-&Ios7lA20y}noHDS#+!3rK%ObS#UjUig=$jP(m|sj%aH^C}5e2?_@wD?Ss9
z@qkYvq1C0^+^v)1l;?t(E5<#%HHKQeQDY{>zj7
z^iZKj3JW{)alfe}`{I|A{`NoppA-K8?Jk81UvSXI!_}|&%KrN5-`S7*I_>?fKm1x0
zDy72;J&Tmj_Ef*rbN5%CJ45`MhaQk6fQ`-KV>+cJf3s{a61itpGIC{>Yi
zTzez`0D71GSzq22WS9Q{nf|L2{8y+@u3mrprRa^g{#IV%f4esC>TZ8^x?X?!?62&W
p{{X|GLa;xbja-dW{_N@>?1ujUxT?&V{L(*EP@zo0%!K6R|JnR~jWPfL
literal 0
HcmV?d00001
diff --git a/src/App.jsx b/src/App.jsx
index f67355a..0a6269c 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,35 +1,236 @@
-import { useState } from 'react'
-import reactLogo from './assets/react.svg'
-import viteLogo from '/vite.svg'
-import './App.css'
+// src/App.jsx
+import React, { useState } from "react";
+import {
+ BarChart,
+ Bar,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ ResponsiveContainer,
+ Legend,
+} from "recharts";
+
+// 🔹 Temporary fake data per floor (we'll replace with Firebase data later)
+const floorData = [
+ { floor: "1", devices: 8 },
+ { floor: "2", devices: 12 },
+ { floor: "4", devices: 5 },
+ { floor: "5", devices: 10 },
+ { floor: "6", devices: 15 },
+ { floor: "7", devices: 9 },
+ { floor: "8", devices: 4 },
+];
+
+// Total across all floors
+const totalDevices = floorData.reduce((sum, row) => sum + row.devices, 0);
+
+// Data for the bar chart: all floors + total
+const vizData = [
+ ...floorData,
+ { floor: "Total", devices: totalDevices },
+];
function App() {
- const [count, setCount] = useState(0)
+ const [page, setPage] = useState("home");
+
+ const renderPage = () => {
+ if (page === "home") {
+ return (
+
+ Geisel Wi-Fi Occupancy Tracker
+
+ This project estimates how many devices are connected to Wi-Fi near
+ ESP32 sensors placed throughout Geisel Library. The long-term goal
+ is to give students a quick sense of which floors are crowded and
+ which are open.
+
+
+ );
+ }
+
+ if (page === "about") {
+ return (
+
+ About
+
+ ESP32 boards, programmed using the Arduino IDE, periodically scan
+ for nearby Wi-Fi devices. Each board records:
+
+
+
+ How many devices were detected
+ Which floor the ESP32 is on
+ The time of the scan
+
+
+
+ These readings are sent to an online database (Firebase) and are
+ visualized on this site. What you see now uses example data; later,
+ it will be driven by real readings from the deployed sensors.
+
+
+ );
+ }
+
+ if (page === "visualization") {
+ return (
+
+ Visualization
+
+ Bar chart of number of devices per floor in Geisel.
+ The last bar shows the total across all floors.
+ This currently uses placeholder data but is wired for live data
+ later.
+
+
+
+
+
+
+
+
+
+
+
+ {/* 🔵 New blue→blue gradient */}
+
+
+ {/* light blue */}
+ {/* deep blue */}
+
+
+
+
+
+
+
+
+ );
+ }
+
+ if (page === "input") {
+ return (
+
+ Data Input (Demo)
+
+ In the final version of this project, readings will be sent
+ automatically by ESP32 boards. This page is for testing what manual
+ input to the database would look like.
+
+
+
+ );
+ }
+
+ return null;
+ };
return (
- <>
-
- Vite + React
-
-
setCount((count) => count + 1)}>
- count is {count}
-
-
- Edit src/App.jsx and save to test HMR
-
-
-
- Click on the Vite and React logos to learn more
-
- >
- )
+
+ {/* Top navigation bar */}
+
+ Geisel Occupancy Tracker
+
+ setPage("home")}
+ >
+ Home
+
+ setPage("about")}
+ >
+ About
+
+ setPage("visualization")}
+ >
+ Visualization
+
+ setPage("input")}
+ >
+ Data Input
+
+
+
+
+ {/* Page content */}
+
{renderPage()}
+
+ {/* Footer */}
+
+ ESP32 Wi-Fi Occupancy • DS3 Geisel Library Project
+
+
+ );
}
-export default App
+export default App;
diff --git a/src/DataInput.jsx b/src/DataInput.jsx
new file mode 100644
index 0000000..536a03c
--- /dev/null
+++ b/src/DataInput.jsx
@@ -0,0 +1,69 @@
+// src/DataInput.jsx
+import { useState } from "react";
+import { db } from "./firebase.js";
+import { ref, push } from "firebase/database";
+
+function DataInput() {
+ const [count, setCount] = useState("");
+ const [status, setStatus] = useState(null); // "success" | "error" | null
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setStatus(null);
+
+ const parsed = parseInt(count, 10);
+ if (Number.isNaN(parsed) || parsed < 0) {
+ setStatus("error");
+ return;
+ }
+
+ try {
+ const readingsRef = ref(db, "readings");
+ await push(readingsRef, {
+ count: parsed,
+ timestamp: Date.now(), // current time in ms
+ });
+ setStatus("success");
+ setCount("");
+ } catch (err) {
+ console.error("Error writing to Firebase:", err);
+ setStatus("error");
+ }
+ };
+
+ return (
+
+ );
+}
+
+export default DataInput;
diff --git a/src/Visualization.jsx b/src/Visualization.jsx
new file mode 100644
index 0000000..c7d9e26
--- /dev/null
+++ b/src/Visualization.jsx
@@ -0,0 +1,97 @@
+// src/Visualization.jsx
+import { useEffect, useState } from "react";
+import { db } from "./firebase.js";
+import { ref, onValue, off } from "firebase/database";
+import {
+ ResponsiveContainer,
+ LineChart,
+ Line,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+} from "recharts";
+
+function Visualization() {
+ const [data, setData] = useState([]);
+
+ useEffect(() => {
+ // Listen to data at /readings in the Realtime Database
+ const readingsRef = ref(db, "readings");
+
+ const unsubscribe = onValue(
+ readingsRef,
+ (snapshot) => {
+ const val = snapshot.val();
+
+ if (!val) {
+ setData([]);
+ return;
+ }
+
+ // val is an object like { id1: {...}, id2: {...} }
+ const points = Object.values(val)
+ .filter(
+ (item) =>
+ item &&
+ typeof item.count === "number" &&
+ typeof item.timestamp === "number"
+ )
+ .sort((a, b) => a.timestamp - b.timestamp)
+ .map((item) => ({
+ time: new Date(item.timestamp).toLocaleTimeString([], {
+ hour: "2-digit",
+ minute: "2-digit",
+ }),
+ count: item.count,
+ }));
+
+ setData(points);
+ },
+ (error) => {
+ console.error("Error reading data from Firebase:", error);
+ }
+ );
+
+ // Cleanup listener when component unmounts
+ return () => {
+ off(readingsRef);
+ };
+ }, []);
+
+ const hasData = data.length > 0;
+
+ return (
+
+ {!hasData && (
+
+ No data found yet. Once Firebase is configured and readings are
+ written to /readings, the line chart will appear here.
+
+ )}
+
+ {hasData && (
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+ );
+}
+
+export default Visualization;
diff --git a/src/firebase.js b/src/firebase.js
new file mode 100644
index 0000000..a0a3f7c
--- /dev/null
+++ b/src/firebase.js
@@ -0,0 +1,25 @@
+// src/firebase.js
+import { initializeApp } from "firebase/app";
+import { getDatabase } from "firebase/database";
+
+// 🚨 TODO: Fill in these values from his Firebase console.
+// 1. Go to Firebase console → Project settings (gear icon).
+// 2. In "Your apps" → pick the Web app → copy the config object.
+// 3. Paste each value into the matching field below.
+// 4. For databaseURL, go to Realtime Database → copy the URL.
+
+const firebaseConfig = {
+ apiKey: "PASTE_API_KEY_HERE",
+ authDomain: "PASTE_AUTH_DOMAIN_HERE",
+ databaseURL: "PASTE_DATABASE_URL_HERE",
+ projectId: "PASTE_PROJECT_ID_HERE",
+ storageBucket: "PASTE_STORAGE_BUCKET_HERE",
+ messagingSenderId: "PASTE_MESSAGING_SENDER_ID_HERE",
+ appId: "PASTE_APP_ID_HERE",
+};
+
+const app = initializeApp(firebaseConfig);
+
+export const db = getDatabase(app); // Realtime Database instance
+
+export default app;
diff --git a/src/index.css b/src/index.css
index 08a3ac9..8a04ba9 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,68 +1,239 @@
-:root {
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
+/* === Global reset === */
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
+ sans-serif;
+}
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
+/* === Page background === */
+body {
+ min-height: 100vh;
+ background:
+ radial-gradient(circle at top left, #3b82f6 0, transparent 55%),
+ radial-gradient(circle at bottom right, #38bdf8 0, transparent 55%),
+ #0f172a; /* lighter base: was #020617 */
+ color: #e5e7eb;
+}
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
+/* === App layout === */
+.app {
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
}
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
+/* === Navbar === */
+.navbar {
+ position: sticky;
+ top: 0;
+ z-index: 20;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.8rem 1.6rem;
+ backdrop-filter: blur(14px);
+ background: linear-gradient(
+ to right,
+ rgba(15, 23, 42, 0.92),
+ rgba(15, 23, 42, 0.8)
+ );
+ border-bottom: 1px solid rgba(148, 163, 184, 0.25);
}
-a:hover {
- color: #535bf2;
+
+.navbar-title {
+ font-weight: 600;
+ font-size: 1.05rem;
+ letter-spacing: 0.03em;
+ color: #f9fafb;
}
-body {
- margin: 0;
+.navbar-links {
display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
+ gap: 0.5rem;
+}
+
+/* Pill buttons */
+.nav-link {
+ border: 1px solid transparent;
+ padding: 0.35rem 0.9rem;
+ border-radius: 999px;
+ background: transparent;
+ color: #cbd5f5;
+ cursor: pointer;
+ font-size: 0.9rem;
+ transition:
+ background 0.18s ease,
+ color 0.18s ease,
+ border-color 0.18s ease,
+ transform 0.08s ease;
}
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
+.nav-link:hover {
+ background: rgba(255, 210, 0, 0.18);
+ border-color: rgba(56, 189, 248, 0.7);
+ transform: translateY(-1px);
}
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
+
+.nav-link.active {
+ background: linear-gradient(135deg, #2563eb, #0ea5e9);
+ color: #f9fafb;
+ border-color: transparent;
+}
+
+/* === Main content wrapper === */
+.main {
+ flex: 1;
+ max-width: 960px;
+ margin: 1.7rem auto 2.2rem;
+ padding: 0 1.2rem;
+}
+
+/* === “Glass card” sections === */
+.section {
+ position: relative;
+ background:
+ radial-gradient(circle at top left, rgba(56, 189, 248, 0.2), transparent 55%),
+ radial-gradient(circle at bottom right, rgba(255, 210, 0, 0.18), transparent 55%),
+ radial-gradient(circle at 70% 30%, rgba(99, 102, 241, 0.2), transparent 55%),
+ rgba(15, 23, 42, 0.92);
+ border-radius: 1rem;
+ padding: 1.65rem 1.6rem 1.9rem;
+ backdrop-filter: blur(18px);
+ box-shadow:
+ 0 18px 45px rgba(15, 23, 42, 0.6),
+ 0 0 0 1px rgba(148, 163, 184, 0.25);
+}
+
+.section h1 {
+ font-size: 1.7rem;
+ margin-bottom: 0.75rem;
+ color: #f9fafb;
+}
+
+.section p {
+ color: #cbd5f5;
+ line-height: 1.55;
+ font-size: 0.96rem;
+}
+
+.section p + p {
+ margin-top: 0.5rem;
+}
+
+/* === Chart container === */
+.chart-container {
+ margin-top: 1.4rem;
+ width: 100%;
+ height: 320px;
+ background: rgba(15, 23, 42, 0.9);
+ border-radius: 0.85rem;
+ padding: 0.8rem 0.9rem 0.9rem;
+ box-shadow: inset 0 0 0 1px rgba(30, 64, 175, 0.6);
+}
+
+/* === Data Input form === */
+.input-form {
+ margin-top: 1rem;
+ display: flex;
+ flex-direction: column;
+ gap: 0.85rem;
+ max-width: 420px;
+}
+
+.input-form label {
+ display: flex;
+ flex-direction: column;
+ gap: 0.3rem;
+ font-size: 0.9rem;
+ color: #e5e7eb;
+}
+
+.input-form select,
+.input-form input {
+ padding: 0.45rem 0.55rem;
+ border-radius: 0.6rem;
+ border: 1px solid rgba(148, 163, 184, 0.6);
+ background: rgba(15, 23, 42, 0.85);
+ color: #e5e7eb;
+ font-size: 0.9rem;
+}
+
+.input-form select:focus,
+.input-form input:focus {
+ outline: none;
+ border-color: #38bdf8;
+ box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.6);
+}
+
+.input-form button {
+ margin-top: 0.4rem;
+ align-self: flex-start;
+ padding: 0.45rem 1.1rem;
+ border-radius: 999px;
+ border: none;
cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
+ font-size: 0.9rem;
+ font-weight: 500;
+ background: linear-gradient(135deg, #2563eb, #ffd200);
+ color: #f9fafb;
+ box-shadow: 0 10px 20px rgba(15, 23, 42, 0.7);
+ transition:
+ transform 0.08s ease,
+ box-shadow 0.1s ease,
+ filter 0.1s ease;
+}
+
+.input-form button:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 14px 30px rgba(255, 210, 0, 0.45);
+ filter: brightness(1.05);
+}
+
+/* === Footer === */
+.footer {
+ text-align: center;
+ padding: 0.75rem;
+ font-size: 0.8rem;
+ color: #9ca3af;
+}
+
+/* === Home section: Geisel hero === */
+.home-section {
+ position: relative;
+ overflow: hidden;
+ color: #f9fafb;
+ background-image:
+ linear-gradient(
+ to bottom right,
+ rgba(15, 23, 42, 0.15),
+ rgba(15, 23, 42, 0.8)
+ ),
+ url("/geisel.jpg");
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.home-section::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(circle at top right, rgba(56, 189, 248, 0.35), transparent 60%);
+ mix-blend-mode: screen;
+ opacity: 0.9;
+}
+
+.home-section > * {
+ position: relative;
+}
+
+.home-section h1 {
+ font-size: 1.9rem;
+}
+
+.home-section p {
+ max-width: 32rem;
}
diff --git a/src/main.jsx b/src/main.jsx
index b9a1a6d..a2aff31 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,10 +1,11 @@
-import { StrictMode } from 'react'
-import { createRoot } from 'react-dom/client'
-import './index.css'
-import App from './App.jsx'
+// src/main.jsx
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App.jsx";
+import "./index.css";
-createRoot(document.getElementById('root')).render(
-
+ReactDOM.createRoot(document.getElementById("root")).render(
+
- ,
-)
+
+);