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/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 + start server
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 (non-interactive)
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
- console.log(' Installing dependencies...');
122
- execSync('npm install', { cwd: CWD, stdio: 'inherit' });
123
- console.log(' ✓ Dependencies installed');
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
- async function configureMongo() {
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 true;
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 true;
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
- return !!process.env.MONGODB_URI;
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
- // ─── Verify MongoDB ───────────────────────────────────────────────────────────
153
- async function verifyMongo() {
154
- const uri = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/EPMS';
155
- process.stdout.write(' Checking MongoDB connection...');
156
- const reachable = await waitForMongo(uri);
157
- if (reachable) {
158
- console.log(' connected');
159
- return true;
160
- }
161
- console.log(' failed');
162
- console.log(`\n Could not connect to MongoDB at:\n ${uri}\n`);
163
- const retry = await ask('Try a different URI', uri);
164
- if (retry) {
165
- process.env.MONGODB_URI = retry;
166
- writeEnv('MONGODB_URI', retry);
167
- console.log(' ✓ Saved to .env');
168
- process.stdout.write(' Checking MongoDB connection...');
169
- if (await waitForMongo(retry)) {
170
- console.log(' connected');
171
- return true;
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) await configureMongo();
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 only
177
+ // Init: scaffold + install deps
203
178
  if (args.includes('init')) {
204
179
  scaffold();
205
180
  if (isScaffolded(CWD)) {
206
181
  installDeps();
207
- console.log('\n ✔ Project ready! Run:\n npm start\n');
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 && !await configureMongo()) {
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 → start
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
- await configureMongo();
240
- if (!(await verifyMongo())) {
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))}}