husseinelsaadi commited on
Commit
4991915
·
1 Parent(s): 5c64dc0

style updated

Browse files
backend/templates/apply.html CHANGED
@@ -22,155 +22,467 @@
22
  <li>Apply</li>
23
  </ul>
24
 
25
- <div class="card">
26
- <div class="card-header">
27
- <h2>Submit Your Application</h2>
28
- <p>Please upload your resume (PDF, DOCX). Your file will be saved securely for recruiters to review.</p>
29
- </div>
 
30
 
31
- <div class="card-body">
32
- <!-- Application Form -->
33
- <form method="POST" enctype="multipart/form-data">
34
- <div class="form-group">
35
- <label for="resume">Upload Resume</label>
36
- <!-- Resume upload remains mandatory. The file will be stored for recruiter review but is no longer parsed automatically. -->
37
- <input type="file" name="resume" id="resume" class="form-control" required accept=".pdf,.doc,.docx">
38
- <!-- Parse Resume button sits beside the upload to allow users to extract information from their CV. It uses a
39
- type="button" so that clicking it does not submit the form. The actual parsing logic is defined in
40
- the script at the bottom of this template. -->
41
- <button type="button" id="parse-resume" class="btn btn-secondary" style="margin-top:0.5rem;">Parse Resume</button>
42
- </div>
 
 
 
 
 
 
 
 
 
43
 
44
- <!-- Name field added to capture the applicant's full name. This input can be autofilled by the resume parser,
45
- but remains editable so applicants can correct any mistakes. -->
46
- <div class="form-group">
47
- <label for="full-name">Full Name</label>
48
- <input type="text" name="full_name" id="full-name" class="form-control" placeholder="e.g. Jane Doe" required>
49
- </div>
 
 
50
 
51
- <!--
52
- Collect the candidate's skills, experience and education manually.
53
- These fields allow applicants to highlight their background even when resume
54
- parsing is disabled. Entries can be separated by commas, semicolons or newlines;
55
- the backend will normalise them into lists.
56
- -->
57
- <div class="form-group">
58
- <label for="skills">Skills</label>
59
- <textarea name="skills" id="skills" class="form-control" rows="3" placeholder="e.g. Python, Data Analysis, Project Management" required></textarea>
60
- </div>
61
- <div class="form-group">
62
- <label for="experience">Experience</label>
63
- <textarea name="experience" id="experience" class="form-control" rows="3" placeholder="e.g. 3 years at TechCorp as a Backend Developer" required></textarea>
64
- </div>
65
- <div class="form-group">
66
- <label for="education">Education</label>
67
- <textarea name="education" id="education" class="form-control" rows="3" placeholder="e.g. B.Sc. in Computer Science, M.Sc. in Data Science" required></textarea>
68
- </div>
69
 
70
- <!-- Interview guidelines removed from this page. They are now displayed on the
71
- "My Applications" page so applicants see them before taking the interview. -->
 
 
 
 
72
 
73
- <div class="application-actions" style="margin-top: 2rem;">
74
- <button type="submit" class="btn btn-primary">Submit Application</button>
75
- </div>
76
- </form>
 
 
 
77
 
78
- <div style="margin-top: 1.5rem; text-align: center;">
79
- <a href="{{ url_for('job_detail', job_id=job.id) }}" class="btn btn-outline">Back to Job Details</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  </div>
81
  </div>
82
  </div>
83
  </section>
84
 
85
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  .form-group label {
87
  font-weight: 600;
88
- color: var(--primary);
89
  margin-bottom: 0.5rem;
90
- display: block;
 
 
91
  }
92
 
93
  .form-control {
94
  width: 100%;
95
- padding: 0.75rem;
96
  font-size: 1rem;
97
- border-radius: 6px;
98
- border: 1px solid #ccc;
 
 
99
  }
100
 
101
- .application-actions {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  text-align: center;
103
  }
104
 
105
- .btn-primary {
106
- background: linear-gradient(135deg, var(--primary), var(--secondary));
107
- color: white;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  padding: 0.75rem 1.5rem;
109
  font-weight: 500;
110
- border: none;
111
- border-radius: 6px;
112
- cursor: pointer;
113
  }
114
 
115
- .btn-primary:hover {
116
- opacity: 0.9;
 
117
  }
118
 
119
- /* Secondary button styling used for the "Parse Resume" control */
120
  .btn-secondary {
121
- background: var(--secondary);
122
  color: white;
123
- padding: 0.75rem 1.5rem;
124
- font-weight: 500;
125
  border: none;
126
- border-radius: 6px;
127
- cursor: pointer;
128
  }
 
129
  .btn-secondary:hover {
130
- opacity: 0.9;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
  </style>
133
 
134
- {# Resume parsing script: attaches click handler to the Parse Resume button. It performs an asynchronous
135
- POST to a placeholder endpoint (`/parse_resume`) with the uploaded file and, upon success,
136
- populates the corresponding form fields. Users can still edit the populated fields. #}
137
  <script>
138
  document.addEventListener('DOMContentLoaded', function() {
139
- const parseBtn = document.getElementById('parse-resume');
140
- if (!parseBtn) return;
141
- parseBtn.addEventListener('click', function() {
142
- const resumeInput = document.getElementById('resume');
143
- if (!resumeInput || !resumeInput.files || resumeInput.files.length === 0) {
144
- alert('Please upload your resume before parsing.');
145
- return;
146
- }
147
- const formData = new FormData();
148
- formData.append('resume', resumeInput.files[0]);
149
- fetch('/parse_resume', {
150
- method: 'POST',
151
- body: formData
152
- }).then(resp => resp.json())
153
- .then(data => {
154
- if (data) {
155
- if (data.name && document.getElementById('full-name')) {
156
- document.getElementById('full-name').value = data.name;
157
- }
158
- if (data.skills && document.getElementById('skills')) {
159
- document.getElementById('skills').value = data.skills;
160
- }
161
- if (data.education && document.getElementById('education')) {
162
- document.getElementById('education').value = data.education;
163
- }
164
- if (data.experience && document.getElementById('experience')) {
165
- document.getElementById('experience').value = data.experience;
166
- }
167
  }
168
- })
169
- .catch(err => {
170
- console.error(err);
171
- alert('Unable to parse resume. Please try again later.');
172
- });
173
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  });
175
  </script>
176
- {% endblock %}
 
22
  <li>Apply</li>
23
  </ul>
24
 
25
+ <div class="application-container">
26
+ <div class="card application-card">
27
+ <div class="card-header">
28
+ <h2>Submit Your Application</h2>
29
+ <p>Please upload your resume and fill in the required information below.</p>
30
+ </div>
31
 
32
+ <div class="card-body">
33
+ <form method="POST" enctype="multipart/form-data" id="application-form">
34
+ <!-- Resume Upload Section -->
35
+ <div class="upload-section">
36
+ <div class="form-group">
37
+ <label for="resume">
38
+ <i class="upload-icon">📄</i>
39
+ Upload Resume
40
+ </label>
41
+ <div class="file-input-wrapper">
42
+ <input type="file" name="resume" id="resume" class="file-input" required accept=".pdf,.doc,.docx">
43
+ <div class="file-input-display">
44
+ <span class="file-placeholder">Choose file... (PDF, DOCX)</span>
45
+ <span class="file-name"></span>
46
+ </div>
47
+ </div>
48
+ <button type="button" id="parse-resume" class="btn btn-secondary mt-2">
49
+ <span class="btn-icon">🔍</span> Parse Resume
50
+ </button>
51
+ </div>
52
+ </div>
53
 
54
+ <!-- Personal Information -->
55
+ <div class="form-section">
56
+ <h3 class="section-title">Personal Information</h3>
57
+ <div class="form-group">
58
+ <label for="full-name">Full Name</label>
59
+ <input type="text" name="full_name" id="full-name" class="form-control" placeholder="e.g. Jane Doe" required>
60
+ </div>
61
+ </div>
62
 
63
+ <!-- Professional Details -->
64
+ <div class="form-section">
65
+ <h3 class="section-title">Professional Details</h3>
66
+
67
+ <div class="form-group">
68
+ <label for="skills">Skills</label>
69
+ <textarea name="skills" id="skills" class="form-control" rows="3"
70
+ placeholder="e.g. Python, Data Analysis, Project Management" required></textarea>
71
+ <small class="form-text">Separate skills with commas</small>
72
+ </div>
 
 
 
 
 
 
 
 
73
 
74
+ <div class="form-group">
75
+ <label for="experience">Experience</label>
76
+ <textarea name="experience" id="experience" class="form-control" rows="4"
77
+ placeholder="e.g. 3 years at TechCorp as a Backend Developer" required></textarea>
78
+ <small class="form-text">List your relevant work experience</small>
79
+ </div>
80
 
81
+ <div class="form-group">
82
+ <label for="education">Education</label>
83
+ <textarea name="education" id="education" class="form-control" rows="3"
84
+ placeholder="e.g. B.Sc. in Computer Science, M.Sc. in Data Science" required></textarea>
85
+ <small class="form-text">Include degrees, certifications, and relevant coursework</small>
86
+ </div>
87
+ </div>
88
 
89
+ <!-- Submit Section -->
90
+ <div class="application-actions">
91
+ <button type="submit" class="btn btn-primary btn-lg">
92
+ <span class="btn-icon">✓</span> Submit Application
93
+ </button>
94
+ <a href="{{ url_for('job_detail', job_id=job.id) }}" class="btn btn-outline">
95
+ <span class="btn-icon">←</span> Back to Job Details
96
+ </a>
97
+ </div>
98
+ </form>
99
+ </div>
100
+ </div>
101
+
102
+ <!-- Job Summary Sidebar -->
103
+ <div class="job-summary-sidebar">
104
+ <div class="card">
105
+ <div class="card-header">
106
+ <h3>Job Summary</h3>
107
+ </div>
108
+ <div class="card-body">
109
+ <div class="summary-item">
110
+ <strong>Role:</strong> {{ job.role }}
111
+ </div>
112
+ <div class="summary-item">
113
+ <strong>Company:</strong> {{ job.company }}
114
+ </div>
115
+ {% if job.seniority %}
116
+ <div class="summary-item">
117
+ <strong>Seniority:</strong> {{ job.seniority }}
118
+ </div>
119
+ {% endif %}
120
+ {% if job.location %}
121
+ <div class="summary-item">
122
+ <strong>Location:</strong> {{ job.location }}
123
+ </div>
124
+ {% endif %}
125
+ {% if job.salary %}
126
+ <div class="summary-item">
127
+ <strong>Salary:</strong> {{ job.salary }}
128
+ </div>
129
+ {% endif %}
130
+ </div>
131
  </div>
132
  </div>
133
  </div>
134
  </section>
135
 
136
  <style>
137
+ /* Application Container */
138
+ .application-container {
139
+ display: grid;
140
+ grid-template-columns: 1fr;
141
+ gap: 2rem;
142
+ }
143
+
144
+ @media (min-width: 992px) {
145
+ .application-container {
146
+ grid-template-columns: 2fr 1fr;
147
+ }
148
+ }
149
+
150
+ /* Card Enhancements */
151
+ .application-card {
152
+ background: white;
153
+ border-radius: 12px;
154
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
155
+ overflow: hidden;
156
+ }
157
+
158
+ .application-card .card-header {
159
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
160
+ color: white;
161
+ padding: 2rem;
162
+ }
163
+
164
+ .application-card .card-header h2 {
165
+ margin: 0 0 0.5rem 0;
166
+ font-size: 1.75rem;
167
+ }
168
+
169
+ .application-card .card-header p {
170
+ margin: 0;
171
+ opacity: 0.9;
172
+ }
173
+
174
+ .application-card .card-body {
175
+ padding: 2rem;
176
+ }
177
+
178
+ /* Form Sections */
179
+ .form-section {
180
+ margin-bottom: 2.5rem;
181
+ }
182
+
183
+ .section-title {
184
+ font-size: 1.25rem;
185
+ color: var(--primary);
186
+ margin-bottom: 1.5rem;
187
+ padding-bottom: 0.5rem;
188
+ border-bottom: 2px solid #e9ecef;
189
+ }
190
+
191
+ /* Form Elements */
192
+ .form-group {
193
+ margin-bottom: 1.5rem;
194
+ }
195
+
196
  .form-group label {
197
  font-weight: 600;
198
+ color: var(--dark);
199
  margin-bottom: 0.5rem;
200
+ display: flex;
201
+ align-items: center;
202
+ gap: 0.5rem;
203
  }
204
 
205
  .form-control {
206
  width: 100%;
207
+ padding: 0.875rem;
208
  font-size: 1rem;
209
+ border-radius: 8px;
210
+ border: 2px solid #e9ecef;
211
+ transition: all 0.3s ease;
212
+ background-color: #f8f9fa;
213
  }
214
 
215
+ .form-control:focus {
216
+ outline: none;
217
+ border-color: var(--primary);
218
+ background-color: white;
219
+ box-shadow: 0 0 0 4px rgba(67, 97, 238, 0.1);
220
+ }
221
+
222
+ .form-text {
223
+ display: block;
224
+ margin-top: 0.5rem;
225
+ color: #6c757d;
226
+ font-size: 0.875rem;
227
+ }
228
+
229
+ /* File Upload Styling */
230
+ .upload-section {
231
+ background-color: #f8f9fa;
232
+ padding: 1.5rem;
233
+ border-radius: 8px;
234
+ margin-bottom: 2rem;
235
+ }
236
+
237
+ .upload-icon {
238
+ font-size: 1.5rem;
239
+ }
240
+
241
+ .file-input-wrapper {
242
+ position: relative;
243
+ overflow: hidden;
244
+ display: inline-block;
245
+ width: 100%;
246
+ }
247
+
248
+ .file-input {
249
+ position: absolute;
250
+ left: -9999px;
251
+ }
252
+
253
+ .file-input-display {
254
+ display: block;
255
+ padding: 0.875rem;
256
+ border: 2px dashed var(--primary);
257
+ border-radius: 8px;
258
+ background-color: white;
259
+ cursor: pointer;
260
+ transition: all 0.3s ease;
261
  text-align: center;
262
  }
263
 
264
+ .file-input-wrapper:hover .file-input-display {
265
+ border-color: var(--secondary);
266
+ background-color: #f8f9fa;
267
+ }
268
+
269
+ .file-placeholder {
270
+ color: #6c757d;
271
+ }
272
+
273
+ .file-name {
274
+ color: var(--primary);
275
+ font-weight: 500;
276
+ }
277
+
278
+ /* Button Enhancements */
279
+ .btn {
280
+ display: inline-flex;
281
+ align-items: center;
282
+ gap: 0.5rem;
283
  padding: 0.75rem 1.5rem;
284
  font-weight: 500;
285
+ border-radius: 8px;
286
+ transition: all 0.3s ease;
 
287
  }
288
 
289
+ .btn-lg {
290
+ padding: 1rem 2rem;
291
+ font-size: 1.1rem;
292
  }
293
 
 
294
  .btn-secondary {
295
+ background: #6c757d;
296
  color: white;
 
 
297
  border: none;
 
 
298
  }
299
+
300
  .btn-secondary:hover {
301
+ background: #5a6268;
302
+ transform: translateY(-2px);
303
+ }
304
+
305
+ .btn-icon {
306
+ font-size: 1.2rem;
307
+ }
308
+
309
+ /* Application Actions */
310
+ .application-actions {
311
+ display: flex;
312
+ gap: 1rem;
313
+ margin-top: 2rem;
314
+ padding-top: 2rem;
315
+ border-top: 2px solid #e9ecef;
316
+ flex-wrap: wrap;
317
+ }
318
+
319
+ /* Job Summary Sidebar */
320
+ .job-summary-sidebar .card {
321
+ position: sticky;
322
+ top: 2rem;
323
+ }
324
+
325
+ .job-summary-sidebar .card-header {
326
+ background-color: #f8f9fa;
327
+ padding: 1rem 1.5rem;
328
+ }
329
+
330
+ .job-summary-sidebar .card-header h3 {
331
+ margin: 0;
332
+ font-size: 1.2rem;
333
+ color: var(--primary);
334
+ }
335
+
336
+ .summary-item {
337
+ padding: 0.75rem 0;
338
+ border-bottom: 1px solid #e9ecef;
339
+ }
340
+
341
+ .summary-item:last-child {
342
+ border-bottom: none;
343
+ }
344
+
345
+ /* Responsive Adjustments */
346
+ @media (max-width: 768px) {
347
+ .application-card .card-header {
348
+ padding: 1.5rem;
349
+ }
350
+
351
+ .application-card .card-body {
352
+ padding: 1.5rem;
353
+ }
354
+
355
+ .form-section {
356
+ margin-bottom: 2rem;
357
+ }
358
+
359
+ .application-actions {
360
+ flex-direction: column;
361
+ }
362
+
363
+ .application-actions .btn {
364
+ width: 100%;
365
+ justify-content: center;
366
+ }
367
+
368
+ .job-summary-sidebar {
369
+ order: -1;
370
+ }
371
+ }
372
+
373
+ /* Loading State */
374
+ .btn:disabled {
375
+ opacity: 0.6;
376
+ cursor: not-allowed;
377
+ }
378
+
379
+ /* Success Animation */
380
+ @keyframes successPulse {
381
+ 0% {
382
+ box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.4);
383
+ }
384
+ 70% {
385
+ box-shadow: 0 0 0 10px rgba(46, 204, 113, 0);
386
+ }
387
+ 100% {
388
+ box-shadow: 0 0 0 0 rgba(46, 204, 113, 0);
389
+ }
390
+ }
391
+
392
+ .application-success {
393
+ animation: successPulse 2s infinite;
394
  }
395
  </style>
396
 
 
 
 
397
  <script>
398
  document.addEventListener('DOMContentLoaded', function() {
399
+ // File input handling
400
+ const fileInput = document.getElementById('resume');
401
+ const fileDisplay = document.querySelector('.file-input-display');
402
+ const filePlaceholder = document.querySelector('.file-placeholder');
403
+ const fileName = document.querySelector('.file-name');
404
+
405
+ fileInput.addEventListener('change', function() {
406
+ if (this.files && this.files[0]) {
407
+ filePlaceholder.style.display = 'none';
408
+ fileName.textContent = this.files[0].name;
409
+ fileName.style.display = 'block';
410
+ fileDisplay.style.borderStyle = 'solid';
411
+ fileDisplay.style.borderColor = 'var(--success)';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  }
413
+ });
414
+
415
+ // Parse resume functionality
416
+ const parseBtn = document.getElementById('parse-resume');
417
+ if (parseBtn) {
418
+ parseBtn.addEventListener('click', function() {
419
+ const resumeInput = document.getElementById('resume');
420
+ if (!resumeInput || !resumeInput.files || resumeInput.files.length === 0) {
421
+ alert('Please upload your resume before parsing.');
422
+ return;
423
+ }
424
+
425
+ // Show loading state
426
+ parseBtn.disabled = true;
427
+ parseBtn.innerHTML = '<span class="btn-icon">⏳</span> Parsing...';
428
+
429
+ const formData = new FormData();
430
+ formData.append('resume', resumeInput.files[0]);
431
+
432
+ fetch('/parse_resume', {
433
+ method: 'POST',
434
+ body: formData
435
+ })
436
+ .then(resp => resp.json())
437
+ .then(data => {
438
+ if (data) {
439
+ // Populate fields with animation
440
+ const fields = [
441
+ { id: 'full-name', value: data.name },
442
+ { id: 'skills', value: data.skills },
443
+ { id: 'education', value: data.education },
444
+ { id: 'experience', value: data.experience }
445
+ ];
446
+
447
+ fields.forEach((field, index) => {
448
+ if (field.value && document.getElementById(field.id)) {
449
+ setTimeout(() => {
450
+ const element = document.getElementById(field.id);
451
+ element.value = field.value;
452
+ element.style.borderColor = 'var(--success)';
453
+ setTimeout(() => {
454
+ element.style.borderColor = '';
455
+ }, 1000);
456
+ }, index * 200);
457
+ }
458
+ });
459
+
460
+ // Show success message
461
+ parseBtn.innerHTML = '<span class="btn-icon">✓</span> Parsed Successfully';
462
+ parseBtn.classList.add('btn-success');
463
+ }
464
+ })
465
+ .catch(err => {
466
+ console.error(err);
467
+ alert('Unable to parse resume. Please fill in the fields manually.');
468
+ })
469
+ .finally(() => {
470
+ setTimeout(() => {
471
+ parseBtn.disabled = false;
472
+ parseBtn.innerHTML = '<span class="btn-icon">🔍</span> Parse Resume';
473
+ parseBtn.classList.remove('btn-success');
474
+ }, 2000);
475
+ });
476
+ });
477
+ }
478
+
479
+ // Form validation
480
+ const form = document.getElementById('application-form');
481
+ form.addEventListener('submit', function(e) {
482
+ const submitBtn = form.querySelector('button[type="submit"]');
483
+ submitBtn.disabled = true;
484
+ submitBtn.innerHTML = '<span class="btn-icon">⏳</span> Submitting...';
485
+ });
486
  });
487
  </script>
488
+ {% endblock %}
backend/templates/base.html CHANGED
@@ -14,6 +14,7 @@
14
  --success: #2ecc71;
15
  --warning: #f39c12;
16
  --danger: #e74c3c;
 
17
  }
18
 
19
  * {
@@ -29,8 +30,12 @@
29
  line-height: 1.6;
30
  perspective: 1000px;
31
  overflow-x: hidden;
 
 
 
32
  }
33
 
 
34
  header {
35
  background: linear-gradient(135deg, var(--primary), var(--secondary));
36
  color: white;
@@ -52,8 +57,11 @@
52
  display: flex;
53
  justify-content: space-between;
54
  align-items: center;
 
 
55
  }
56
 
 
57
  .logo {
58
  display: flex;
59
  align-items: center;
@@ -92,23 +100,37 @@
92
  color: var(--accent);
93
  }
94
 
 
95
  .login-buttons {
96
  display: flex;
97
  align-items: center;
98
- gap: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  }
100
 
101
- /* Style for the welcome message */
102
  .welcome-message {
103
  color: white;
104
  font-weight: 500;
105
- margin-right: 0.5rem;
106
  display: flex;
107
  align-items: center;
108
  background-color: rgba(255, 255, 255, 0.1);
109
  padding: 0.5rem 1rem;
110
  border-radius: 5px;
111
  transition: all 0.3s ease;
 
112
  }
113
 
114
  .welcome-message:before {
@@ -116,24 +138,7 @@
116
  margin-right: 0.5rem;
117
  }
118
 
119
- /* Enhanced logout button */
120
- .btn-logout {
121
- background-color: transparent;
122
- border: 2px solid var(--accent);
123
- color: var(--accent);
124
- font-weight: 600;
125
- padding: 0.5rem 1.5rem;
126
- border-radius: 5px;
127
- transition: all 0.3s ease;
128
- }
129
-
130
- .btn-logout:hover {
131
- background-color: var(--accent);
132
- color: var(--dark);
133
- transform: translateY(-2px);
134
- box-shadow: 0 5px 15px rgba(76, 201, 240, 0.3);
135
- }
136
-
137
  .btn {
138
  padding: 0.5rem 1.5rem;
139
  border-radius: 5px;
@@ -145,6 +150,8 @@
145
  position: relative;
146
  overflow: hidden;
147
  z-index: 1;
 
 
148
  }
149
 
150
  .btn::before {
@@ -175,11 +182,99 @@
175
  color: white;
176
  }
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  .btn:hover {
179
  transform: translateY(-2px);
180
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
181
  }
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  .hero {
184
  background: linear-gradient(rgba(67, 97, 238, 0.8), rgba(58, 12, 163, 0.9)), url("/api/placeholder/1200/600") no-repeat center center/cover;
185
  color: white;
@@ -248,249 +343,117 @@
248
  animation: fadeIn 1s ease-out 0.3s both;
249
  }
250
 
251
- .luna-avatar-container {
252
- position: relative;
253
- width: 250px;
254
- height: 250px;
255
- margin-bottom: 2rem;
256
- perspective: 1000px;
257
  }
258
 
259
- .luna-avatar {
260
- width: 100%;
261
- height: 100%;
262
- border-radius: 50%;
263
- border: 4px solid var(--accent);
264
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3), 0 0 20px rgba(76, 201, 240, 0.5);
265
- overflow: hidden;
266
- animation: float 4s ease-in-out infinite;
267
- position: relative;
268
- z-index: 2;
269
- background: linear-gradient(135deg, rgba(76, 201, 240, 0.2), rgba(58, 12, 163, 0.2));
270
  display: flex;
271
- justify-content: center;
272
  align-items: center;
273
- }
274
-
275
- .luna-glow {
276
- position: absolute;
277
- width: 100%;
278
- height: 100%;
279
- border-radius: 50%;
280
- background: radial-gradient(circle, rgba(76, 201, 240, 0.8) 0%, rgba(76, 201, 240, 0) 70%);
281
- filter: blur(15px);
282
- opacity: 0.7;
283
- z-index: 1;
284
- animation: pulse 4s ease-in-out infinite alternate;
285
- }
286
-
287
- @keyframes pulse {
288
- 0% {
289
- transform: scale(0.9);
290
- opacity: 0.5;
291
- }
292
- 100% {
293
- transform: scale(1.1);
294
- opacity: 0.7;
295
- }
296
- }
297
-
298
- @keyframes float {
299
- 0% {
300
- transform: translateY(0px) rotateY(0deg);
301
- }
302
- 50% {
303
- transform: translateY(-15px) rotateY(5deg);
304
- }
305
- 100% {
306
- transform: translateY(0px) rotateY(0deg);
307
- }
308
- }
309
-
310
- .luna-avatar img {
311
- width: 100%;
312
- height: 100%;
313
- object-fit: cover;
314
- object-position: center -10px;
315
- top: 0;
316
- left: 0;
317
- }
318
-
319
- .hero-buttons {
320
- display: flex;
321
- justify-content: center;
322
- gap: 1.5rem;
323
  flex-wrap: wrap;
324
- transform: translateZ(15px);
325
- animation: fadeIn 1s ease-out 0.6s both;
326
  }
327
 
328
- .features {
329
- padding: 5rem 1rem;
330
- background-color: white;
331
- position: relative;
332
- z-index: 1;
333
  }
334
 
335
- .section-title {
336
- text-align: center;
337
- margin-bottom: 3rem;
338
- transform-style: preserve-3d;
339
- transition: transform 0.3s ease;
340
  }
341
 
342
- .section-title h2 {
343
- font-size: 2.5rem;
344
  color: var(--primary);
345
- margin-bottom: 1rem;
346
- position: relative;
347
- display: inline-block;
348
- }
349
-
350
- .section-title h2::after {
351
- content: '';
352
- position: absolute;
353
- bottom: -10px;
354
- left: 50%;
355
- transform: translateX(-50%);
356
- width: 80px;
357
- height: 3px;
358
- background: linear-gradient(to right, var(--primary), var(--accent));
359
  }
360
 
361
- .section-title p {
362
- max-width: 600px;
363
- margin: 0 auto;
364
- color: #666;
365
  }
366
 
367
- .features-grid {
368
- display: grid;
369
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
370
- gap: 2rem;
 
371
  }
372
 
373
- .feature-card {
 
374
  background-color: white;
375
  border-radius: 10px;
376
  overflow: hidden;
377
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
378
  transition: all 0.5s ease;
379
- display: flex;
380
- flex-direction: column;
381
- height: 100%;
382
- transform-style: preserve-3d;
383
- perspective: 1000px;
384
  }
385
 
386
- .feature-card:hover {
387
- transform: translateY(-10px) rotateX(5deg);
388
  box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
389
  }
390
 
391
- .feature-icon {
392
- background: linear-gradient(135deg, rgba(67, 97, 238, 0.1), rgba(76, 201, 240, 0.1));
393
- padding: 2rem;
394
- display: flex;
395
- justify-content: center;
396
- align-items: center;
397
- font-size: 2.5rem;
398
- color: var(--primary);
399
- transition: all 0.3s ease;
400
- }
401
-
402
- .feature-card:hover .feature-icon {
403
- transform: translateZ(20px);
404
- color: var(--accent);
405
- }
406
-
407
- .feature-content {
408
  padding: 1.5rem;
409
- flex-grow: 1;
410
- transform: translateZ(0);
411
- transition: transform 0.3s ease;
412
  }
413
 
414
- .feature-card:hover .feature-content {
415
- transform: translateZ(10px);
416
  }
417
 
418
- .feature-content h3 {
419
- font-size : 1.5rem;
420
- margin-bottom: 1rem;
421
- color: var(--dark);
422
- position: relative;
423
- display: inline-block;
424
  }
425
 
426
- .feature-content h3::after {
427
- content: '';
428
- position: absolute;
429
- bottom: -5px;
430
- left: 0;
431
- width: 40px;
432
- height: 2px;
433
- background: var(--primary);
434
- transition: width 0.3s ease;
435
  }
436
 
437
- .feature-card:hover .feature-content h3::after {
438
  width: 100%;
 
 
 
 
 
439
  }
440
 
441
- .content-section {
442
- padding: 5rem 1rem;
443
- background-color: white;
444
- min-height: 50vh;
445
- }
446
-
447
- .cta {
448
- background: linear-gradient(135deg, var(--secondary), var(--primary));
449
- color: white;
450
- padding: 5rem 1rem;
451
- text-align: center;
452
- position: relative;
453
- overflow: hidden;
454
- }
455
-
456
- .cta::before {
457
- content: '';
458
- position: absolute;
459
- top: -50%;
460
- left: -50%;
461
- width: 200%;
462
- height: 200%;
463
- background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 60%);
464
- animation: rotate 20s linear infinite;
465
- z-index: 1;
466
- }
467
-
468
- .cta .container {
469
- position: relative;
470
- z-index: 2;
471
- }
472
-
473
- .cta h2 {
474
- font-size: 2.5rem;
475
- margin-bottom: 1.5rem;
476
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
477
- }
478
-
479
- .cta p {
480
- max-width: 600px;
481
- margin: 0 auto 2rem;
482
- font-size: 1.2rem;
483
  }
484
 
 
485
  footer {
486
  background-color: var(--dark);
487
  color: white;
488
  padding: 3rem 1rem;
 
489
  }
490
 
491
  .footer-grid {
492
  display: grid;
493
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
494
  gap: 2rem;
495
  }
496
 
@@ -544,63 +507,236 @@
544
  color: #aaa;
545
  }
546
 
547
- .card {
548
- background-color: white;
549
- border-radius: 10px;
550
- overflow: hidden;
551
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
552
- transition: all 0.5s ease;
553
- margin-bottom: 2rem;
 
 
 
 
 
 
 
 
 
 
 
554
  }
555
 
556
- .card:hover {
557
- transform: translateY(-5px);
558
- box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
559
  }
560
 
561
- .card-header {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
562
  background: linear-gradient(135deg, var(--primary), var(--secondary));
563
  color: white;
564
- padding: 1.5rem;
 
 
 
565
  }
566
 
567
- .card-body {
568
- padding: 1.5rem;
 
 
 
569
  }
570
 
571
- .job-grid {
572
- display: grid;
573
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
574
- gap: 2rem;
575
  }
576
 
577
- .job-card {
578
- background-color: white;
579
- border-radius: 10px;
580
- overflow: hidden;
581
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
582
- transition: all 0.5s ease;
583
- height: 100%;
584
  display: flex;
585
- flex-direction: column;
 
586
  }
587
 
588
- .job-card:hover {
589
- transform: translateY(-10px);
590
- box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
 
 
 
 
 
591
  }
592
 
593
- .job-header {
594
- background: linear-gradient(135deg, rgba(67, 97, 238, 0.9), rgba(58, 12, 163, 0.9));
595
- color: white;
596
- padding: 1.5rem;
 
 
 
 
 
597
  }
598
 
599
- .job-header h3 {
600
- font-size: 1.5rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
601
  }
602
 
603
- /* Additional content styling omitted for brevity */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
604
  </style>
605
  </head>
606
  <body>
@@ -609,13 +745,11 @@
609
  <a href="{{ url_for('index') }}" class="logo">
610
  <span class="logo-part1">Cod</span><span class="logo-part2">in</span><span class="logo-part3">go</span>
611
  </a>
612
- <div class="login-buttons">
 
 
 
613
  {% if current_user.is_authenticated %}
614
- {#
615
- Display navigation options based on the authenticated user's role.
616
- Job seekers (role: "unemployed") can view available jobs and their own applications.
617
- Recruiters and admins can post new jobs, view the jobs list and access the recruiter dashboard.
618
- #}
619
  {% if current_user.role == 'unemployed' %}
620
  <a href="{{ url_for('jobs') }}" class="btn btn-outline">Jobs</a>
621
  <a href="{{ url_for('my_applications') }}" class="btn btn-outline">My Applications</a>
@@ -631,9 +765,8 @@
631
  <a href="{{ url_for('auth.signup') }}" class="btn btn-primary">Sign Up</a>
632
  {% endif %}
633
  </div>
634
- <!-- Mobile chat icon visible only on small screens -->
635
- <div id="chatbot-nav" class="chat-nav-icon" onclick="toggleChatbot()">💬</div>
636
-
637
  </div>
638
  </header>
639
 
@@ -654,123 +787,15 @@
654
  {% block content %}{% endblock %}
655
  </div>
656
 
657
- #CHATBOT START
658
- <!-- Chatbot Toggle Button -->
659
- <!--
660
- The floating chat button toggles the visibility of the chat window.
661
- We use a flex container here to ensure the emoji and text remain
662
- centred on all screen sizes. Additional media queries adjust the
663
- button's position and padding for very small viewports.
664
- -->
665
  <div id="chatbot-toggle" onclick="toggleChatbot()">💬</div>
666
 
667
- <!-- Chatbox Popup -->
668
- <div id="chatbot-box">
669
- <div id="chat-header">LUNA AI</div>
670
- <div id="chat-messages"></div>
671
- <input id="chat-input" type="text" placeholder="Ask me anything..." onkeydown="sendChat(event)">
672
- </div>
673
-
674
- <style>
675
- #chatbot-toggle {
676
- /* Floating circular button on desktop. It is vertically centred along the right edge */
677
- position: fixed;
678
- top: 50%;
679
- right: 1rem;
680
- transform: translateY(-50%);
681
- width: 3rem;
682
- height: 3rem;
683
- background-color: #4caf50;
684
- color: #ffffff;
685
- border-radius: 50%;
686
- cursor: pointer;
687
- z-index: 1000;
688
- display: flex;
689
- align-items: center;
690
- justify-content: center;
691
- font-size: 1.5rem;
692
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
693
- transition: background-color 0.2s ease;
694
- }
695
-
696
- #chatbot-toggle:hover {
697
- background-color: #43a047;
698
- }
699
-
700
- /* Chat icon inside the navbar (hidden by default and shown on small screens via media query) */
701
- #chatbot-nav {
702
- display: none;
703
- }
704
-
705
- #chatbot-box {
706
- position: fixed;
707
- /* Align the chat window vertically with the toggle on desktop */
708
- top: 50%;
709
- right: calc(1rem + 3rem + 1rem);
710
- transform: translateY(-50%);
711
- /* Default dimensions for larger screens */
712
- width: 20rem;
713
- height: 25rem;
714
- background: white;
715
- border: 2px solid #ccc;
716
- border-radius: 10px;
717
- display: none;
718
- flex-direction: column;
719
- z-index: 1000;
720
- box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
721
- }
722
-
723
- #chat-header {
724
- background-color: #4caf50;
725
- color: white;
726
- padding: 10px;
727
- text-align: center;
728
- font-weight: bold;
729
- }
730
-
731
- #chat-messages {
732
- flex: 1;
733
- padding: 10px;
734
- overflow-y: auto;
735
- max-height: 300px;
736
- }
737
-
738
- /* Responsive adjustments for small screens */
739
- @media (max-width: 768px) {
740
- /* Hide the floating button and reveal the navbar icon on mobile */
741
- #chatbot-toggle {
742
- display: none !important;
743
- }
744
- #chatbot-nav {
745
- display: block;
746
- font-size: 1.5rem;
747
- color: var(--accent);
748
- margin-left: 1rem;
749
- cursor: pointer;
750
- }
751
- #chatbot-box {
752
- width: 90vw;
753
- height: 60vh;
754
- bottom: 1rem;
755
- right: 5vw;
756
- top: auto;
757
- transform: none;
758
- }
759
- #chat-messages {
760
- max-height: calc(60vh - 5.5rem);
761
- }
762
- }
763
-
764
- #chat-input {
765
- border: none;
766
- border-top: 1px solid #ccc;
767
- padding: 10px;
768
- width: 100%;
769
- box-sizing: border-box;
770
- }
771
- </style>
772
-
773
- #CHATBOT END
774
  </main>
775
 
776
  <footer>
@@ -780,9 +805,9 @@
780
  <h3>Codingo</h3>
781
  <p>AI-powered recruitment platform that revolutionizes how companies hire technical talent.</p>
782
  <div class="social-links">
783
- <a href="#"><span>f</span></a>
784
- <a href="#"><span>t</span></a>
785
- <a href="#"><span>in</span></a>
786
  </div>
787
  </div>
788
  </div>
@@ -792,91 +817,83 @@
792
  </div>
793
  </footer>
794
 
795
- {# -------------------------------------------------------------------------
796
- Chatbot UI scripts and styles
797
-
798
- The following script powers the floating chatbot widget located at the
799
- bottom right of every page. When the user clicks the 💬 button, the
800
- widget toggles visibility. Pressing Enter in the input box sends the
801
- message to the `/chatbot` endpoint defined in ``app.py``. Both user
802
- and bot messages are appended to the conversation pane with simple
803
- styling defined below. Jinja's ``url_for`` helper is used to
804
- dynamically generate the correct path to the endpoint at render time.
805
- #}
806
- <script type="text/javascript">
807
- function toggleChatbot() {
808
  const box = document.getElementById('chatbot-box');
809
  if (!box) return;
810
- // Toggle between flex (visible) and none (hidden)
811
  box.style.display = (box.style.display === 'flex') ? 'none' : 'flex';
812
- }
813
 
814
- function sendChat(event) {
815
  if (event.key === 'Enter') {
816
- event.preventDefault();
817
- const input = document.getElementById('chat-input');
818
- const message = input.value.trim();
819
- if (!message) return;
820
- appendChatMessage(message, 'user');
821
- input.value = '';
822
- fetch("{{ url_for('chatbot_endpoint') }}", {
823
- method: 'POST',
824
- headers: { 'Content-Type': 'application/json' },
825
- body: JSON.stringify({ message: message })
826
- }).then(response => response.json())
 
 
 
 
 
 
827
  .then(data => {
828
- if (data.response) {
829
- appendChatMessage(data.response, 'bot');
830
- } else {
831
- appendChatMessage(data.error || 'Error occurred.', 'bot');
832
- }
833
- }).catch(() => {
834
- appendChatMessage('Network error.', 'bot');
 
 
 
 
 
835
  });
836
  }
837
- }
838
 
839
- function appendChatMessage(text, sender) {
840
  const container = document.getElementById('chat-messages');
841
  if (!container) return;
 
842
  const wrapper = document.createElement('div');
843
  wrapper.className = sender === 'user' ? 'user-message' : 'bot-message';
 
844
  const bubble = document.createElement('div');
845
  bubble.className = sender === 'user' ? 'user-bubble' : 'bot-bubble';
846
  bubble.textContent = text;
 
847
  wrapper.appendChild(bubble);
848
  container.appendChild(wrapper);
849
  container.scrollTop = container.scrollHeight;
850
- }
851
- </script>
852
- <style>
853
- /* Chat message styling for user and bot */
854
- #chat-messages .user-message {
855
- display: flex;
856
- justify-content: flex-end;
857
- margin-bottom: 8px;
858
- }
859
- #chat-messages .bot-message {
860
- display: flex;
861
- justify-content: flex-start;
862
- margin-bottom: 8px;
863
- }
864
- #chat-messages .user-bubble {
865
- background-color: #4caf50;
866
- color: #ffffff;
867
- padding: 8px 12px;
868
- border-radius: 12px;
869
- max-width: 80%;
870
- word-wrap: break-word;
871
- }
872
- #chat-messages .bot-bubble {
873
- background-color: #f1f0f0;
874
- color: #000000;
875
- padding: 8px 12px;
876
- border-radius: 12px;
877
- max-width: 80%;
878
- word-wrap: break-word;
879
- }
880
- </style>
881
  </body>
882
- </html>
 
14
  --success: #2ecc71;
15
  --warning: #f39c12;
16
  --danger: #e74c3c;
17
+ --info: #3498db;
18
  }
19
 
20
  * {
 
30
  line-height: 1.6;
31
  perspective: 1000px;
32
  overflow-x: hidden;
33
+ min-height: 100vh;
34
+ display: flex;
35
+ flex-direction: column;
36
  }
37
 
38
+ /* Header Styles */
39
  header {
40
  background: linear-gradient(135deg, var(--primary), var(--secondary));
41
  color: white;
 
57
  display: flex;
58
  justify-content: space-between;
59
  align-items: center;
60
+ flex-wrap: wrap;
61
+ gap: 1rem;
62
  }
63
 
64
+ /* Logo Styles */
65
  .logo {
66
  display: flex;
67
  align-items: center;
 
100
  color: var(--accent);
101
  }
102
 
103
+ /* Navigation Buttons */
104
  .login-buttons {
105
  display: flex;
106
  align-items: center;
107
+ gap: 0.75rem;
108
+ flex-wrap: wrap;
109
+ }
110
+
111
+ /* Mobile Menu Toggle */
112
+ .mobile-menu-toggle {
113
+ display: none;
114
+ background: transparent;
115
+ border: 2px solid var(--accent);
116
+ color: var(--accent);
117
+ padding: 0.5rem;
118
+ border-radius: 5px;
119
+ cursor: pointer;
120
+ font-size: 1.5rem;
121
  }
122
 
123
+ /* Welcome Message */
124
  .welcome-message {
125
  color: white;
126
  font-weight: 500;
 
127
  display: flex;
128
  align-items: center;
129
  background-color: rgba(255, 255, 255, 0.1);
130
  padding: 0.5rem 1rem;
131
  border-radius: 5px;
132
  transition: all 0.3s ease;
133
+ white-space: nowrap;
134
  }
135
 
136
  .welcome-message:before {
 
138
  margin-right: 0.5rem;
139
  }
140
 
141
+ /* Button Styles */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  .btn {
143
  padding: 0.5rem 1.5rem;
144
  border-radius: 5px;
 
150
  position: relative;
151
  overflow: hidden;
152
  z-index: 1;
153
+ display: inline-block;
154
+ white-space: nowrap;
155
  }
156
 
157
  .btn::before {
 
182
  color: white;
183
  }
184
 
185
+ .btn-logout {
186
+ background-color: transparent;
187
+ border: 2px solid var(--accent);
188
+ color: var(--accent);
189
+ font-weight: 600;
190
+ }
191
+
192
+ .btn-logout:hover {
193
+ background-color: var(--accent);
194
+ color: var(--dark);
195
+ transform: translateY(-2px);
196
+ box-shadow: 0 5px 15px rgba(76, 201, 240, 0.3);
197
+ }
198
+
199
  .btn:hover {
200
  transform: translateY(-2px);
201
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
202
  }
203
 
204
+ /* Flash Messages */
205
+ .flash-messages {
206
+ margin: 1rem 0;
207
+ }
208
+
209
+ .alert {
210
+ padding: 1rem 1.5rem;
211
+ border-radius: 8px;
212
+ margin-bottom: 1rem;
213
+ font-weight: 500;
214
+ position: relative;
215
+ animation: slideIn 0.3s ease-out;
216
+ display: flex;
217
+ align-items: center;
218
+ gap: 0.75rem;
219
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
220
+ }
221
+
222
+ @keyframes slideIn {
223
+ from {
224
+ transform: translateY(-20px);
225
+ opacity: 0;
226
+ }
227
+ to {
228
+ transform: translateY(0);
229
+ opacity: 1;
230
+ }
231
+ }
232
+
233
+ .alert::before {
234
+ font-size: 1.2rem;
235
+ }
236
+
237
+ .alert-success {
238
+ background-color: #d4edda;
239
+ color: #155724;
240
+ border: 1px solid #c3e6cb;
241
+ }
242
+
243
+ .alert-success::before {
244
+ content: '✓';
245
+ }
246
+
247
+ .alert-danger, .alert-error {
248
+ background-color: #f8d7da;
249
+ color: #721c24;
250
+ border: 1px solid #f5c6cb;
251
+ }
252
+
253
+ .alert-danger::before, .alert-error::before {
254
+ content: '⚠';
255
+ }
256
+
257
+ .alert-warning {
258
+ background-color: #fff3cd;
259
+ color: #856404;
260
+ border: 1px solid #ffeaa7;
261
+ }
262
+
263
+ .alert-warning::before {
264
+ content: '!';
265
+ }
266
+
267
+ .alert-info {
268
+ background-color: #d1ecf1;
269
+ color: #0c5460;
270
+ border: 1px solid #bee5eb;
271
+ }
272
+
273
+ .alert-info::before {
274
+ content: 'ℹ';
275
+ }
276
+
277
+ /* Hero Section */
278
  .hero {
279
  background: linear-gradient(rgba(67, 97, 238, 0.8), rgba(58, 12, 163, 0.9)), url("/api/placeholder/1200/600") no-repeat center center/cover;
280
  color: white;
 
343
  animation: fadeIn 1s ease-out 0.3s both;
344
  }
345
 
346
+ /* Main Content */
347
+ main {
348
+ flex: 1;
349
+ padding: 2rem 0;
 
 
350
  }
351
 
352
+ /* Breadcrumbs */
353
+ .breadcrumbs {
354
+ list-style: none;
 
 
 
 
 
 
 
 
355
  display: flex;
 
356
  align-items: center;
357
+ gap: 0.5rem;
358
+ margin-bottom: 2rem;
359
+ padding: 0.75rem 1rem;
360
+ background-color: white;
361
+ border-radius: 8px;
362
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  flex-wrap: wrap;
 
 
364
  }
365
 
366
+ .breadcrumbs li {
367
+ display: flex;
368
+ align-items: center;
 
 
369
  }
370
 
371
+ .breadcrumbs li:not(:last-child)::after {
372
+ content: '›';
373
+ margin-left: 0.5rem;
374
+ color: #999;
 
375
  }
376
 
377
+ .breadcrumbs a {
 
378
  color: var(--primary);
379
+ text-decoration: none;
380
+ transition: color 0.3s ease;
 
 
 
 
 
 
 
 
 
 
 
 
381
  }
382
 
383
+ .breadcrumbs a:hover {
384
+ color: var(--secondary);
 
 
385
  }
386
 
387
+ /* Content Section */
388
+ .content-section {
389
+ padding: 3rem 1rem;
390
+ background-color: white;
391
+ min-height: 50vh;
392
  }
393
 
394
+ /* Cards */
395
+ .card {
396
  background-color: white;
397
  border-radius: 10px;
398
  overflow: hidden;
399
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
400
  transition: all 0.5s ease;
401
+ margin-bottom: 2rem;
 
 
 
 
402
  }
403
 
404
+ .card:hover {
405
+ transform: translateY(-5px);
406
  box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
407
  }
408
 
409
+ .card-header {
410
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
411
+ color: white;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  padding: 1.5rem;
 
 
 
413
  }
414
 
415
+ .card-body {
416
+ padding: 1.5rem;
417
  }
418
 
419
+ /* Form Styles */
420
+ .form-group {
421
+ margin-bottom: 1.5rem;
 
 
 
422
  }
423
 
424
+ .form-group label {
425
+ font-weight: 600;
426
+ color: var(--primary);
427
+ margin-bottom: 0.5rem;
428
+ display: block;
 
 
 
 
429
  }
430
 
431
+ .form-control {
432
  width: 100%;
433
+ padding: 0.75rem;
434
+ font-size: 1rem;
435
+ border-radius: 6px;
436
+ border: 1px solid #ddd;
437
+ transition: all 0.3s ease;
438
  }
439
 
440
+ .form-control:focus {
441
+ outline: none;
442
+ border-color: var(--primary);
443
+ box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  }
445
 
446
+ /* Footer */
447
  footer {
448
  background-color: var(--dark);
449
  color: white;
450
  padding: 3rem 1rem;
451
+ margin-top: auto;
452
  }
453
 
454
  .footer-grid {
455
  display: grid;
456
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
457
  gap: 2rem;
458
  }
459
 
 
507
  color: #aaa;
508
  }
509
 
510
+ /* Chatbot Styles */
511
+ #chatbot-toggle {
512
+ position: fixed;
513
+ bottom: 2rem;
514
+ right: 2rem;
515
+ width: 3.5rem;
516
+ height: 3.5rem;
517
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
518
+ color: white;
519
+ border-radius: 50%;
520
+ cursor: pointer;
521
+ z-index: 1000;
522
+ display: flex;
523
+ align-items: center;
524
+ justify-content: center;
525
+ font-size: 1.5rem;
526
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
527
+ transition: all 0.3s ease;
528
  }
529
 
530
+ #chatbot-toggle:hover {
531
+ transform: scale(1.1);
532
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
533
  }
534
 
535
+ .chat-nav-icon {
536
+ display: none;
537
+ font-size: 1.5rem;
538
+ color: var(--accent);
539
+ cursor: pointer;
540
+ }
541
+
542
+ #chatbot-box {
543
+ position: fixed;
544
+ bottom: 6rem;
545
+ right: 2rem;
546
+ width: 350px;
547
+ height: 500px;
548
+ background: white;
549
+ border-radius: 15px;
550
+ display: none;
551
+ flex-direction: column;
552
+ z-index: 1000;
553
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
554
+ overflow: hidden;
555
+ }
556
+
557
+ #chat-header {
558
  background: linear-gradient(135deg, var(--primary), var(--secondary));
559
  color: white;
560
+ padding: 1rem;
561
+ text-align: center;
562
+ font-weight: bold;
563
+ font-size: 1.2rem;
564
  }
565
 
566
+ #chat-messages {
567
+ flex: 1;
568
+ padding: 1rem;
569
+ overflow-y: auto;
570
+ background-color: #f9f9f9;
571
  }
572
 
573
+ #chat-messages .user-message {
574
+ display: flex;
575
+ justify-content: flex-end;
576
+ margin-bottom: 1rem;
577
  }
578
 
579
+ #chat-messages .bot-message {
 
 
 
 
 
 
580
  display: flex;
581
+ justify-content: flex-start;
582
+ margin-bottom: 1rem;
583
  }
584
 
585
+ #chat-messages .user-bubble {
586
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
587
+ color: white;
588
+ padding: 0.75rem 1rem;
589
+ border-radius: 18px 18px 4px 18px;
590
+ max-width: 80%;
591
+ word-wrap: break-word;
592
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
593
  }
594
 
595
+ #chat-messages .bot-bubble {
596
+ background-color: white;
597
+ color: var(--dark);
598
+ padding: 0.75rem 1rem;
599
+ border-radius: 18px 18px 18px 4px;
600
+ max-width: 80%;
601
+ word-wrap: break-word;
602
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
603
+ border: 1px solid #eee;
604
  }
605
 
606
+ #chat-input {
607
+ border: none;
608
+ border-top: 1px solid #eee;
609
+ padding: 1rem;
610
+ width: 100%;
611
+ box-sizing: border-box;
612
+ font-size: 1rem;
613
+ transition: all 0.3s ease;
614
+ }
615
+
616
+ #chat-input:focus {
617
+ outline: none;
618
+ background-color: #f9f9f9;
619
+ }
620
+
621
+ /* Responsive Styles */
622
+ @media (max-width: 768px) {
623
+ .nav-container {
624
+ padding: 0.5rem 0;
625
+ }
626
+
627
+ .logo {
628
+ font-size: 1.5rem;
629
+ }
630
+
631
+ .mobile-menu-toggle {
632
+ display: block;
633
+ }
634
+
635
+ .login-buttons {
636
+ width: 100%;
637
+ order: 3;
638
+ justify-content: center;
639
+ padding: 1rem 0;
640
+ background-color: rgba(0, 0, 0, 0.1);
641
+ margin: 0 -1rem;
642
+ border-radius: 8px;
643
+ display: none;
644
+ }
645
+
646
+ .login-buttons.show {
647
+ display: flex;
648
+ }
649
+
650
+ .welcome-message {
651
+ font-size: 0.9rem;
652
+ padding: 0.4rem 0.8rem;
653
+ }
654
+
655
+ .btn {
656
+ padding: 0.4rem 1rem;
657
+ font-size: 0.9rem;
658
+ }
659
+
660
+ .hero h1 {
661
+ font-size: 2rem;
662
+ }
663
+
664
+ .hero p {
665
+ font-size: 1rem;
666
+ }
667
+
668
+ #chatbot-toggle {
669
+ display: none !important;
670
+ }
671
+
672
+ .chat-nav-icon {
673
+ display: block;
674
+ }
675
+
676
+ #chatbot-box {
677
+ width: 90vw;
678
+ height: 70vh;
679
+ bottom: 1rem;
680
+ right: 5vw;
681
+ max-width: 400px;
682
+ }
683
+
684
+ .card {
685
+ margin-bottom: 1rem;
686
+ }
687
+
688
+ .content-section {
689
+ padding: 2rem 1rem;
690
+ }
691
+
692
+ .footer-grid {
693
+ grid-template-columns: 1fr;
694
+ text-align: center;
695
+ }
696
+
697
+ .social-links {
698
+ justify-content: center;
699
+ }
700
  }
701
 
702
+ @media (max-width: 480px) {
703
+ .hero h1 {
704
+ font-size: 1.75rem;
705
+ }
706
+
707
+ .btn {
708
+ width: 100%;
709
+ margin-bottom: 0.5rem;
710
+ }
711
+
712
+ .login-buttons {
713
+ flex-direction: column;
714
+ gap: 0.5rem;
715
+ }
716
+
717
+ .breadcrumbs {
718
+ font-size: 0.9rem;
719
+ }
720
+ }
721
+
722
+ /* Utility Classes */
723
+ .text-center {
724
+ text-align: center;
725
+ }
726
+
727
+ .mt-1 { margin-top: 0.5rem; }
728
+ .mt-2 { margin-top: 1rem; }
729
+ .mt-3 { margin-top: 1.5rem; }
730
+ .mt-4 { margin-top: 2rem; }
731
+
732
+ .mb-1 { margin-bottom: 0.5rem; }
733
+ .mb-2 { margin-bottom: 1rem; }
734
+ .mb-3 { margin-bottom: 1.5rem; }
735
+ .mb-4 { margin-bottom: 2rem; }
736
+
737
+ .gap-1 { gap: 0.5rem; }
738
+ .gap-2 { gap: 1rem; }
739
+ .gap-3 { gap: 1.5rem; }
740
  </style>
741
  </head>
742
  <body>
 
745
  <a href="{{ url_for('index') }}" class="logo">
746
  <span class="logo-part1">Cod</span><span class="logo-part2">in</span><span class="logo-part3">go</span>
747
  </a>
748
+
749
+ <button class="mobile-menu-toggle" onclick="toggleMobileMenu()">☰</button>
750
+
751
+ <div class="login-buttons" id="nav-menu">
752
  {% if current_user.is_authenticated %}
 
 
 
 
 
753
  {% if current_user.role == 'unemployed' %}
754
  <a href="{{ url_for('jobs') }}" class="btn btn-outline">Jobs</a>
755
  <a href="{{ url_for('my_applications') }}" class="btn btn-outline">My Applications</a>
 
765
  <a href="{{ url_for('auth.signup') }}" class="btn btn-primary">Sign Up</a>
766
  {% endif %}
767
  </div>
768
+
769
+ <div class="chat-nav-icon" onclick="toggleChatbot()">💬</div>
 
770
  </div>
771
  </header>
772
 
 
787
  {% block content %}{% endblock %}
788
  </div>
789
 
790
+ <!-- Chatbot Toggle Button -->
 
 
 
 
 
 
 
791
  <div id="chatbot-toggle" onclick="toggleChatbot()">💬</div>
792
 
793
+ <!-- Chatbox Popup -->
794
+ <div id="chatbot-box">
795
+ <div id="chat-header">LUNA AI Assistant</div>
796
+ <div id="chat-messages"></div>
797
+ <input id="chat-input" type="text" placeholder="Ask me anything..." onkeydown="sendChat(event)">
798
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
799
  </main>
800
 
801
  <footer>
 
805
  <h3>Codingo</h3>
806
  <p>AI-powered recruitment platform that revolutionizes how companies hire technical talent.</p>
807
  <div class="social-links">
808
+ <a href="#" aria-label="Facebook"><span>f</span></a>
809
+ <a href="#" aria-label="Twitter"><span>t</span></a>
810
+ <a href="#" aria-label="LinkedIn"><span>in</span></a>
811
  </div>
812
  </div>
813
  </div>
 
817
  </div>
818
  </footer>
819
 
820
+ <script type="text/javascript">
821
+ // Mobile menu toggle
822
+ function toggleMobileMenu() {
823
+ const menu = document.getElementById('nav-menu');
824
+ menu.classList.toggle('show');
825
+ }
826
+
827
+ // Chatbot functionality
828
+ function toggleChatbot() {
 
 
 
 
829
  const box = document.getElementById('chatbot-box');
830
  if (!box) return;
 
831
  box.style.display = (box.style.display === 'flex') ? 'none' : 'flex';
832
+ }
833
 
834
+ function sendChat(event) {
835
  if (event.key === 'Enter') {
836
+ event.preventDefault();
837
+ const input = document.getElementById('chat-input');
838
+ const message = input.value.trim();
839
+ if (!message) return;
840
+
841
+ appendChatMessage(message, 'user');
842
+ input.value = '';
843
+
844
+ // Show typing indicator
845
+ const typingIndicator = appendChatMessage('...', 'bot');
846
+
847
+ fetch("{{ url_for('chatbot_endpoint') }}", {
848
+ method: 'POST',
849
+ headers: { 'Content-Type': 'application/json' },
850
+ body: JSON.stringify({ message: message })
851
+ })
852
+ .then(response => response.json())
853
  .then(data => {
854
+ // Remove typing indicator
855
+ typingIndicator.remove();
856
+
857
+ if (data.response) {
858
+ appendChatMessage(data.response, 'bot');
859
+ } else {
860
+ appendChatMessage(data.error || 'Error occurred.', 'bot');
861
+ }
862
+ })
863
+ .catch(() => {
864
+ typingIndicator.remove();
865
+ appendChatMessage('Network error. Please try again.', 'bot');
866
  });
867
  }
868
+ }
869
 
870
+ function appendChatMessage(text, sender) {
871
  const container = document.getElementById('chat-messages');
872
  if (!container) return;
873
+
874
  const wrapper = document.createElement('div');
875
  wrapper.className = sender === 'user' ? 'user-message' : 'bot-message';
876
+
877
  const bubble = document.createElement('div');
878
  bubble.className = sender === 'user' ? 'user-bubble' : 'bot-bubble';
879
  bubble.textContent = text;
880
+
881
  wrapper.appendChild(bubble);
882
  container.appendChild(wrapper);
883
  container.scrollTop = container.scrollHeight;
884
+
885
+ return wrapper;
886
+ }
887
+
888
+ // Close mobile menu when clicking outside
889
+ document.addEventListener('click', function(event) {
890
+ const menu = document.getElementById('nav-menu');
891
+ const toggle = document.querySelector('.mobile-menu-toggle');
892
+
893
+ if (!menu.contains(event.target) && !toggle.contains(event.target)) {
894
+ menu.classList.remove('show');
895
+ }
896
+ });
897
+ </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
  </body>
899
+ </html>
backend/templates/my_applications.html CHANGED
@@ -4,9 +4,9 @@
4
 
5
  {% block content %}
6
  <section class="content-section">
7
- <div class="section-title">
8
  <h2>My Applications</h2>
9
- <p>Your submitted job applications are listed below.</p>
10
  </div>
11
 
12
  <ul class="breadcrumbs">
@@ -14,120 +14,525 @@
14
  <li>My Applications</li>
15
  </ul>
16
 
17
- <!-- Prominent interview tips moved from the apply page. This section is placed
18
- near the top of the My Applications page so candidates see the
19
- guidelines before initiating their AI interview. It is responsive
20
- and uses colours consistent with the overall theme. -->
21
- <div class="tips-section">
22
- <h3>Important Interview Guidelines</h3>
23
- <ul>
24
- <li>The interview can be taken only once, so please be prepared.</li>
25
- <li>Make sure you are in a quiet environment with a stable internet connection.</li>
26
- <li>This is not a final job interview, but it helps the company shortlist the most relevant candidates.</li>
27
- <li>The interview is customized based on your CV and the job requirements.</li>
28
- <li>It takes 10 to 15 minutes and includes both general and skill‑based questions.</li>
29
- </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  </div>
31
 
32
- <div class="application-list">
 
33
  {% if applications %}
34
- {% for application in applications %}
35
- <div class="application-card">
36
- <div class="application-header">
37
- <h3>{{ application.job.role if application.job else 'Unknown Role' }}</h3>
38
- <div class="application-info">
39
- <span>{{ application.job.company if application.job else '' }}</span>
40
- <span>Status: {{ application.status }}</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  </div>
42
  </div>
43
- <div class="application-body">
44
- <p>Applied on {{ application.date_applied.strftime('%B %d, %Y') }}</p>
45
- {% if application.job %}
46
- <p>{{ application.job.description[:150] }}{% if application.job.description|length > 150 %}...{% endif %}</p>
47
- {% endif %}
48
- </div>
49
- <div class="application-footer">
50
- {% if application.job %}
51
- <a href="{{ url_for('job_detail', job_id=application.job.id) }}" class="btn btn-outline">View Job</a>
52
- {% endif %}
53
- {% if application.extracted_features %}
54
- <!-- Offer to take the interview if CV data exists -->
55
- <a href="{{ url_for('interview_page', job_id=application.job.id) }}" class="btn btn-primary">Take Interview</a>
56
- {% endif %}
57
- </div>
58
- </div>
59
- {% endfor %}
60
  {% else %}
61
- <div class="card">
62
- <div class="card-body">
63
- <p>You haven't applied to any jobs yet. Browse available positions on the <a href="{{ url_for('jobs') }}">jobs page</a>.</p>
64
- </div>
 
 
 
65
  </div>
66
  {% endif %}
67
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  </section>
69
 
70
  <style>
71
- .application-list {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  display: grid;
73
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
74
  gap: 1.5rem;
75
  }
76
 
 
77
  .application-card {
78
- background-color: var(--light);
79
- border: 1px solid #eee;
80
- border-radius: 8px;
81
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
 
 
82
  display: flex;
83
  flex-direction: column;
84
- justify-content: space-between;
85
- padding: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  }
87
 
88
  .application-header h3 {
89
- margin-bottom: 0.5rem;
90
  color: var(--primary);
 
 
91
  }
92
 
93
- .application-info span {
94
- margin-right: 1rem;
 
 
 
 
 
 
 
 
95
  color: var(--dark);
96
- font-weight: 500;
97
  }
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  .application-footer {
100
- margin-top: 1rem;
101
  display: flex;
102
- justify-content: flex-end;
103
- gap: 0.5rem;
104
  }
105
 
106
- /* Interview tips styling. Creates a highlighted panel with a coloured
107
- border and responsive padding. */
108
- .tips-section {
109
- background-color: #f8f9fa;
110
- border-left: 5px solid var(--primary);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  padding: 2rem;
112
- margin: 2rem 0;
113
- border-radius: 8px;
 
 
114
  }
115
- .tips-section h3 {
116
- margin-top: 0;
 
 
 
 
 
 
 
117
  color: var(--primary);
118
- margin-bottom: 1rem;
119
- font-size: 1.5rem;
120
  }
121
- .tips-section ul {
122
- margin-left: 1rem;
123
- padding-left: 1rem;
124
- list-style-type: disc;
125
- line-height: 1.6;
126
  }
127
- @media (max-width: 600px) {
128
- .tips-section {
129
- padding: 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
131
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  </style>
133
- {% endblock %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  {% block content %}
6
  <section class="content-section">
7
+ <div class="section-header">
8
  <h2>My Applications</h2>
9
+ <p>Track and manage your job applications</p>
10
  </div>
11
 
12
  <ul class="breadcrumbs">
 
14
  <li>My Applications</li>
15
  </ul>
16
 
17
+ <!-- Interview Guidelines Section -->
18
+ <div class="interview-guidelines">
19
+ <div class="guidelines-header">
20
+ <h3><span class="icon">🎯</span> Important Interview Guidelines</h3>
21
+ </div>
22
+ <div class="guidelines-content">
23
+ <div class="guideline-item">
24
+ <span class="guideline-icon">⚡</span>
25
+ <div class="guideline-text">
26
+ <strong>One-time opportunity:</strong> The interview can be taken only once, so please be well-prepared.
27
+ </div>
28
+ </div>
29
+ <div class="guideline-item">
30
+ <span class="guideline-icon">🎧</span>
31
+ <div class="guideline-text">
32
+ <strong>Environment:</strong> Ensure you're in a quiet space with a stable internet connection.
33
+ </div>
34
+ </div>
35
+ <div class="guideline-item">
36
+ <span class="guideline-icon">📋</span>
37
+ <div class="guideline-text">
38
+ <strong>Purpose:</strong> This helps companies shortlist the most relevant candidates for the role.
39
+ </div>
40
+ </div>
41
+ <div class="guideline-item">
42
+ <span class="guideline-icon">🎯</span>
43
+ <div class="guideline-text">
44
+ <strong>Customization:</strong> Questions are tailored based on your CV and job requirements.
45
+ </div>
46
+ </div>
47
+ <div class="guideline-item">
48
+ <span class="guideline-icon">⏱️</span>
49
+ <div class="guideline-text">
50
+ <strong>Duration:</strong> 10-15 minutes including general and skill-based questions.
51
+ </div>
52
+ </div>
53
+ </div>
54
  </div>
55
 
56
+ <!-- Applications Grid -->
57
+ <div class="applications-container">
58
  {% if applications %}
59
+ <div class="applications-grid">
60
+ {% for application in applications %}
61
+ <div class="application-card" data-status="{{ application.status }}">
62
+ <div class="card-status-badge status-{{ application.status.lower().replace(' ', '-') }}">
63
+ {{ application.status }}
64
+ </div>
65
+
66
+ <div class="application-header">
67
+ <h3>{{ application.job.role if application.job else 'Unknown Role' }}</h3>
68
+ <div class="company-info">
69
+ <span class="company-name">{{ application.job.company if application.job else '' }}</span>
70
+ {% if application.job and application.job.location %}
71
+ <span class="location">📍 {{ application.job.location }}</span>
72
+ {% endif %}
73
+ </div>
74
+ </div>
75
+
76
+ <div class="application-body">
77
+ <div class="application-meta">
78
+ <span class="meta-item">
79
+ <i class="icon">📅</i>
80
+ Applied {{ application.date_applied.strftime('%B %d, %Y') }}
81
+ </span>
82
+ {% if application.job and application.job.seniority %}
83
+ <span class="meta-item">
84
+ <i class="icon">💼</i>
85
+ {{ application.job.seniority }}
86
+ </span>
87
+ {% endif %}
88
+ </div>
89
+
90
+ {% if application.job %}
91
+ <p class="job-description">
92
+ {{ application.job.description[:150] }}{% if application.job.description|length > 150 %}...{% endif %}
93
+ </p>
94
+ {% endif %}
95
+ </div>
96
+
97
+ <div class="application-footer">
98
+ {% if application.job %}
99
+ <a href="{{ url_for('job_detail', job_id=application.job.id) }}" class="btn btn-outline btn-sm">
100
+ <span class="btn-icon">👁️</span> View Job
101
+ </a>
102
+ {% endif %}
103
+
104
+ {% if application.extracted_features %}
105
+ <a href="{{ url_for('interview_page', job_id=application.job.id) }}" class="btn btn-primary btn-sm">
106
+ <span class="btn-icon">🎤</span> Take Interview
107
+ </a>
108
+ {% endif %}
109
  </div>
110
  </div>
111
+ {% endfor %}
112
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  {% else %}
114
+ <div class="empty-state">
115
+ <div class="empty-state-icon">📋</div>
116
+ <h3>No Applications Yet</h3>
117
+ <p>You haven't applied to any jobs yet. Start exploring opportunities!</p>
118
+ <a href="{{ url_for('jobs') }}" class="btn btn-primary">
119
+ <span class="btn-icon">🔍</span> Browse Jobs
120
+ </a>
121
  </div>
122
  {% endif %}
123
  </div>
124
+
125
+ <!-- Stats Section -->
126
+ {% if applications %}
127
+ <div class="applications-stats">
128
+ <div class="stat-card">
129
+ <div class="stat-number">{{ applications|length }}</div>
130
+ <div class="stat-label">Total Applications</div>
131
+ </div>
132
+ <div class="stat-card">
133
+ <div class="stat-number">{{ applications|selectattr('status', 'equalto', 'pending')|list|length }}</div>
134
+ <div class="stat-label">Pending Review</div>
135
+ </div>
136
+ <div class="stat-card">
137
+ <div class="stat-number">{{ applications|selectattr('extracted_features')|list|length }}</div>
138
+ <div class="stat-label">Ready for Interview</div>
139
+ </div>
140
+ </div>
141
+ {% endif %}
142
  </section>
143
 
144
  <style>
145
+ /* Section Header */
146
+ .section-header {
147
+ text-align: center;
148
+ margin-bottom: 3rem;
149
+ }
150
+
151
+ .section-header h2 {
152
+ font-size: 2.5rem;
153
+ color: var(--primary);
154
+ margin-bottom: 0.5rem;
155
+ position: relative;
156
+ display: inline-block;
157
+ }
158
+
159
+ .section-header h2::after {
160
+ content: '';
161
+ position: absolute;
162
+ bottom: -10px;
163
+ left: 50%;
164
+ transform: translateX(-50%);
165
+ width: 80px;
166
+ height: 3px;
167
+ background: linear-gradient(to right, var(--primary), var(--accent));
168
+ }
169
+
170
+ .section-header p {
171
+ color: #666;
172
+ font-size: 1.1rem;
173
+ }
174
+
175
+ /* Interview Guidelines */
176
+ .interview-guidelines {
177
+ background: linear-gradient(135deg, #f5f7ff 0%, #e8ecff 100%);
178
+ border-radius: 12px;
179
+ padding: 2rem;
180
+ margin: 2rem 0;
181
+ box-shadow: 0 5px 15px rgba(67, 97, 238, 0.1);
182
+ border: 1px solid rgba(67, 97, 238, 0.1);
183
+ }
184
+
185
+ .guidelines-header {
186
+ margin-bottom: 1.5rem;
187
+ }
188
+
189
+ .guidelines-header h3 {
190
+ color: var(--primary);
191
+ font-size: 1.5rem;
192
+ margin: 0;
193
+ display: flex;
194
+ align-items: center;
195
+ gap: 0.5rem;
196
+ }
197
+
198
+ .guidelines-header .icon {
199
+ font-size: 1.75rem;
200
+ }
201
+
202
+ .guidelines-content {
203
+ display: grid;
204
+ gap: 1rem;
205
+ }
206
+
207
+ .guideline-item {
208
+ display: flex;
209
+ align-items: flex-start;
210
+ gap: 1rem;
211
+ padding: 0.75rem;
212
+ background: white;
213
+ border-radius: 8px;
214
+ transition: all 0.3s ease;
215
+ }
216
+
217
+ .guideline-item:hover {
218
+ transform: translateX(5px);
219
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
220
+ }
221
+
222
+ .guideline-icon {
223
+ font-size: 1.5rem;
224
+ min-width: 2rem;
225
+ display: flex;
226
+ align-items: center;
227
+ justify-content: center;
228
+ }
229
+
230
+ .guideline-text {
231
+ flex: 1;
232
+ line-height: 1.6;
233
+ }
234
+
235
+ .guideline-text strong {
236
+ color: var(--primary);
237
+ }
238
+
239
+ /* Applications Container */
240
+ .applications-container {
241
+ margin: 3rem 0;
242
+ }
243
+
244
+ /* Applications Grid */
245
+ .applications-grid {
246
  display: grid;
247
+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
248
  gap: 1.5rem;
249
  }
250
 
251
+ /* Application Card */
252
  .application-card {
253
+ background: white;
254
+ border-radius: 12px;
255
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
256
+ position: relative;
257
+ transition: all 0.3s ease;
258
+ overflow: hidden;
259
  display: flex;
260
  flex-direction: column;
261
+ }
262
+
263
+ .application-card:hover {
264
+ transform: translateY(-5px);
265
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
266
+ }
267
+
268
+ /* Status Badge */
269
+ .card-status-badge {
270
+ position: absolute;
271
+ top: 1rem;
272
+ right: 1rem;
273
+ padding: 0.25rem 0.75rem;
274
+ border-radius: 20px;
275
+ font-size: 0.875rem;
276
+ font-weight: 600;
277
+ text-transform: uppercase;
278
+ }
279
+
280
+ .status-pending {
281
+ background-color: #fff3cd;
282
+ color: #856404;
283
+ }
284
+
285
+ .status-approved {
286
+ background-color: #d4edda;
287
+ color: #155724;
288
+ }
289
+
290
+ .status-rejected {
291
+ background-color: #f8d7da;
292
+ color: #721c24;
293
+ }
294
+
295
+ .status-interview-scheduled {
296
+ background-color: #d1ecf1;
297
+ color: #0c5460;
298
+ }
299
+
300
+ /* Application Header */
301
+ .application-header {
302
+ padding: 1.5rem 1.5rem 0;
303
  }
304
 
305
  .application-header h3 {
 
306
  color: var(--primary);
307
+ margin: 0 0 0.5rem 0;
308
+ font-size: 1.5rem;
309
  }
310
 
311
+ .company-info {
312
+ display: flex;
313
+ flex-wrap: wrap;
314
+ gap: 1rem;
315
+ color: #666;
316
+ font-size: 0.95rem;
317
+ }
318
+
319
+ .company-name {
320
+ font-weight: 600;
321
  color: var(--dark);
 
322
  }
323
 
324
+ /* Application Body */
325
+ .application-body {
326
+ padding: 1rem 1.5rem;
327
+ flex: 1;
328
+ }
329
+
330
+ .application-meta {
331
+ display: flex;
332
+ flex-wrap: wrap;
333
+ gap: 1rem;
334
+ margin-bottom: 1rem;
335
+ font-size: 0.9rem;
336
+ color: #666;
337
+ }
338
+
339
+ .meta-item {
340
+ display: flex;
341
+ align-items: center;
342
+ gap: 0.25rem;
343
+ }
344
+
345
+ .meta-item .icon {
346
+ font-size: 1rem;
347
+ }
348
+
349
+ .job-description {
350
+ color: #495057;
351
+ line-height: 1.6;
352
+ margin: 0;
353
+ }
354
+
355
+ /* Application Footer */
356
  .application-footer {
357
+ padding: 0 1.5rem 1.5rem;
358
  display: flex;
359
+ gap: 0.75rem;
360
+ flex-wrap: wrap;
361
  }
362
 
363
+ .btn-sm {
364
+ padding: 0.5rem 1rem;
365
+ font-size: 0.9rem;
366
+ }
367
+
368
+ /* Empty State */
369
+ .empty-state {
370
+ text-align: center;
371
+ padding: 4rem 2rem;
372
+ background: #f8f9fa;
373
+ border-radius: 12px;
374
+ border: 2px dashed #dee2e6;
375
+ }
376
+
377
+ .empty-state-icon {
378
+ font-size: 4rem;
379
+ margin-bottom: 1rem;
380
+ opacity: 0.5;
381
+ }
382
+
383
+ .empty-state h3 {
384
+ color: var(--primary);
385
+ margin-bottom: 0.5rem;
386
+ }
387
+
388
+ .empty-state p {
389
+ color: #666;
390
+ margin-bottom: 2rem;
391
+ }
392
+
393
+ /* Stats Section */
394
+ .applications-stats {
395
+ display: grid;
396
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
397
+ gap: 1.5rem;
398
+ margin-top: 3rem;
399
+ }
400
+
401
+ .stat-card {
402
+ background: white;
403
  padding: 2rem;
404
+ border-radius: 12px;
405
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
406
+ text-align: center;
407
+ transition: all 0.3s ease;
408
  }
409
+
410
+ .stat-card:hover {
411
+ transform: translateY(-3px);
412
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
413
+ }
414
+
415
+ .stat-number {
416
+ font-size: 2.5rem;
417
+ font-weight: 700;
418
  color: var(--primary);
419
+ margin-bottom: 0.5rem;
 
420
  }
421
+
422
+ .stat-label {
423
+ color: #666;
424
+ font-size: 1rem;
 
425
  }
426
+
427
+ /* Responsive Design */
428
+ @media (max-width: 768px) {
429
+ .section-header h2 {
430
+ font-size: 2rem;
431
+ }
432
+
433
+ .interview-guidelines {
434
+ padding: 1.5rem;
435
+ }
436
+
437
+ .guidelines-header h3 {
438
+ font-size: 1.25rem;
439
+ }
440
+
441
+ .guideline-item {
442
+ padding: 0.5rem;
443
+ }
444
+
445
+ .guideline-icon {
446
+ font-size: 1.25rem;
447
+ }
448
+
449
+ .applications-grid {
450
+ grid-template-columns: 1fr;
451
+ }
452
+
453
+ .application-card {
454
+ margin-bottom: 1rem;
455
+ }
456
+
457
+ .applications-stats {
458
+ grid-template-columns: 1fr;
459
+ }
460
+
461
+ .stat-card {
462
+ padding: 1.5rem;
463
+ }
464
+ }
465
+
466
+ @media (max-width: 480px) {
467
+ .company-info {
468
+ flex-direction: column;
469
+ gap: 0.5rem;
470
+ }
471
+
472
+ .application-meta {
473
+ flex-direction: column;
474
+ gap: 0.5rem;
475
+ }
476
+
477
+ .application-footer {
478
+ flex-direction: column;
479
+ }
480
+
481
+ .application-footer .btn {
482
+ width: 100%;
483
+ justify-content: center;
484
  }
485
  }
486
+
487
+ /* Loading Animation */
488
+ @keyframes shimmer {
489
+ 0% {
490
+ background-position: -1000px 0;
491
+ }
492
+ 100% {
493
+ background-position: 1000px 0;
494
+ }
495
+ }
496
+
497
+ .loading {
498
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
499
+ background-size: 1000px 100%;
500
+ animation: shimmer 2s infinite;
501
+ }
502
  </style>
503
+
504
+ <script>
505
+ document.addEventListener('DOMContentLoaded', function() {
506
+ // Add animation to cards on page load
507
+ const cards = document.querySelectorAll('.application-card');
508
+ cards.forEach((card, index) => {
509
+ setTimeout(() => {
510
+ card.style.opacity = '0';
511
+ card.style.transform = 'translateY(20px)';
512
+ card.style.animation = 'fadeInUp 0.5s ease forwards';
513
+ }, index * 100);
514
+ });
515
+
516
+ // Filter functionality (if needed in future)
517
+ const statusBadges = document.querySelectorAll('.card-status-badge');
518
+ statusBadges.forEach(badge => {
519
+ badge.addEventListener('click', function() {
520
+ const status = this.textContent.trim();
521
+ // Add filter logic here if needed
522
+ });
523
+ });
524
+ });
525
+
526
+ // Animation keyframes
527
+ const style = document.createElement('style');
528
+ style.textContent = `
529
+ @keyframes fadeInUp {
530
+ to {
531
+ opacity: 1;
532
+ transform: translateY(0);
533
+ }
534
+ }
535
+ `;
536
+ document.head.appendChild(style);
537
+ </script>
538
+ {% endblock %}