GuglielmoTor commited on
Commit
9ce1f5d
·
verified ·
1 Parent(s): 64b4cd4

Update ui/okr_ui_generator.py

Browse files
Files changed (1) hide show
  1. ui/okr_ui_generator.py +182 -92
ui/okr_ui_generator.py CHANGED
@@ -8,62 +8,151 @@ logger = logging.getLogger(__name__)
8
  def create_enhanced_okr_tab():
9
  """
10
  Creates a modern, visually appealing OKR tab with improved layout and styling.
11
- Removes the checkbox selector for a cleaner, always-visible design.
 
12
 
13
  Returns:
14
  gr.HTML: The Gradio HTML component that will display the formatted OKRs.
15
  """
16
 
17
- # Custom CSS for modern OKR styling
18
  okr_custom_css = """
19
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  /* Overall Container */
21
  .okr-container {
22
- font-family: 'Inter', sans-serif; /* Using Inter font */
23
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
24
  min-height: 100vh;
25
  padding: 2rem;
26
- margin: -1rem; /* Adjust margin to fill the space */
27
- box-sizing: border-box; /* Ensure padding is included in width/height */
28
- overflow-y: auto; /* Enable scrolling if content overflows */
29
  }
30
 
31
  /* Header Section */
32
  .okr-header {
33
  text-align: center;
34
  margin-bottom: 3rem;
35
- color: white; /* Keep general header text white */
36
  }
37
 
38
  .okr-title {
39
  font-size: 2.5rem;
40
  font-weight: 700;
41
  margin-bottom: 0.5rem;
42
- /* Removed background-clip and text-fill-color from here */
43
- text-shadow: 0 2px 4px rgba(0,0,0,0.1);
44
- display: flex; /* Use flexbox to align emoji and text */
45
  justify-content: center;
46
  align-items: center;
47
- gap: 0.75rem; /* Space between emoji and text */
48
  }
49
 
50
- /* New class for the text content within the title */
51
  .okr-title-content {
52
  background: linear-gradient(45deg, #ffffff, #e0e7ff);
53
  -webkit-background-clip: text;
54
  -webkit-text-fill-color: transparent;
55
  background-clip: text;
56
  }
 
 
 
 
 
 
 
57
 
58
- /* Ensure emoji maintains its default color */
59
  .okr-title-emoji {
60
- font-size: 2.5rem; /* Match title font size for consistent sizing */
61
- color: initial; /* Reset color to browser default for emoji */
62
- -webkit-text-fill-color: initial; /* Reset text fill for emoji */
63
- background-clip: initial; /* Reset background clip for emoji */
64
  }
65
 
66
-
67
  .okr-subtitle {
68
  font-size: 1.2rem;
69
  opacity: 0.9;
@@ -81,28 +170,28 @@ def create_enhanced_okr_tab():
81
  }
82
 
83
  .stat-card {
84
- background: rgba(255, 255, 255, 0.15);
85
  backdrop-filter: blur(10px);
86
- border: 1px solid rgba(255, 255, 255, 0.2);
87
  border-radius: 16px;
88
  padding: 1.5rem;
89
  text-align: center;
90
- color: white;
91
  min-width: 140px;
92
  transition: all 0.3s ease;
93
  }
94
 
95
  .stat-card:hover {
96
  transform: translateY(-2px);
97
- background: rgba(255, 255, 255, 0.2);
98
- box-shadow: 0 8px 32px rgba(0,0,0,0.1);
99
  }
100
 
101
  .stat-number {
102
  font-size: 2rem;
103
  font-weight: 700;
104
  margin-bottom: 0.25rem;
105
- color: #fbbf24; /* Amber color for numbers */
106
  }
107
 
108
  .stat-label {
@@ -114,49 +203,51 @@ def create_enhanced_okr_tab():
114
 
115
  /* Main Content Area */
116
  .okr-content {
117
- background: white;
118
  border-radius: 24px;
119
  padding: 0;
120
- box-shadow: 0 20px 40px rgba(0,0,0,0.1);
121
- overflow: hidden; /* Ensures rounded corners are applied to children */
122
  margin-top: 2rem;
123
  }
124
 
125
  /* Objective Card */
126
  .okr-objective {
127
- background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
128
- border-left: 6px solid #3b82f6; /* Blue border for objectives */
129
- margin: 2rem; /* Add margin within the white content box */
130
  border-radius: 16px;
131
  overflow: hidden;
132
  box-shadow: 0 4px 16px rgba(0,0,0,0.05);
133
  transition: all 0.3s ease;
134
  }
 
 
 
 
135
 
136
  .okr-objective:hover {
137
  transform: translateY(-2px);
138
  box-shadow: 0 8px 24px rgba(0,0,0,0.1);
139
  }
 
 
 
 
140
 
141
- /* Objective Header */
142
  .objective-header {
143
  padding: 2rem;
144
- background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%);
145
- color: white;
146
  position: relative;
147
- overflow: hidden;
148
  }
149
-
150
- .objective-header::before {
151
- content: '';
152
- position: absolute;
153
- top: 0;
154
- left: 0;
155
- right: 0;
156
- bottom: 0;
157
- background: url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M20 20c0 4.4-3.6 8-8 8s-8-3.6-8-8 3.6-8 8-8 8 3.6 8 8zm0-20c0 4.4-3.6 8-8 8s-8-3.6-8-8 3.6-8 8-8 8 3.6 8 8z'/%3E%3C/g%3E%3C/svg%3E");
158
- pointer-events: none;
159
  }
 
 
160
 
161
  .objective-title {
162
  font-size: 1.5rem;
@@ -164,6 +255,7 @@ def create_enhanced_okr_tab():
164
  margin-bottom: 0.75rem;
165
  position: relative;
166
  z-index: 1;
 
167
  }
168
 
169
  .objective-meta {
@@ -180,7 +272,7 @@ def create_enhanced_okr_tab():
180
  align-items: center;
181
  gap: 0.5rem;
182
  font-size: 0.9rem;
183
- opacity: 0.9;
184
  }
185
 
186
  .meta-icon {
@@ -191,13 +283,13 @@ def create_enhanced_okr_tab():
191
 
192
  /* Key Results Container */
193
  .key-results-container {
194
- padding: 2rem; /* Consistent padding for content within objectives */
195
  }
196
 
197
  /* Key Result Card */
198
  .key-result {
199
- background: white;
200
- border: 2px solid #e5e7eb;
201
  border-radius: 12px;
202
  margin: 1.5rem 0;
203
  overflow: hidden;
@@ -205,20 +297,24 @@ def create_enhanced_okr_tab():
205
  }
206
 
207
  .key-result:hover {
208
- border-color: #3b82f6;
209
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1);
210
  }
 
 
 
 
211
 
212
  .kr-header {
213
- background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
214
  padding: 1.5rem;
215
- border-bottom: 1px solid #e5e7eb;
216
  }
217
 
218
  .kr-title {
219
  font-size: 1.2rem;
220
  font-weight: 600;
221
- color: #1e293b;
222
  margin-bottom: 0.75rem;
223
  }
224
 
@@ -230,13 +326,13 @@ def create_enhanced_okr_tab():
230
  }
231
 
232
  .kr-metric {
233
- background: rgba(59, 130, 246, 0.1);
234
- color: #1e40af;
235
  padding: 0.5rem 1rem;
236
  border-radius: 8px;
237
  font-size: 0.85rem;
238
  font-weight: 500;
239
- border: 1px solid rgba(59, 130, 246, 0.2);
240
  }
241
 
242
  /* Tasks Section */
@@ -247,7 +343,7 @@ def create_enhanced_okr_tab():
247
  .tasks-title {
248
  font-size: 1rem;
249
  font-weight: 600;
250
- color: #374151;
251
  margin-bottom: 1rem;
252
  display: flex;
253
  align-items: center;
@@ -255,8 +351,8 @@ def create_enhanced_okr_tab():
255
  }
256
 
257
  .task-item {
258
- background: #f9fafb;
259
- border: 1px solid #e5e7eb;
260
  border-radius: 8px;
261
  padding: 1.25rem;
262
  margin: 1rem 0;
@@ -264,8 +360,8 @@ def create_enhanced_okr_tab():
264
  }
265
 
266
  .task-item:hover {
267
- background: #f3f4f6;
268
- border-color: #d1d5db;
269
  }
270
 
271
  .task-header {
@@ -278,7 +374,7 @@ def create_enhanced_okr_tab():
278
 
279
  .task-title {
280
  font-weight: 600;
281
- color: #111827;
282
  flex: 1;
283
  line-height: 1.4;
284
  }
@@ -295,21 +391,21 @@ def create_enhanced_okr_tab():
295
 
296
  /* Priority Colors */
297
  .priority-high {
298
- background: #fef2f2;
299
- color: #dc2626;
300
- border: 1px solid #fca5a5;
301
  }
302
 
303
  .priority-medium {
304
- background: #fffbeb;
305
- color: #d97706;
306
- border: 1px solid #fcd34d;
307
  }
308
 
309
  .priority-low {
310
- background: #f0fdf4;
311
- color: #16a34a;
312
- border: 1px solid #86efac;
313
  }
314
 
315
  /* Task Details Grid */
@@ -325,12 +421,12 @@ def create_enhanced_okr_tab():
325
  align-items: center;
326
  gap: 0.5rem;
327
  font-size: 0.875rem;
328
- color: #6b7280;
329
  }
330
 
331
  .task-detail-label {
332
  font-weight: 500;
333
- color: #374151;
334
  min-width: 80px;
335
  }
336
 
@@ -338,19 +434,19 @@ def create_enhanced_okr_tab():
338
  .task-description {
339
  margin-top: 1rem;
340
  padding: 1rem;
341
- background: white;
342
  border-radius: 6px;
343
- border-left: 3px solid #3b82f6;
344
  font-size: 0.9rem;
345
  line-height: 1.5;
346
- color: #4b5563;
347
  }
348
 
349
  /* Empty State */
350
  .empty-state {
351
  text-align: center;
352
  padding: 4rem 2rem;
353
- color: #6b7280;
354
  }
355
 
356
  .empty-state-icon {
@@ -362,7 +458,7 @@ def create_enhanced_okr_tab():
362
  font-size: 1.5rem;
363
  font-weight: 600;
364
  margin-bottom: 0.5rem;
365
- color: #374151;
366
  }
367
 
368
  /* Loading Spinner */
@@ -370,9 +466,9 @@ def create_enhanced_okr_tab():
370
  display: inline-block;
371
  width: 20px;
372
  height: 20px;
373
- border: 3px solid #f3f4f6;
374
  border-radius: 50%;
375
- border-top-color: #3b82f6;
376
  animation: spin 1s ease-in-out infinite;
377
  }
378
 
@@ -385,29 +481,23 @@ def create_enhanced_okr_tab():
385
  .okr-container {
386
  padding: 1rem;
387
  }
388
-
389
  .okr-title {
390
  font-size: 2rem;
391
  }
392
-
393
  .okr-stats-bar {
394
  gap: 1rem;
395
  }
396
-
397
  .stat-card {
398
  min-width: 120px;
399
  padding: 1rem;
400
  }
401
-
402
  .objective-meta {
403
  flex-direction: column;
404
  gap: 1rem;
405
  }
406
-
407
  .task-details {
408
  grid-template-columns: 1fr;
409
  }
410
-
411
  .task-header {
412
  flex-direction: column;
413
  align-items: flex-start;
@@ -699,13 +789,13 @@ def format_okrs_for_enhanced_display(reconstruction_cache: dict) -> str:
699
  html_parts.append('</div>') # Close tasks-section
700
  else:
701
  html_parts.append("""
702
- <div class="tasks-section">
703
- <div class="empty-state-small">
704
- <div class="empty-state-icon">📄</div>
705
- <div class="empty-state-description">No tasks defined for this Key Result.</div>
 
706
  </div>
707
- </div>
708
- """)
709
 
710
  html_parts.append('</div>') # Close key-result
711
 
 
8
  def create_enhanced_okr_tab():
9
  """
10
  Creates a modern, visually appealing OKR tab with improved layout and styling.
11
+ This version includes full support for Gradio's dark mode and a redesigned,
12
+ more readable objective header.
13
 
14
  Returns:
15
  gr.HTML: The Gradio HTML component that will display the formatted OKRs.
16
  """
17
 
18
+ # Custom CSS for modern OKR styling with Dark Mode support
19
  okr_custom_css = """
20
  <style>
21
+ /* ----------------------------------------- */
22
+ /* --- THEME & COLOR VARIABLES (NEW) --- */
23
+ /* ----------------------------------------- */
24
+ :root {
25
+ --okr-bg-start: #667eea;
26
+ --okr-bg-end: #764ba2;
27
+ --header-text-color: white;
28
+ --header-text-shadow: rgba(0,0,0,0.1);
29
+ --stat-card-bg: rgba(255, 255, 255, 0.15);
30
+ --stat-card-bg-hover: rgba(255, 255, 255, 0.2);
31
+ --stat-card-border: rgba(255, 255, 255, 0.2);
32
+ --stat-number-color: #fbbf24;
33
+ --content-bg: white;
34
+ --content-shadow: rgba(0,0,0,0.1);
35
+ --objective-card-bg: #f8fafc;
36
+ --objective-card-border: #3b82f6;
37
+ --objective-header-bg: transparent; /* Cleaner header background */
38
+ --objective-title-color: #1e40af; /* Make title the colored element */
39
+ --objective-meta-text-color: #475569;
40
+ --key-result-bg: white;
41
+ --key-result-border: #e5e7eb;
42
+ --key-result-border-hover: #3b82f6;
43
+ --kr-header-bg: #f8fafc;
44
+ --kr-title-color: #1e293b;
45
+ --kr-metric-bg: rgba(59, 130, 246, 0.1);
46
+ --kr-metric-color: #1e40af;
47
+ --kr-metric-border: rgba(59, 130, 246, 0.2);
48
+ --task-item-bg: #f9fafb;
49
+ --task-item-bg-hover: #f3f4f6;
50
+ --task-item-border: #e5e7eb;
51
+ --task-item-border-hover: #d1d5db;
52
+ --task-title-color: #111827;
53
+ --task-detail-label-color: #374151;
54
+ --task-detail-text-color: #6b7280;
55
+ --task-description-bg: white;
56
+ --task-description-border: #3b82f6;
57
+ --task-description-color: #4b5563;
58
+ --priority-high-bg: #fef2f2;
59
+ --priority-high-color: #dc2626;
60
+ --priority-high-border: #fca5a5;
61
+ --priority-medium-bg: #fffbeb;
62
+ --priority-medium-color: #d97706;
63
+ --priority-medium-border: #fcd34d;
64
+ --priority-low-bg: #f0fdf4;
65
+ --priority-low-color: #16a34a;
66
+ --priority-low-border: #86efac;
67
+ }
68
+
69
+ html.dark {
70
+ --header-text-color: #e5e7eb;
71
+ --stat-card-bg: rgba(30, 41, 59, 0.5);
72
+ --stat-card-bg-hover: rgba(51, 65, 85, 0.7);
73
+ --stat-card-border: rgba(51, 65, 85, 0.8);
74
+ --content-bg: #1e293b; /* Dark background for content */
75
+ --content-shadow: rgba(0,0,0,0.4);
76
+ --objective-card-bg: #0f172a; /* Darker card background */
77
+ --objective-title-color: #60a5fa; /* Lighter blue for dark bg */
78
+ --objective-meta-text-color: #94a3b8;
79
+ --key-result-bg: #1e293b;
80
+ --key-result-border: #334155;
81
+ --key-result-border-hover: #3b82f6;
82
+ --kr-header-bg: #0f172a;
83
+ --kr-title-color: #e2e8f0;
84
+ --kr-metric-bg: rgba(59, 130, 246, 0.15);
85
+ --kr-metric-color: #93c5fd;
86
+ --kr-metric-border: rgba(59, 130, 246, 0.3);
87
+ --task-item-bg: #334155;
88
+ --task-item-bg-hover: #475569;
89
+ --task-item-border: #475569;
90
+ --task-item-border-hover: #52525b;
91
+ --task-title-color: #f1f5f9;
92
+ --task-detail-label-color: #cbd5e1;
93
+ --task-detail-text-color: #94a3b8;
94
+ --task-description-bg: #1e293b;
95
+ --task-description-border: #3b82f6;
96
+ --task-description-color: #cbd5e1;
97
+ --priority-high-bg: #450a0a;
98
+ --priority-high-color: #fca5a5;
99
+ --priority-high-border: #7f1d1d;
100
+ --priority-medium-bg: #422006;
101
+ --priority-medium-color: #fcd34d;
102
+ --priority-medium-border: #78350f;
103
+ --priority-low-bg: #062813;
104
+ --priority-low-color: #86efac;
105
+ --priority-low-border: #14532d;
106
+ }
107
+
108
  /* Overall Container */
109
  .okr-container {
110
+ font-family: 'Inter', sans-serif;
111
+ background: linear-gradient(135deg, var(--okr-bg-start) 0%, var(--okr-bg-end) 100%);
112
  min-height: 100vh;
113
  padding: 2rem;
114
+ margin: -1rem;
115
+ box-sizing: border-box;
116
+ overflow-y: auto;
117
  }
118
 
119
  /* Header Section */
120
  .okr-header {
121
  text-align: center;
122
  margin-bottom: 3rem;
123
+ color: var(--header-text-color);
124
  }
125
 
126
  .okr-title {
127
  font-size: 2.5rem;
128
  font-weight: 700;
129
  margin-bottom: 0.5rem;
130
+ text-shadow: 0 2px 4px var(--header-text-shadow);
131
+ display: flex;
 
132
  justify-content: center;
133
  align-items: center;
134
+ gap: 0.75rem;
135
  }
136
 
 
137
  .okr-title-content {
138
  background: linear-gradient(45deg, #ffffff, #e0e7ff);
139
  -webkit-background-clip: text;
140
  -webkit-text-fill-color: transparent;
141
  background-clip: text;
142
  }
143
+
144
+ html.dark .okr-title-content {
145
+ background: linear-gradient(45deg, #e5e7eb, #9ca3af);
146
+ -webkit-background-clip: text;
147
+ -webkit-text-fill-color: transparent;
148
+ background-clip: text;
149
+ }
150
 
 
151
  .okr-title-emoji {
152
+ font-size: 2.5rem;
153
+ -webkit-text-fill-color: initial;
 
 
154
  }
155
 
 
156
  .okr-subtitle {
157
  font-size: 1.2rem;
158
  opacity: 0.9;
 
170
  }
171
 
172
  .stat-card {
173
+ background: var(--stat-card-bg);
174
  backdrop-filter: blur(10px);
175
+ border: 1px solid var(--stat-card-border);
176
  border-radius: 16px;
177
  padding: 1.5rem;
178
  text-align: center;
179
+ color: var(--header-text-color);
180
  min-width: 140px;
181
  transition: all 0.3s ease;
182
  }
183
 
184
  .stat-card:hover {
185
  transform: translateY(-2px);
186
+ background: var(--stat-card-bg-hover);
187
+ box-shadow: 0 8px 32px var(--content-shadow);
188
  }
189
 
190
  .stat-number {
191
  font-size: 2rem;
192
  font-weight: 700;
193
  margin-bottom: 0.25rem;
194
+ color: var(--stat-number-color);
195
  }
196
 
197
  .stat-label {
 
203
 
204
  /* Main Content Area */
205
  .okr-content {
206
+ background: var(--content-bg);
207
  border-radius: 24px;
208
  padding: 0;
209
+ box-shadow: 0 20px 40px var(--content-shadow);
210
+ overflow: hidden;
211
  margin-top: 2rem;
212
  }
213
 
214
  /* Objective Card */
215
  .okr-objective {
216
+ background: var(--objective-card-bg);
217
+ border-left: 6px solid var(--objective-card-border);
218
+ margin: 2rem;
219
  border-radius: 16px;
220
  overflow: hidden;
221
  box-shadow: 0 4px 16px rgba(0,0,0,0.05);
222
  transition: all 0.3s ease;
223
  }
224
+
225
+ html.dark .okr-objective {
226
+ box-shadow: 0 4px 16px rgba(0,0,0,0.2);
227
+ }
228
 
229
  .okr-objective:hover {
230
  transform: translateY(-2px);
231
  box-shadow: 0 8px 24px rgba(0,0,0,0.1);
232
  }
233
+
234
+ html.dark .okr-objective:hover {
235
+ box-shadow: 0 8px 24px rgba(0,0,0,0.3);
236
+ }
237
 
238
+ /* --- Objective Header (REDESIGNED) --- */
239
  .objective-header {
240
  padding: 2rem;
241
+ background: var(--objective-header-bg);
242
+ border-bottom: 1px solid #e5e7eb; /* Subtle separator */
243
  position: relative;
 
244
  }
245
+
246
+ html.dark .objective-header {
247
+ border-bottom-color: #334155;
 
 
 
 
 
 
 
248
  }
249
+
250
+ /* REMOVED distracting ::before dot pattern */
251
 
252
  .objective-title {
253
  font-size: 1.5rem;
 
255
  margin-bottom: 0.75rem;
256
  position: relative;
257
  z-index: 1;
258
+ color: var(--objective-title-color); /* Use variable */
259
  }
260
 
261
  .objective-meta {
 
272
  align-items: center;
273
  gap: 0.5rem;
274
  font-size: 0.9rem;
275
+ color: var(--objective-meta-text-color);
276
  }
277
 
278
  .meta-icon {
 
283
 
284
  /* Key Results Container */
285
  .key-results-container {
286
+ padding: 2rem;
287
  }
288
 
289
  /* Key Result Card */
290
  .key-result {
291
+ background: var(--key-result-bg);
292
+ border: 2px solid var(--key-result-border);
293
  border-radius: 12px;
294
  margin: 1.5rem 0;
295
  overflow: hidden;
 
297
  }
298
 
299
  .key-result:hover {
300
+ border-color: var(--key-result-border-hover);
301
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1);
302
  }
303
+
304
+ html.dark .key-result:hover {
305
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.2);
306
+ }
307
 
308
  .kr-header {
309
+ background: var(--kr-header-bg);
310
  padding: 1.5rem;
311
+ border-bottom: 1px solid var(--key-result-border);
312
  }
313
 
314
  .kr-title {
315
  font-size: 1.2rem;
316
  font-weight: 600;
317
+ color: var(--kr-title-color);
318
  margin-bottom: 0.75rem;
319
  }
320
 
 
326
  }
327
 
328
  .kr-metric {
329
+ background: var(--kr-metric-bg);
330
+ color: var(--kr-metric-color);
331
  padding: 0.5rem 1rem;
332
  border-radius: 8px;
333
  font-size: 0.85rem;
334
  font-weight: 500;
335
+ border: 1px solid var(--kr-metric-border);
336
  }
337
 
338
  /* Tasks Section */
 
343
  .tasks-title {
344
  font-size: 1rem;
345
  font-weight: 600;
346
+ color: var(--task-detail-label-color);
347
  margin-bottom: 1rem;
348
  display: flex;
349
  align-items: center;
 
351
  }
352
 
353
  .task-item {
354
+ background: var(--task-item-bg);
355
+ border: 1px solid var(--task-item-border);
356
  border-radius: 8px;
357
  padding: 1.25rem;
358
  margin: 1rem 0;
 
360
  }
361
 
362
  .task-item:hover {
363
+ background: var(--task-item-bg-hover);
364
+ border-color: var(--task-item-border-hover);
365
  }
366
 
367
  .task-header {
 
374
 
375
  .task-title {
376
  font-weight: 600;
377
+ color: var(--task-title-color);
378
  flex: 1;
379
  line-height: 1.4;
380
  }
 
391
 
392
  /* Priority Colors */
393
  .priority-high {
394
+ background: var(--priority-high-bg);
395
+ color: var(--priority-high-color);
396
+ border: 1px solid var(--priority-high-border);
397
  }
398
 
399
  .priority-medium {
400
+ background: var(--priority-medium-bg);
401
+ color: var(--priority-medium-color);
402
+ border: 1px solid var(--priority-medium-border);
403
  }
404
 
405
  .priority-low {
406
+ background: var(--priority-low-bg);
407
+ color: var(--priority-low-color);
408
+ border: 1px solid var(--priority-low-border);
409
  }
410
 
411
  /* Task Details Grid */
 
421
  align-items: center;
422
  gap: 0.5rem;
423
  font-size: 0.875rem;
424
+ color: var(--task-detail-text-color);
425
  }
426
 
427
  .task-detail-label {
428
  font-weight: 500;
429
+ color: var(--task-detail-label-color);
430
  min-width: 80px;
431
  }
432
 
 
434
  .task-description {
435
  margin-top: 1rem;
436
  padding: 1rem;
437
+ background: var(--task-description-bg);
438
  border-radius: 6px;
439
+ border-left: 3px solid var(--task-description-border);
440
  font-size: 0.9rem;
441
  line-height: 1.5;
442
+ color: var(--task-description-color);
443
  }
444
 
445
  /* Empty State */
446
  .empty-state {
447
  text-align: center;
448
  padding: 4rem 2rem;
449
+ color: var(--task-detail-text-color);
450
  }
451
 
452
  .empty-state-icon {
 
458
  font-size: 1.5rem;
459
  font-weight: 600;
460
  margin-bottom: 0.5rem;
461
+ color: var(--task-title-color);
462
  }
463
 
464
  /* Loading Spinner */
 
466
  display: inline-block;
467
  width: 20px;
468
  height: 20px;
469
+ border: 3px solid var(--task-item-bg-hover);
470
  border-radius: 50%;
471
+ border-top-color: var(--objective-card-border);
472
  animation: spin 1s ease-in-out infinite;
473
  }
474
 
 
481
  .okr-container {
482
  padding: 1rem;
483
  }
 
484
  .okr-title {
485
  font-size: 2rem;
486
  }
 
487
  .okr-stats-bar {
488
  gap: 1rem;
489
  }
 
490
  .stat-card {
491
  min-width: 120px;
492
  padding: 1rem;
493
  }
 
494
  .objective-meta {
495
  flex-direction: column;
496
  gap: 1rem;
497
  }
 
498
  .task-details {
499
  grid-template-columns: 1fr;
500
  }
 
501
  .task-header {
502
  flex-direction: column;
503
  align-items: flex-start;
 
789
  html_parts.append('</div>') # Close tasks-section
790
  else:
791
  html_parts.append("""
792
+ <div class="tasks-section">
793
+ <div class="empty-state-small">
794
+ <div class="empty-state-icon">📄</div>
795
+ <div class="empty-state-description">No tasks defined for this Key Result.</div>
796
+ </div>
797
  </div>
798
+ """)
 
799
 
800
  html_parts.append('</div>') # Close key-result
801