alpe-temp 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +1 -1
- package/backend-project/server-err.txt +0 -0
- package/backend-project/server-out.txt +6 -0
- package/backend-project/src/modules/reports/reports.controller.js +147 -0
- package/backend-project/src/modules/reports/reports.routes.js +1 -0
- package/backend-project/test-all-routes.js +294 -0
- package/bin/epms.js +57 -92
- package/frontend-project/dist/assets/index-CRG9iE0k.css +1 -0
- package/frontend-project/dist/assets/{index-Bo0aORq7.js → index-LpBGz8lQ.js} +8 -8
- package/frontend-project/dist/index.html +2 -3
- package/frontend-project/index.html +0 -1
- package/frontend-project/src/Auth/Login.jsx +1 -1
- package/frontend-project/src/Auth/Register.jsx +0 -1
- package/frontend-project/src/Intro.jsx +1 -1
- package/frontend-project/src/api/ApiClient.js +2 -1
- package/frontend-project/src/config.js +4 -4
- package/frontend-project/src/layouts/BottomNav.jsx +1 -1
- package/frontend-project/src/layouts/TopNav.jsx +0 -1
- package/frontend-project/src/pages/Reports.jsx +38 -6
- package/package.json +2 -14
- package/frontend-project/dist/assets/index-BXwcQ8Za.css +0 -1
package/bin/epms.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const readline = require('readline');
|
|
5
4
|
const { execSync } = require('child_process');
|
|
6
5
|
|
|
7
6
|
const ROOT = path.resolve(__dirname, '..');
|
|
@@ -14,13 +13,13 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
14
13
|
alpe-temp — Employee Payroll Management System (EPMS)
|
|
15
14
|
|
|
16
15
|
Usage:
|
|
17
|
-
npx alpe-temp Scaffold project
|
|
18
|
-
npx alpe-temp init Scaffold project files only
|
|
16
|
+
npx alpe-temp Scaffold project, install deps, configure DB
|
|
17
|
+
npx alpe-temp init Scaffold project files + install deps only
|
|
19
18
|
npx alpe-temp seed Seed the database
|
|
20
|
-
npx alpe-temp start Start server (in existing project)
|
|
19
|
+
npx alpe-temp start Start backend server (in existing project)
|
|
21
20
|
|
|
22
21
|
Options:
|
|
23
|
-
--db <uri> MongoDB connection string (
|
|
22
|
+
--db <uri> MongoDB connection string (default: mongodb://127.0.0.1:27017/HRMS)
|
|
24
23
|
|
|
25
24
|
Environment variables:
|
|
26
25
|
PORT Server port (default: 3000)
|
|
@@ -56,32 +55,6 @@ function writeEnv(key, value) {
|
|
|
56
55
|
fs.writeFileSync(ENV_PATH, updated, 'utf-8');
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
async function ask(question, defaultValue) {
|
|
60
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
61
|
-
return new Promise((resolve) => {
|
|
62
|
-
const hint = defaultValue ? ` (default: ${defaultValue})` : '';
|
|
63
|
-
rl.question(` ${question}${hint}: `, (answer) => {
|
|
64
|
-
rl.close();
|
|
65
|
-
resolve(answer.trim() || defaultValue || '');
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async function waitForMongo(uri, timeoutMs = 5000) {
|
|
71
|
-
const mongoose = require('mongoose');
|
|
72
|
-
const start = Date.now();
|
|
73
|
-
while (Date.now() - start < timeoutMs) {
|
|
74
|
-
try {
|
|
75
|
-
await mongoose.connect(uri, { serverSelectionTimeoutMS: 2000 });
|
|
76
|
-
await mongoose.disconnect();
|
|
77
|
-
return true;
|
|
78
|
-
} catch {
|
|
79
|
-
await new Promise((r) => setTimeout(r, 1500));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
58
|
function isScaffolded(dir) {
|
|
86
59
|
return fs.existsSync(path.join(dir, 'backend-project', 'server.js'));
|
|
87
60
|
}
|
|
@@ -116,66 +89,68 @@ function scaffold() {
|
|
|
116
89
|
return true;
|
|
117
90
|
}
|
|
118
91
|
|
|
119
|
-
// ─── Install dependencies
|
|
92
|
+
// ─── Install dependencies separately in each project ──────────────────────────
|
|
120
93
|
function installDeps() {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
94
|
+
const backendDir = path.join(CWD, 'backend-project');
|
|
95
|
+
const frontendDir = path.join(CWD, 'frontend-project');
|
|
96
|
+
|
|
97
|
+
if (fs.existsSync(backendDir)) {
|
|
98
|
+
console.log(' Installing backend dependencies...');
|
|
99
|
+
execSync('npm install', { cwd: backendDir, stdio: 'inherit' });
|
|
100
|
+
console.log(' ✓ Backend dependencies installed');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (fs.existsSync(frontendDir)) {
|
|
104
|
+
console.log(' Installing frontend dependencies...');
|
|
105
|
+
execSync('npm install', { cwd: frontendDir, stdio: 'inherit' });
|
|
106
|
+
console.log(' ✓ Frontend dependencies installed');
|
|
107
|
+
}
|
|
124
108
|
}
|
|
125
109
|
|
|
126
|
-
// ─── Configure MongoDB
|
|
127
|
-
|
|
110
|
+
// ─── Configure MongoDB (silent — defaults to HRMS) ───────────────────────────
|
|
111
|
+
function configureMongo() {
|
|
128
112
|
const env = loadEnv();
|
|
129
113
|
if (env.MONGODB_URI) {
|
|
130
114
|
process.env.MONGODB_URI = env.MONGODB_URI;
|
|
131
|
-
return
|
|
115
|
+
return;
|
|
132
116
|
}
|
|
133
117
|
|
|
134
118
|
const dbIndex = args.indexOf('--db');
|
|
135
119
|
if (dbIndex !== -1 && args[dbIndex + 1]) {
|
|
136
120
|
process.env.MONGODB_URI = args[dbIndex + 1];
|
|
137
121
|
writeEnv('MONGODB_URI', args[dbIndex + 1]);
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
console.log(' MongoDB not configured.');
|
|
142
|
-
const uri = await ask('Enter MongoDB URI', 'mongodb://127.0.0.1:27017/EPMS');
|
|
143
|
-
if (uri) {
|
|
144
|
-
process.env.MONGODB_URI = uri;
|
|
145
|
-
writeEnv('MONGODB_URI', uri);
|
|
146
|
-
console.log(' ✓ Saved to .env');
|
|
122
|
+
return;
|
|
147
123
|
}
|
|
148
124
|
|
|
149
|
-
|
|
125
|
+
// Default to HRMS without prompting
|
|
126
|
+
const defaultUri = 'mongodb://127.0.0.1:27017/HRMS';
|
|
127
|
+
process.env.MONGODB_URI = defaultUri;
|
|
128
|
+
writeEnv('MONGODB_URI', defaultUri);
|
|
150
129
|
}
|
|
151
130
|
|
|
152
|
-
// ───
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
console.log(' failed');
|
|
174
|
-
}
|
|
175
|
-
return false;
|
|
131
|
+
// ─── Print run instructions ──────────────────────────────────────────────────
|
|
132
|
+
function printInstructions() {
|
|
133
|
+
console.log(`
|
|
134
|
+
┌─────────────────────────────────────────────────────────┐
|
|
135
|
+
│ ✔ Project ready! │
|
|
136
|
+
│ │
|
|
137
|
+
│ Run each service in a separate terminal: │
|
|
138
|
+
│ │
|
|
139
|
+
│ Terminal 1 — Backend (Express API): │
|
|
140
|
+
│ cd backend-project │
|
|
141
|
+
│ npm run dev │
|
|
142
|
+
│ │
|
|
143
|
+
│ Terminal 2 — Frontend (React + Vite): │
|
|
144
|
+
│ cd frontend-project │
|
|
145
|
+
│ npm run dev │
|
|
146
|
+
│ │
|
|
147
|
+
│ Backend → http://localhost:3000 │
|
|
148
|
+
│ Frontend → http://localhost:5173 │
|
|
149
|
+
└─────────────────────────────────────────────────────────┘
|
|
150
|
+
`);
|
|
176
151
|
}
|
|
177
152
|
|
|
178
|
-
// ─── Start server
|
|
153
|
+
// ─── Start backend server (production) ────────────────────────────────────────
|
|
179
154
|
function startServer() {
|
|
180
155
|
process.env.NODE_ENV = process.env.NODE_ENV || 'production';
|
|
181
156
|
const serverEntry = path.join(CWD, 'backend-project', 'server.js');
|
|
@@ -192,24 +167,25 @@ async function main() {
|
|
|
192
167
|
if (args.includes('seed')) {
|
|
193
168
|
const cwdEnv = loadEnv();
|
|
194
169
|
if (cwdEnv.MONGODB_URI) process.env.MONGODB_URI = cwdEnv.MONGODB_URI;
|
|
195
|
-
if (!process.env.MONGODB_URI)
|
|
170
|
+
if (!process.env.MONGODB_URI) configureMongo();
|
|
196
171
|
console.log('Seeding database...');
|
|
197
172
|
const seedEntry = path.join(isScaffolded(CWD) ? CWD : ROOT, 'backend-project', 'src', 'seed.js');
|
|
198
173
|
execSync(`node "${seedEntry}"`, { cwd: isScaffolded(CWD) ? CWD : ROOT, stdio: 'inherit' });
|
|
199
174
|
return;
|
|
200
175
|
}
|
|
201
176
|
|
|
202
|
-
// Init: scaffold
|
|
177
|
+
// Init: scaffold + install deps
|
|
203
178
|
if (args.includes('init')) {
|
|
204
179
|
scaffold();
|
|
205
180
|
if (isScaffolded(CWD)) {
|
|
206
181
|
installDeps();
|
|
207
|
-
|
|
182
|
+
configureMongo();
|
|
183
|
+
printInstructions();
|
|
208
184
|
}
|
|
209
185
|
return;
|
|
210
186
|
}
|
|
211
187
|
|
|
212
|
-
// Start: just start the server (assume already scaffolded)
|
|
188
|
+
// Start: just start the backend server (assume already scaffolded)
|
|
213
189
|
if (args.includes('start')) {
|
|
214
190
|
if (!isScaffolded(CWD)) {
|
|
215
191
|
console.error(' No alpe-temp project found in this directory. Run `npx alpe-temp init` first.');
|
|
@@ -217,31 +193,20 @@ async function main() {
|
|
|
217
193
|
}
|
|
218
194
|
const env = loadEnv();
|
|
219
195
|
if (env.MONGODB_URI) process.env.MONGODB_URI = env.MONGODB_URI;
|
|
220
|
-
if (!process.env.MONGODB_URI
|
|
221
|
-
console.error(' MongoDB URI is required.');
|
|
222
|
-
process.exit(1);
|
|
223
|
-
}
|
|
224
|
-
if (!(await verifyMongo())) {
|
|
225
|
-
console.error('\n Unable to connect to MongoDB. Please ensure it is running.\n');
|
|
226
|
-
process.exit(1);
|
|
227
|
-
}
|
|
196
|
+
if (!process.env.MONGODB_URI) configureMongo();
|
|
228
197
|
startServer();
|
|
229
198
|
return;
|
|
230
199
|
}
|
|
231
200
|
|
|
232
|
-
// Default: scaffold → install → configure →
|
|
201
|
+
// Default: scaffold → install → configure → instructions
|
|
233
202
|
const justScaffolded = scaffold();
|
|
234
203
|
if (justScaffolded) installDeps();
|
|
235
204
|
if (!isScaffolded(CWD)) {
|
|
236
205
|
console.error(' Project setup failed.');
|
|
237
206
|
process.exit(1);
|
|
238
207
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
console.error('\n Unable to connect to MongoDB.\n');
|
|
242
|
-
process.exit(1);
|
|
243
|
-
}
|
|
244
|
-
startServer();
|
|
208
|
+
configureMongo();
|
|
209
|
+
printInstructions();
|
|
245
210
|
}
|
|
246
211
|
|
|
247
212
|
main().catch((err) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (width>=640px){.container{max-width:640px}}@media (width>=768px){.container{max-width:768px}}@media (width>=1024px){.container{max-width:1024px}}@media (width>=1280px){.container{max-width:1280px}}@media (width>=1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.left-3{left:.75rem}.right-0{right:0}.right-3{right:.75rem}.right-5{right:1.25rem}.top-0{top:0}.top-1\/2{top:50%}.top-5{top:1.25rem}.top-full{top:100%}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[9999\]{z-index:9999}.col-span-2{grid-column:span 2/span 2}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-auto{margin-bottom:auto}.ml-0\.5{margin-left:.125rem}.ml-auto{margin-left:auto}.mr-4{margin-right:1rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-auto{margin-top:auto}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[500px\]{height:500px}.h-\[52px\]{height:52px}.h-\[540px\]{height:540px}.h-\[64px\]{height:64px}.h-screen{height:100vh}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/12{width:41.6667%}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-fit{width:fit-content}.w-full{width:100%}.min-w-\[150px\]{min-width:150px}.min-w-\[240px\]{min-width:240px}.min-w-max{min-width:max-content}.max-w-2xl{max-width:42rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-\[760px\]{max-width:760px}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y:-50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:2s cubic-bezier(.4,0,.6,1) infinite pulse}@keyframes spin{to{transform:rotate(360deg)}}.select-none{-webkit-user-select:none;user-select:none}.resize-none{resize:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-50>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(249 250 251/var(--tw-divide-opacity,1))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-emerald-200{--tw-border-opacity:1;border-color:rgb(167 243 208/var(--tw-border-opacity,1))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-white\/20{border-color:#fff3}.border-yellow-200{--tw-border-opacity:1;border-color:rgb(254 240 138/var(--tw-border-opacity,1))}.border-zinc-200{--tw-border-opacity:1;border-color:rgb(228 228 231/var(--tw-border-opacity,1))}.border-t-\[\#008A75\]{--tw-border-opacity:1;border-top-color:rgb(0 138 117/var(--tw-border-opacity,1))}.bg-\[\#008A75\]{--tw-bg-opacity:1;background-color:rgb(0 138 117/var(--tw-bg-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black\/40{background-color:#0006}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-emerald-50{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity,1))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(22 163 74/var(--tw-bg-opacity,1))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity,1))}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity,1))}.bg-zinc-50{--tw-bg-opacity:1;background-color:rgb(250 250 250/var(--tw-bg-opacity,1))}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pl-9{padding-left:2.25rem}.pr-10{padding-right:2.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-10{padding-top:2.5rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[18px\]{font-size:18px}.text-\[20px\]{font-size:20px}.text-\[22px\]{font-size:22px}.text-\[32px\]{font-size:32px}.text-\[7px\]{font-size:7px}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-\[\#008A75\]{--tw-text-opacity:1;color:rgb(0 138 117/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-blue-800{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity,1))}.text-emerald-500{--tw-text-opacity:1;color:rgb(16 185 129/var(--tw-text-opacity,1))}.text-emerald-600{--tw-text-opacity:1;color:rgb(5 150 105/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity,1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/40{color:#fff6}.text-white\/50{color:#ffffff80}.text-white\/60{color:#fff9}.text-yellow-600{--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity,1))}.text-yellow-800{--tw-text-opacity:1;color:rgb(133 77 14/var(--tw-text-opacity,1))}.text-zinc-800{--tw-text-opacity:1;color:rgb(39 39 42/var(--tw-text-opacity,1))}.text-zinc-800\/60{color:#27272a99}.text-zinc-900{--tw-text-opacity:1;color:rgb(24 24 27/var(--tw-text-opacity,1))}.opacity-60{opacity:.6}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.outline{outline-style:solid}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{transition-property:transform;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}:root{--color-primary:#008a75;--color-surface:#f9fafb;--color-card:#fff;--color-border:#e5e7eb;--color-text:#1f2937;--color-text-muted:#9ca3af;--color-nav-bg:#fff;--color-nav-text:#4b5563;--color-nav-active:#008a75;--color-danger:#ef4444;--color-success:#10b981;--color-warning:#f59e0b;--color-info:#3b82f6;--radius:.375rem;--text-xs:.75rem;--text-sm:.8125rem;--text-base:.875rem;--text-lg:1rem;--text-xl:1.25rem;--text-2xl:1.5rem;--text-3xl:2rem}.animate-spin{animation:1s linear infinite spin}.placeholder\:text-gray-400::placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.hover\:bg-emerald-600:hover{--tw-bg-opacity:1;background-color:rgb(5 150 105/var(--tw-bg-opacity,1))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.hover\:bg-gray-900:hover{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(21 128 61/var(--tw-bg-opacity,1))}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity,1))}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-70:hover{opacity:.7}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-90:hover{opacity:.9}.focus\:outline-none:focus{outline-offset:2px;outline:2px solid #0000}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.focus\:ring-\[\#008A75\]:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(0 138 117/var(--tw-ring-opacity,1))}.focus\:ring-\[var\(--color-primary\)\]:focus{--tw-ring-color:var(--color-primary)}.focus\:ring-emerald-400:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(52 211 153/var(--tw-ring-opacity,1))}.focus\:ring-gray-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(229 231 235/var(--tw-ring-opacity,1))}.focus\:ring-gray-300:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity,1))}.focus\:ring-gray-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(75 85 99/var(--tw-ring-opacity,1))}.focus\:ring-red-400:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(248 113 113/var(--tw-ring-opacity,1))}.focus\:ring-offset-1:focus{--tw-ring-offset-width:1px}.active\:scale-\[0\.98\]:active{--tw-scale-x:.98;--tw-scale-y:.98;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.disabled\:text-gray-400:disabled{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=640px){.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:p-10{padding:2.5rem}}@media (width>=1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
|