trackops 2.0.4 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +660 -575
  3. package/bin/trackops.js +127 -106
  4. package/lib/cli-format.js +118 -0
  5. package/lib/config.js +352 -326
  6. package/lib/control.js +408 -246
  7. package/lib/env.js +234 -222
  8. package/lib/i18n.js +5 -4
  9. package/lib/init.js +390 -282
  10. package/lib/locale.js +41 -41
  11. package/lib/opera-bootstrap.js +1066 -880
  12. package/lib/opera.js +615 -444
  13. package/lib/preferences.js +74 -74
  14. package/lib/registry.js +214 -214
  15. package/lib/release.js +56 -56
  16. package/lib/runtime-state.js +144 -144
  17. package/lib/skills.js +114 -89
  18. package/lib/workspace.js +259 -248
  19. package/locales/en.json +311 -167
  20. package/locales/es.json +314 -170
  21. package/package.json +61 -58
  22. package/scripts/postinstall-locale.js +21 -21
  23. package/scripts/skills-marketplace-smoke.js +124 -124
  24. package/scripts/smoke-tests.js +563 -517
  25. package/scripts/sync-skill-version.js +21 -21
  26. package/scripts/validate-skill.js +103 -103
  27. package/skills/trackops/SKILL.md +126 -122
  28. package/skills/trackops/agents/openai.yaml +7 -7
  29. package/skills/trackops/locales/en/SKILL.md +126 -122
  30. package/skills/trackops/locales/en/references/activation.md +94 -90
  31. package/skills/trackops/locales/en/references/troubleshooting.md +73 -67
  32. package/skills/trackops/locales/en/references/workflow.md +55 -32
  33. package/skills/trackops/references/activation.md +94 -90
  34. package/skills/trackops/references/troubleshooting.md +73 -67
  35. package/skills/trackops/references/workflow.md +55 -32
  36. package/skills/trackops/skill.json +29 -29
  37. package/templates/hooks/post-checkout +2 -2
  38. package/templates/hooks/post-commit +2 -2
  39. package/templates/hooks/post-merge +2 -2
  40. package/templates/opera/agent.md +28 -27
  41. package/templates/opera/architecture/dependency-graph.md +24 -24
  42. package/templates/opera/architecture/runtime-automation.md +24 -24
  43. package/templates/opera/architecture/runtime-operations.md +34 -34
  44. package/templates/opera/en/agent.md +22 -21
  45. package/templates/opera/en/architecture/dependency-graph.md +24 -24
  46. package/templates/opera/en/architecture/runtime-automation.md +24 -24
  47. package/templates/opera/en/architecture/runtime-operations.md +34 -34
  48. package/templates/opera/en/reviews/delivery-audit.md +18 -18
  49. package/templates/opera/en/reviews/integration-audit.md +18 -18
  50. package/templates/opera/en/router.md +24 -19
  51. package/templates/opera/references/autonomy-and-recovery.md +117 -117
  52. package/templates/opera/references/opera-cycle.md +193 -193
  53. package/templates/opera/registry.md +28 -28
  54. package/templates/opera/reviews/delivery-audit.md +18 -18
  55. package/templates/opera/reviews/integration-audit.md +18 -18
  56. package/templates/opera/router.md +54 -49
  57. package/templates/skills/changelog-updater/SKILL.md +69 -69
  58. package/templates/skills/commiter/SKILL.md +99 -99
  59. package/templates/skills/opera-contract-auditor/SKILL.md +38 -38
  60. package/templates/skills/opera-contract-auditor/locales/en/SKILL.md +38 -38
  61. package/templates/skills/opera-policy-guard/SKILL.md +26 -26
  62. package/templates/skills/opera-policy-guard/locales/en/SKILL.md +26 -26
  63. package/templates/skills/opera-skill/SKILL.md +279 -0
  64. package/templates/skills/opera-skill/locales/en/SKILL.md +279 -0
  65. package/templates/skills/opera-skill/locales/en/references/phase-dod.md +138 -0
  66. package/templates/skills/opera-skill/references/phase-dod.md +138 -0
  67. package/templates/skills/project-starter-skill/SKILL.md +150 -131
  68. package/templates/skills/project-starter-skill/locales/en/SKILL.md +143 -105
  69. package/templates/skills/project-starter-skill/references/opera-cycle.md +195 -193
  70. package/ui/css/base.css +284 -284
  71. package/ui/css/charts.css +425 -425
  72. package/ui/css/components.css +1107 -1107
  73. package/ui/css/onboarding.css +133 -133
  74. package/ui/css/terminal.css +125 -125
  75. package/ui/css/timeline.css +58 -58
  76. package/ui/css/tokens.css +284 -284
  77. package/ui/favicon.svg +5 -5
  78. package/ui/index.html +99 -99
  79. package/ui/js/charts.js +526 -526
  80. package/ui/js/console-logger.js +172 -172
  81. package/ui/js/filters.js +247 -247
  82. package/ui/js/icons.js +129 -129
  83. package/ui/js/keyboard.js +229 -229
  84. package/ui/js/router.js +142 -142
  85. package/ui/js/theme.js +100 -100
  86. package/ui/js/time-tracker.js +248 -248
  87. package/ui/js/views/dashboard.js +870 -870
  88. package/ui/js/views/flash.js +47 -47
  89. package/ui/js/views/projects.js +745 -745
  90. package/ui/js/views/scrum.js +476 -476
  91. package/ui/js/views/settings.js +331 -331
  92. package/ui/js/views/timeline.js +265 -265
@@ -1,1107 +1,1107 @@
1
- /* ═══════════════════════════════════════════════════════
2
- COMPONENTS — Botones, Cards, Badges, Forms
3
- ═══════════════════════════════════════════════════════ */
4
-
5
- /* ───────────────────────────────────
6
- BOTONES
7
- ─────────────────────────────────── */
8
- .btn {
9
- display: inline-flex;
10
- align-items: center;
11
- justify-content: center;
12
- gap: var(--space-2);
13
- font-weight: 600;
14
- font-size: var(--text-sm);
15
- border-radius: var(--radius-full);
16
- padding: 0.6rem 1.25rem;
17
- border: 1px solid transparent;
18
- transition:
19
- background var(--duration-base) var(--ease-out),
20
- box-shadow var(--duration-base) var(--ease-out),
21
- transform var(--duration-fast) var(--ease-out),
22
- border-color var(--duration-base) var(--ease-out);
23
- letter-spacing: 0.01em;
24
- cursor: pointer;
25
- white-space: nowrap;
26
- min-height: 36px;
27
- line-height: 1;
28
- }
29
-
30
- .btn:active { transform: translateY(1px); }
31
-
32
- /* Primary */
33
- .btn-primary {
34
- background: linear-gradient(135deg, #3B82F6 0%, #60A5FA 100%);
35
- color: white;
36
- box-shadow: 0 4px 12px rgba(96, 165, 250, 0.3);
37
- }
38
- .btn-primary:hover {
39
- transform: translateY(-1px);
40
- box-shadow: 0 12px 32px rgba(96, 165, 250, 0.35);
41
- }
42
-
43
- /* Ghost */
44
- .btn-ghost {
45
- background: var(--glass-bg-subtle);
46
- color: var(--text-secondary);
47
- border: 1px solid var(--glass-border);
48
- }
49
- .btn-ghost:hover {
50
- background: var(--glass-bg);
51
- color: var(--text-primary);
52
- border-color: var(--border-strong);
53
- }
54
-
55
- /* Danger */
56
- .btn-danger {
57
- background: var(--danger-light);
58
- color: var(--danger);
59
- border-color: rgba(239,68,68,0.2);
60
- }
61
- .btn-danger:hover {
62
- background: var(--danger);
63
- color: white;
64
- }
65
-
66
- /* Success */
67
- .btn-success {
68
- background: var(--success-light);
69
- color: var(--success);
70
- border-color: rgba(16,185,129,0.2);
71
- }
72
- .btn-success:hover {
73
- background: var(--success);
74
- color: white;
75
- }
76
-
77
- /* Icon button */
78
- .btn-icon {
79
- padding: var(--space-2);
80
- min-height: 36px;
81
- min-width: 36px;
82
- border-radius: var(--radius-md);
83
- }
84
-
85
- /* Small — min 44px touch target via padding (WCAG 2.2 AA) */
86
- .btn-sm {
87
- padding: 0.4rem 0.85rem;
88
- font-size: var(--text-xs);
89
- min-height: 32px;
90
- position: relative;
91
- }
92
- /* Invisible touch target expansion for small buttons */
93
- .btn-sm::after {
94
- content: '';
95
- position: absolute;
96
- inset: -6px;
97
- pointer-events: auto;
98
- }
99
-
100
- /* Chip / pill */
101
- .chip {
102
- display: inline-flex;
103
- align-items: center;
104
- gap: var(--space-1);
105
- padding: 0.25rem 0.75rem;
106
- font-size: var(--text-xs);
107
- font-weight: 600;
108
- border-radius: var(--radius-full);
109
- border: 1px solid var(--border);
110
- background: var(--surface-4);
111
- color: var(--text-secondary);
112
- cursor: pointer;
113
- transition:
114
- background var(--duration-fast) var(--ease-out),
115
- border-color var(--duration-fast) var(--ease-out),
116
- color var(--duration-fast) var(--ease-out);
117
- }
118
- .chip:hover {
119
- background: var(--surface-3);
120
- border-color: var(--border-strong);
121
- color: var(--text-primary);
122
- }
123
- .chip.is-active {
124
- background: var(--accent-light);
125
- border-color: var(--border-accent);
126
- color: var(--text-accent);
127
- }
128
-
129
- /* ───────────────────────────────────
130
- BADGES / TAGS
131
- ─────────────────────────────────── */
132
- .badge {
133
- display: inline-flex;
134
- align-items: center;
135
- gap: var(--space-1);
136
- padding: 0.2rem 0.6rem;
137
- font-size: var(--text-xs);
138
- font-weight: 700;
139
- border-radius: var(--radius-full);
140
- white-space: nowrap;
141
- letter-spacing: 0.04em;
142
- }
143
-
144
- .badge-accent { background: var(--accent-light); color: var(--accent); border: 1px solid rgba(96,165,250,0.2); }
145
- .badge-success { background: var(--success-light); color: var(--success); border: 1px solid rgba(16,185,129,0.2); }
146
- .badge-warning { background: var(--warning-light); color: var(--warning); border: 1px solid rgba(245,158,11,0.2); }
147
- .badge-danger { background: var(--danger-light); color: var(--danger); border: 1px solid rgba(239,68,68,0.2); }
148
- .badge-muted { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
149
- .badge-info { background: var(--info-light); color: var(--info); border: 1px solid rgba(59,130,246,0.2); }
150
-
151
- /* Priority badges */
152
- .badge-p0 { background: rgba(239,68,68,0.12); color: var(--p0); border: 1px solid rgba(239,68,68,0.2); }
153
- .badge-p1 { background: rgba(245,158,11,0.12); color: var(--p1); border: 1px solid rgba(245,158,11,0.2); }
154
- .badge-p2 { background: var(--accent-light); color: var(--accent); border: 1px solid rgba(99,102,241,0.2); }
155
- .badge-p3 { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
156
-
157
- /* Status badges */
158
- .status-pending { background: rgba(245,158,11,0.1); color: var(--warning); border: 1px solid rgba(245,158,11,0.15); }
159
- .status-in_progress { background: var(--info-light); color: var(--info); border: 1px solid rgba(59,130,246,0.2); }
160
- .status-in_review { background: var(--accent-light); color: var(--text-accent); border: 1px solid rgba(99,102,241,0.2); }
161
- .status-blocked { background: var(--danger-light); color: var(--danger); border: 1px solid rgba(239,68,68,0.2); }
162
- .status-completed { background: var(--success-light); color: var(--success); border: 1px solid rgba(16,185,129,0.2); }
163
- .status-cancelled { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
164
-
165
- /* ── Glass Card ── */
166
- .glass-card {
167
- background: var(--glass-bg);
168
- backdrop-filter: blur(var(--glass-blur));
169
- -webkit-backdrop-filter: blur(var(--glass-blur));
170
- border: 1px solid var(--glass-border);
171
- border-radius: var(--radius-xl);
172
- box-shadow: var(--glass-shadow), var(--glass-inner);
173
- }
174
- .glass-card:hover {
175
- background: var(--glass-bg-strong);
176
- border-color: var(--glass-border-hover);
177
- box-shadow: var(--shadow-md);
178
- }
179
-
180
- /* ───────────────────────────────────
181
- CARDS
182
- ─────────────────────────────────── */
183
- .card {
184
- background: var(--glass-bg);
185
- backdrop-filter: blur(var(--glass-blur));
186
- -webkit-backdrop-filter: blur(var(--glass-blur));
187
- border: 1px solid var(--glass-border);
188
- border-radius: var(--radius-lg);
189
- box-shadow: var(--glass-shadow), var(--glass-inner);
190
- transition:
191
- border-color var(--duration-base) var(--ease-out),
192
- box-shadow var(--duration-base) var(--ease-out),
193
- background var(--duration-base) var(--ease-out);
194
- }
195
- .card:hover { border-color: var(--glass-border-hover); box-shadow: var(--shadow-md); }
196
-
197
- /* Fallback for browsers without backdrop-filter */
198
- @supports not (backdrop-filter: blur(1px)) {
199
- .card, .glass-card, .kpi-card, .chart-card, .task-card, .project-card {
200
- background: var(--gray-800);
201
- }
202
- }
203
-
204
- .card-body { padding: var(--space-5); }
205
- .card-sm .card-body { padding: var(--space-4); }
206
- .card-lg .card-body { padding: var(--space-6); }
207
-
208
- /* KPI metric card */
209
- .kpi-card {
210
- background: var(--glass-bg);
211
- backdrop-filter: blur(var(--glass-blur));
212
- -webkit-backdrop-filter: blur(var(--glass-blur));
213
- border: 1px solid var(--glass-border);
214
- border-radius: var(--radius-lg);
215
- padding: var(--space-5);
216
- display: flex;
217
- flex-direction: column;
218
- gap: var(--space-2);
219
- position: relative;
220
- overflow: hidden;
221
- transition:
222
- border-color var(--duration-base) var(--ease-out),
223
- box-shadow var(--duration-base) var(--ease-out);
224
- }
225
- .kpi-card::before {
226
- content: '';
227
- position: absolute;
228
- top: 0; left: 0; right: 0;
229
- height: 2px;
230
- background: linear-gradient(90deg, var(--accent), transparent);
231
- opacity: 0;
232
- transition: opacity var(--duration-base) var(--ease-out);
233
- }
234
- .kpi-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
235
- .kpi-card:hover::before { opacity: 1; }
236
-
237
- .kpi-card.kpi-accent { border-top: 2px solid var(--accent); }
238
- .kpi-card.kpi-success { border-top: 2px solid var(--success); }
239
- .kpi-card.kpi-warning { border-top: 2px solid var(--warning); }
240
- .kpi-card.kpi-danger { border-top: 2px solid var(--danger); }
241
-
242
- .kpi-header {
243
- display: flex;
244
- align-items: center;
245
- justify-content: space-between;
246
- }
247
-
248
- .kpi-title {
249
- font-size: var(--text-xs);
250
- font-weight: 700;
251
- letter-spacing: 0.08em;
252
- text-transform: uppercase;
253
- color: var(--text-muted);
254
- }
255
-
256
- .kpi-icon {
257
- width: 32px;
258
- height: 32px;
259
- border-radius: var(--radius-sm);
260
- display: flex;
261
- align-items: center;
262
- justify-content: center;
263
- }
264
- .kpi-icon.accent { background: var(--accent-light); color: var(--accent); }
265
- .kpi-icon.success { background: var(--success-light); color: var(--success); }
266
- .kpi-icon.warning { background: var(--warning-light); color: var(--warning); }
267
- .kpi-icon.danger { background: var(--danger-light); color: var(--danger); }
268
-
269
- .kpi-value {
270
- font-family: var(--font-heading);
271
- font-size: var(--text-3xl);
272
- font-weight: 800;
273
- letter-spacing: -0.04em;
274
- line-height: 1;
275
- color: var(--text-primary);
276
- }
277
-
278
- .kpi-sub {
279
- font-size: var(--text-xs);
280
- color: var(--text-muted);
281
- }
282
-
283
- .kpi-trend {
284
- display: inline-flex;
285
- align-items: center;
286
- gap: var(--space-1);
287
- font-size: var(--text-xs);
288
- font-weight: 600;
289
- }
290
- .kpi-trend.up { color: var(--success); }
291
- .kpi-trend.down { color: var(--danger); }
292
-
293
- /* Task card (kanban) */
294
- .task-card {
295
- background: var(--glass-bg);
296
- backdrop-filter: blur(var(--glass-blur-sm));
297
- -webkit-backdrop-filter: blur(var(--glass-blur-sm));
298
- border: 1px solid var(--glass-border);
299
- border-radius: var(--radius-md);
300
- padding: var(--space-4);
301
- text-align: left;
302
- width: 100%;
303
- cursor: pointer;
304
- transition:
305
- border-color var(--duration-fast) var(--ease-out),
306
- box-shadow var(--duration-fast) var(--ease-out),
307
- background var(--duration-fast) var(--ease-out),
308
- transform var(--duration-fast) var(--ease-out);
309
- position: relative;
310
- }
311
- .task-card:hover {
312
- border-color: var(--glass-border-hover);
313
- box-shadow: var(--shadow-sm);
314
- transform: translateY(-1px);
315
- }
316
- .task-card.is-selected {
317
- border-color: var(--border-accent);
318
- background: linear-gradient(135deg, rgba(99,102,241,0.06) 0%, var(--surface-2) 100%);
319
- box-shadow: var(--shadow-accent);
320
- }
321
- .task-card[data-status="blocked"] {
322
- border-left: 3px solid var(--danger);
323
- }
324
- .task-card[data-status="completed"] {
325
- opacity: 0.65;
326
- }
327
- .task-card[data-status="completed"]:hover {
328
- opacity: 1;
329
- }
330
-
331
- .task-card-title {
332
- font-size: var(--text-sm);
333
- font-weight: 700;
334
- color: var(--text-primary);
335
- margin-bottom: var(--space-1);
336
- display: -webkit-box;
337
- -webkit-line-clamp: 2;
338
- -webkit-box-orient: vertical;
339
- overflow: hidden;
340
- }
341
- .task-card-id {
342
- font-family: var(--font-mono);
343
- font-size: 0.7rem;
344
- color: var(--text-muted);
345
- display: block;
346
- margin-bottom: var(--space-2);
347
- }
348
- .task-card-summary {
349
- font-size: var(--text-xs);
350
- color: var(--text-secondary);
351
- margin-bottom: var(--space-3);
352
- display: -webkit-box;
353
- -webkit-line-clamp: 2;
354
- -webkit-box-orient: vertical;
355
- overflow: hidden;
356
- min-height: 2.4em;
357
- }
358
- .task-card-meta {
359
- display: flex;
360
- flex-wrap: wrap;
361
- gap: var(--space-1);
362
- }
363
-
364
- /* Dragging state */
365
- .task-card[draggable]:hover { cursor: grab; }
366
- .task-card.is-dragging {
367
- opacity: 0.4;
368
- transform: rotate(2deg) scale(0.98);
369
- }
370
-
371
- /* ───────────────────────────────────
372
- FORMS
373
- ─────────────────────────────────── */
374
- .field { display: flex; flex-direction: column; gap: var(--space-2); }
375
-
376
- .field label {
377
- font-size: var(--text-xs);
378
- font-weight: 700;
379
- letter-spacing: 0.06em;
380
- text-transform: uppercase;
381
- color: var(--text-muted);
382
- }
383
-
384
- input[type="text"],
385
- input[type="search"],
386
- input[type="email"],
387
- textarea,
388
- select {
389
- width: 100%;
390
- padding: 0.65rem 0.85rem;
391
- font-size: var(--text-sm);
392
- font-family: var(--font-ui);
393
- color: var(--text-primary);
394
- background: var(--surface-1);
395
- border: 1px solid var(--border);
396
- border-radius: var(--radius-md);
397
- outline: none;
398
- transition:
399
- border-color var(--duration-fast) var(--ease-out),
400
- box-shadow var(--duration-fast) var(--ease-out),
401
- background var(--duration-fast) var(--ease-out);
402
- min-height: 40px;
403
- appearance: none;
404
- -webkit-appearance: none;
405
- }
406
-
407
- input:hover, textarea:hover, select:hover {
408
- border-color: var(--border-strong);
409
- }
410
-
411
- input:focus, textarea:focus, select:focus {
412
- border-color: var(--accent);
413
- box-shadow: 0 0 0 3px var(--accent-light);
414
- }
415
-
416
- textarea {
417
- resize: vertical;
418
- min-height: 80px;
419
- line-height: 1.5;
420
- }
421
-
422
- select {
423
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2394A3B8' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
424
- background-repeat: no-repeat;
425
- background-position: right 12px center;
426
- padding-right: 36px;
427
- }
428
-
429
- /* Checkbox custom */
430
- input[type="checkbox"] {
431
- width: 18px;
432
- height: 18px;
433
- min-height: 18px;
434
- min-width: 18px;
435
- border-radius: var(--radius-xs);
436
- border: 2px solid var(--border-strong);
437
- background: var(--surface-1);
438
- cursor: pointer;
439
- accent-color: var(--accent);
440
- }
441
-
442
- .checkbox-field {
443
- display: flex;
444
- align-items: center;
445
- gap: var(--space-3);
446
- }
447
- .checkbox-field label {
448
- font-size: var(--text-sm);
449
- font-weight: 500;
450
- letter-spacing: 0;
451
- text-transform: none;
452
- color: var(--text-secondary);
453
- cursor: pointer;
454
- }
455
-
456
- .field-row {
457
- display: grid;
458
- grid-template-columns: repeat(2, 1fr);
459
- gap: var(--space-3);
460
- }
461
-
462
- .form-actions {
463
- display: flex;
464
- gap: var(--space-3);
465
- padding-top: var(--space-2);
466
- }
467
-
468
- /* Search bar */
469
- .search-wrapper {
470
- position: relative;
471
- display: flex;
472
- align-items: center;
473
- }
474
- .search-wrapper .search-icon {
475
- position: absolute;
476
- left: var(--space-3);
477
- color: var(--text-muted);
478
- pointer-events: none;
479
- flex-shrink: 0;
480
- }
481
- .search-wrapper input {
482
- padding-left: 2.4rem;
483
- }
484
- .search-wrapper .search-kbd {
485
- position: absolute;
486
- right: var(--space-3);
487
- font-family: var(--font-mono);
488
- font-size: 0.65rem;
489
- color: var(--text-muted);
490
- background: var(--surface-3);
491
- padding: 2px 6px;
492
- border-radius: var(--radius-xs);
493
- border: 1px solid var(--border);
494
- pointer-events: none;
495
- }
496
-
497
- /* ───────────────────────────────────
498
- EMPTY STATE
499
- ─────────────────────────────────── */
500
- .empty-state {
501
- display: flex;
502
- flex-direction: column;
503
- align-items: center;
504
- justify-content: center;
505
- gap: var(--space-3);
506
- padding: var(--space-10) var(--space-6);
507
- text-align: center;
508
- color: var(--text-muted);
509
- font-size: var(--text-sm);
510
- border: 1px dashed var(--border);
511
- border-radius: var(--radius-lg);
512
- }
513
- .empty-state svg { opacity: 0.4; }
514
-
515
- /* ───────────────────────────────────
516
- INFO ROWS
517
- ─────────────────────────────────── */
518
- .info-row {
519
- padding: var(--space-3) var(--space-4);
520
- border-radius: var(--radius-md);
521
- background: var(--surface-4);
522
- border: 1px solid var(--border);
523
- display: flex;
524
- flex-direction: column;
525
- gap: var(--space-1);
526
- }
527
- .info-row .label-sm { margin-bottom: var(--space-1); }
528
- .info-row .value {
529
- font-size: var(--text-sm);
530
- font-weight: 500;
531
- font-family: var(--font-mono);
532
- color: var(--text-primary);
533
- overflow: hidden;
534
- text-overflow: ellipsis;
535
- white-space: nowrap;
536
- }
537
-
538
- /* ───────────────────────────────────
539
- SECTION HEADER (dentro de vistas)
540
- ─────────────────────────────────── */
541
- .section-header {
542
- display: flex;
543
- align-items: flex-start;
544
- justify-content: space-between;
545
- gap: var(--space-4);
546
- margin-bottom: var(--space-5);
547
- }
548
- .section-header-left { display: flex; flex-direction: column; gap: var(--space-1); }
549
- .section-header h2, .section-header h3 { margin: 0; }
550
- .section-subtitle { font-size: var(--text-sm); color: var(--text-secondary); }
551
-
552
- /* ───────────────────────────────────
553
- STACK LIST
554
- ─────────────────────────────────── */
555
- .stack { display: flex; flex-direction: column; gap: var(--space-2); }
556
- .stack-sm { gap: var(--space-2); }
557
- .stack-md { gap: var(--space-3); }
558
- .stack-lg { gap: var(--space-4); }
559
-
560
- /* ───────────────────────────────────
561
- GRID LAYOUTS COMUNES
562
- ─────────────────────────────────── */
563
- .grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
564
- .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }
565
- .grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
566
- .grid-split { display: grid; grid-template-columns: 1fr 380px; gap: var(--space-4); align-items: start; }
567
-
568
- @media (max-width: 1280px) {
569
- .grid-4 { grid-template-columns: repeat(2, 1fr); }
570
- .grid-3 { grid-template-columns: repeat(2, 1fr); }
571
- .grid-split { grid-template-columns: 1fr; }
572
- }
573
- @media (max-width: 768px) {
574
- .grid-4, .grid-3, .grid-2 { grid-template-columns: 1fr; }
575
- .field-row { grid-template-columns: 1fr; }
576
- }
577
-
578
- /* ───────────────────────────────────
579
- SPINNER DE CARGA
580
- ─────────────────────────────────── */
581
- .spinner {
582
- width: 20px; height: 20px;
583
- border: 2px solid var(--border-strong);
584
- border-top-color: var(--accent);
585
- border-radius: 50%;
586
- animation: spin 0.7s linear infinite;
587
- }
588
-
589
- /* ───────────────────────────────────
590
- THEME TOGGLE BUTTON
591
- ─────────────────────────────────── */
592
- .theme-toggle {
593
- position: relative;
594
- overflow: hidden;
595
- color: var(--text-secondary);
596
- }
597
- .theme-toggle:hover {
598
- color: var(--accent);
599
- background: var(--accent-light);
600
- border-color: var(--border-accent);
601
- }
602
- .theme-toggle svg {
603
- transition: transform var(--duration-slow) var(--ease-out), opacity var(--duration-base);
604
- }
605
- .theme-toggle:hover svg {
606
- transform: rotate(20deg) scale(1.1);
607
- }
608
-
609
- /* ───────────────────────────────────
610
- FILTER BAR
611
- ─────────────────────────────────── */
612
- .filter-bar {
613
- display: flex;
614
- flex-direction: column;
615
- gap: var(--space-3);
616
- margin-bottom: var(--space-4);
617
- }
618
- .filter-controls {
619
- display: flex;
620
- gap: var(--space-2);
621
- flex-wrap: wrap;
622
- align-items: center;
623
- }
624
- .filter-select {
625
- min-width: 130px;
626
- height: 36px;
627
- font-size: var(--text-sm);
628
- padding: 0 2rem 0 0.75rem;
629
- }
630
- .filter-search {
631
- flex: 1;
632
- min-width: 180px;
633
- }
634
- .filter-search-input {
635
- height: 36px;
636
- font-size: var(--text-sm);
637
- }
638
- .filter-active-bar {
639
- display: flex;
640
- align-items: center;
641
- gap: var(--space-2);
642
- flex-wrap: wrap;
643
- }
644
- .filter-clear-all {
645
- margin-left: auto;
646
- }
647
-
648
- /* ───────────────────────────────────
649
- KEYBOARD HELP PANEL
650
- ─────────────────────────────────── */
651
- .kb-help-group {
652
- margin-bottom: var(--space-4);
653
- }
654
- .kb-help-group:last-child {
655
- margin-bottom: 0;
656
- }
657
- .kb-help-group-title {
658
- font-size: var(--text-xs);
659
- font-weight: 700;
660
- letter-spacing: 0.1em;
661
- text-transform: uppercase;
662
- color: var(--text-muted);
663
- margin-bottom: var(--space-3);
664
- padding-bottom: var(--space-2);
665
- border-bottom: 1px solid var(--border);
666
- }
667
- .kb-help-items {
668
- display: flex;
669
- flex-direction: column;
670
- gap: var(--space-2);
671
- }
672
- .kb-help-item {
673
- display: flex;
674
- align-items: center;
675
- justify-content: space-between;
676
- gap: var(--space-4);
677
- padding: var(--space-1) 0;
678
- }
679
- .kb-help-key {
680
- display: inline-flex;
681
- align-items: center;
682
- gap: var(--space-1);
683
- padding: 0.2rem 0.5rem;
684
- background: var(--surface-3);
685
- border: 1px solid var(--border-strong);
686
- border-radius: var(--radius-xs);
687
- font-family: var(--font-mono);
688
- font-size: var(--text-xs);
689
- font-weight: 600;
690
- color: var(--text-primary);
691
- min-width: 24px;
692
- text-align: center;
693
- justify-content: center;
694
- white-space: nowrap;
695
- }
696
- .kb-help-label {
697
- font-size: var(--text-sm);
698
- color: var(--text-secondary);
699
- }
700
-
701
- /* ───────────────────────────────────
702
- SKELETON LOADER
703
- ─────────────────────────────────── */
704
- .skeleton {
705
- background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-4) 50%, var(--surface-3) 75%);
706
- background-size: 200% 100%;
707
- animation: skeleton-pulse 1.5s ease-in-out infinite;
708
- border-radius: var(--radius-sm);
709
- }
710
- .skeleton-text {
711
- height: 14px;
712
- margin-bottom: var(--space-2);
713
- }
714
- .skeleton-text:last-child {
715
- width: 60%;
716
- }
717
- .skeleton-card {
718
- height: 120px;
719
- border-radius: var(--radius-lg);
720
- }
721
- .skeleton-circle {
722
- border-radius: 50%;
723
- }
724
-
725
- @keyframes skeleton-pulse {
726
- 0% { background-position: 200% 0; }
727
- 100% { background-position: -200% 0; }
728
- }
729
-
730
- /* ───────────────────────────────────
731
- PROJECT CARDS (vista Projects)
732
- ─────────────────────────────────── */
733
- .projects-grid {
734
- display: grid;
735
- grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
736
- gap: var(--space-4);
737
- }
738
- @media (max-width: 960px) {
739
- .projects-grid { grid-template-columns: 1fr; }
740
- }
741
-
742
- .project-card {
743
- background: var(--glass-bg);
744
- backdrop-filter: blur(var(--glass-blur));
745
- -webkit-backdrop-filter: blur(var(--glass-blur));
746
- border: 1px solid var(--glass-border);
747
- border-radius: var(--radius-xl);
748
- padding: var(--space-5);
749
- display: flex;
750
- flex-direction: column;
751
- gap: var(--space-4);
752
- box-shadow: var(--glass-shadow), var(--glass-inner);
753
- transition:
754
- border-color var(--duration-fast) var(--ease-out),
755
- box-shadow var(--duration-base) var(--ease-out),
756
- transform var(--duration-base) var(--ease-out);
757
- }
758
- .project-card:hover {
759
- border-color: var(--glass-border-hover);
760
- box-shadow: var(--shadow-md);
761
- transform: translateY(-2px);
762
- }
763
- .project-card.is-current {
764
- border-color: var(--border-accent);
765
- background: linear-gradient(135deg, var(--surface-2), rgba(99,102,241,0.04));
766
- }
767
- .project-card.is-unavailable {
768
- opacity: 0.6;
769
- }
770
- .project-card.is-unavailable:hover {
771
- transform: none;
772
- box-shadow: none;
773
- }
774
-
775
- .project-card-header {
776
- display: flex;
777
- align-items: flex-start;
778
- justify-content: space-between;
779
- gap: var(--space-3);
780
- }
781
- .project-card-info { min-width: 0; flex: 1; }
782
- .project-card-name {
783
- font-size: var(--text-md);
784
- font-weight: 800;
785
- font-family: var(--font-heading);
786
- color: var(--text-primary);
787
- margin: 0;
788
- }
789
- .project-card-path {
790
- font-size: var(--text-xs);
791
- font-family: var(--font-mono);
792
- color: var(--text-muted);
793
- overflow: hidden;
794
- text-overflow: ellipsis;
795
- white-space: nowrap;
796
- margin-top: var(--space-1);
797
- }
798
- .project-card-badges {
799
- display: flex;
800
- gap: var(--space-2);
801
- flex-wrap: wrap;
802
- flex-shrink: 0;
803
- }
804
-
805
- .project-metrics-grid {
806
- display: grid;
807
- grid-template-columns: repeat(5, 1fr);
808
- gap: var(--space-2);
809
- }
810
- .project-metric {
811
- text-align: center;
812
- padding: var(--space-2);
813
- background: var(--surface-3);
814
- border-radius: var(--radius-md);
815
- border: 1px solid var(--border);
816
- }
817
- .project-metric-value {
818
- display: block;
819
- font-family: var(--font-heading);
820
- font-size: var(--text-lg);
821
- font-weight: 800;
822
- color: var(--text-primary);
823
- line-height: 1.2;
824
- }
825
- .project-metric-label {
826
- display: block;
827
- font-size: 0.65rem;
828
- font-weight: 600;
829
- color: var(--text-muted);
830
- text-transform: uppercase;
831
- letter-spacing: 0.08em;
832
- margin-top: var(--space-1);
833
- }
834
-
835
- .project-progress-track {
836
- width: 100%;
837
- height: 6px;
838
- background: var(--surface-3);
839
- border-radius: var(--radius-full);
840
- overflow: hidden;
841
- }
842
- .project-progress-fill {
843
- height: 100%;
844
- background: linear-gradient(90deg, var(--accent), var(--success));
845
- border-radius: var(--radius-full);
846
- transition: width var(--duration-slow) var(--ease-out);
847
- }
848
-
849
- .project-card-meta {
850
- display: flex;
851
- gap: var(--space-4);
852
- flex-wrap: wrap;
853
- }
854
-
855
- .project-card-actions {
856
- display: flex;
857
- gap: var(--space-2);
858
- flex-wrap: wrap;
859
- padding-top: var(--space-3);
860
- border-top: 1px solid var(--border);
861
- }
862
-
863
- .project-card-metrics.is-disabled {
864
- opacity: 0.4;
865
- pointer-events: none;
866
- }
867
-
868
- /* ── Project card name row + info tooltip ── */
869
- .project-card-name-row {
870
- display: flex;
871
- align-items: center;
872
- gap: var(--space-2);
873
- position: relative;
874
- }
875
- .project-info-btn {
876
- display: flex;
877
- align-items: center;
878
- justify-content: center;
879
- color: var(--text-muted);
880
- opacity: 0;
881
- transition: opacity var(--duration-fast), color var(--duration-fast);
882
- }
883
- .project-card:hover .project-info-btn { opacity: 1; }
884
- .project-info-btn:hover { color: var(--accent); }
885
- .project-info-tooltip {
886
- position: absolute;
887
- top: 100%;
888
- left: 0;
889
- z-index: var(--z-panel);
890
- min-width: 280px;
891
- background: var(--glass-bg-strong);
892
- backdrop-filter: blur(var(--glass-blur-lg));
893
- -webkit-backdrop-filter: blur(var(--glass-blur-lg));
894
- border: 1px solid var(--glass-border);
895
- border-radius: var(--radius-md);
896
- padding: var(--space-3);
897
- box-shadow: var(--shadow-lg);
898
- margin-top: var(--space-2);
899
- display: flex;
900
- flex-direction: column;
901
- gap: var(--space-1);
902
- }
903
- .project-info-tooltip.is-hidden { display: none; }
904
- .tooltip-row {
905
- display: flex;
906
- justify-content: space-between;
907
- gap: var(--space-3);
908
- font-size: var(--text-xs);
909
- }
910
- .tooltip-label {
911
- color: var(--text-muted);
912
- white-space: nowrap;
913
- }
914
- .tooltip-value {
915
- color: var(--text-secondary);
916
- font-family: var(--font-mono);
917
- text-align: right;
918
- overflow: hidden;
919
- text-overflow: ellipsis;
920
- white-space: nowrap;
921
- max-width: 200px;
922
- }
923
-
924
- /* ── Card indicators (health, deadline, priority) ── */
925
- .project-card-indicators {
926
- display: flex;
927
- align-items: center;
928
- gap: var(--space-3);
929
- flex-wrap: wrap;
930
- }
931
- .project-indicator {
932
- display: flex;
933
- align-items: center;
934
- gap: var(--space-1);
935
- font-size: var(--text-xs);
936
- color: var(--text-secondary);
937
- }
938
- .indicator-dot {
939
- width: 8px;
940
- height: 8px;
941
- border-radius: 50%;
942
- flex-shrink: 0;
943
- }
944
- .indicator-label {
945
- font-weight: 600;
946
- }
947
-
948
- /* ── Portfolio KPIs ── */
949
- .portfolio-kpi-grid {
950
- display: grid;
951
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
952
- gap: var(--space-3);
953
- margin-bottom: var(--space-4);
954
- }
955
- .portfolio-kpi {
956
- display: flex;
957
- align-items: center;
958
- gap: var(--space-3);
959
- padding: var(--space-4);
960
- }
961
- .portfolio-kpi-icon {
962
- display: flex;
963
- align-items: center;
964
- justify-content: center;
965
- color: var(--text-muted);
966
- flex-shrink: 0;
967
- }
968
- .portfolio-kpi-value {
969
- display: block;
970
- font-family: var(--font-heading);
971
- font-size: var(--text-2xl);
972
- font-weight: 800;
973
- line-height: 1;
974
- color: var(--text-primary);
975
- }
976
- .portfolio-kpi-label {
977
- display: block;
978
- font-size: var(--text-xs);
979
- color: var(--text-muted);
980
- margin-top: 2px;
981
- }
982
- .portfolio-kpi.kpi-danger { border-color: rgba(248,113,113,0.3); }
983
- .portfolio-kpi.kpi-warning { border-color: rgba(250,204,21,0.3); }
984
-
985
- /* ── Portfolio analytics ── */
986
- .portfolio-analytics {
987
- display: grid;
988
- grid-template-columns: 1fr 1fr 1fr;
989
- gap: var(--space-4);
990
- margin-bottom: var(--space-5);
991
- }
992
- @media (max-width: 1100px) {
993
- .portfolio-analytics { grid-template-columns: 1fr; }
994
- }
995
- .portfolio-chart, .portfolio-attention {
996
- padding: var(--space-4);
997
- }
998
- .portfolio-attention {
999
- max-height: 260px;
1000
- overflow-y: auto;
1001
- }
1002
- .attention-item {
1003
- display: flex;
1004
- align-items: center;
1005
- gap: var(--space-2);
1006
- padding: var(--space-2) 0;
1007
- border-bottom: 1px solid var(--border);
1008
- }
1009
- .attention-item:last-child { border-bottom: none; }
1010
- .attention-dot {
1011
- width: 6px;
1012
- height: 6px;
1013
- border-radius: 50%;
1014
- flex-shrink: 0;
1015
- }
1016
-
1017
- /* ── Donut legend ── */
1018
- .donut-legend {
1019
- display: flex;
1020
- flex-direction: column;
1021
- gap: var(--space-1);
1022
- }
1023
- .donut-legend-item {
1024
- display: flex;
1025
- align-items: center;
1026
- gap: var(--space-2);
1027
- font-size: var(--text-xs);
1028
- color: var(--text-secondary);
1029
- }
1030
- .donut-legend-dot {
1031
- width: 8px;
1032
- height: 8px;
1033
- border-radius: 50%;
1034
- flex-shrink: 0;
1035
- }
1036
-
1037
- /* Section header (reusable en views) */
1038
- .section-header {
1039
- display: flex;
1040
- align-items: flex-start;
1041
- justify-content: space-between;
1042
- gap: var(--space-4);
1043
- margin-bottom: var(--space-5);
1044
- flex-wrap: wrap;
1045
- }
1046
- .section-header-left { min-width: 0; }
1047
- .section-header-right {
1048
- display: flex;
1049
- align-items: center;
1050
- gap: var(--space-2);
1051
- flex-shrink: 0;
1052
- }
1053
- .eyebrow {
1054
- font-size: var(--text-xs);
1055
- font-weight: 700;
1056
- letter-spacing: 0.12em;
1057
- text-transform: uppercase;
1058
- color: var(--accent);
1059
- margin-bottom: var(--space-1);
1060
- }
1061
-
1062
- /* ───────────────────────────────────
1063
- TAB PILLS
1064
- ─────────────────────────────────── */
1065
- .tab-pills {
1066
- display: inline-flex;
1067
- gap: 2px;
1068
- padding: 3px;
1069
- background: var(--glass-bg-subtle);
1070
- backdrop-filter: blur(var(--glass-blur-sm));
1071
- -webkit-backdrop-filter: blur(var(--glass-blur-sm));
1072
- border: 1px solid var(--glass-border);
1073
- border-radius: var(--radius-full);
1074
- }
1075
- .tab-pill {
1076
- padding: 0.4rem 1rem;
1077
- border: none;
1078
- background: transparent;
1079
- color: var(--text-secondary);
1080
- font-family: var(--font-ui);
1081
- font-size: var(--text-sm);
1082
- font-weight: 600;
1083
- border-radius: var(--radius-full);
1084
- cursor: pointer;
1085
- transition: all var(--duration-fast) var(--ease-out);
1086
- white-space: nowrap;
1087
- }
1088
- .tab-pill:hover {
1089
- color: var(--text-primary);
1090
- background: var(--surface-4);
1091
- }
1092
- .tab-pill.is-active {
1093
- background: var(--accent);
1094
- color: #fff;
1095
- box-shadow: 0 2px 8px rgba(96, 165, 250, 0.25);
1096
- }
1097
-
1098
- /* ───────────────────────────────────
1099
- CHART CARD (glass)
1100
- ─────────────────────────────────── */
1101
- .chart-card {
1102
- background: var(--glass-bg);
1103
- backdrop-filter: blur(var(--glass-blur));
1104
- -webkit-backdrop-filter: blur(var(--glass-blur));
1105
- border: 1px solid var(--glass-border);
1106
- box-shadow: var(--glass-shadow), var(--glass-inner);
1107
- }
1
+ /* ═══════════════════════════════════════════════════════
2
+ COMPONENTS — Botones, Cards, Badges, Forms
3
+ ═══════════════════════════════════════════════════════ */
4
+
5
+ /* ───────────────────────────────────
6
+ BOTONES
7
+ ─────────────────────────────────── */
8
+ .btn {
9
+ display: inline-flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ gap: var(--space-2);
13
+ font-weight: 600;
14
+ font-size: var(--text-sm);
15
+ border-radius: var(--radius-full);
16
+ padding: 0.6rem 1.25rem;
17
+ border: 1px solid transparent;
18
+ transition:
19
+ background var(--duration-base) var(--ease-out),
20
+ box-shadow var(--duration-base) var(--ease-out),
21
+ transform var(--duration-fast) var(--ease-out),
22
+ border-color var(--duration-base) var(--ease-out);
23
+ letter-spacing: 0.01em;
24
+ cursor: pointer;
25
+ white-space: nowrap;
26
+ min-height: 36px;
27
+ line-height: 1;
28
+ }
29
+
30
+ .btn:active { transform: translateY(1px); }
31
+
32
+ /* Primary */
33
+ .btn-primary {
34
+ background: linear-gradient(135deg, #3B82F6 0%, #60A5FA 100%);
35
+ color: white;
36
+ box-shadow: 0 4px 12px rgba(96, 165, 250, 0.3);
37
+ }
38
+ .btn-primary:hover {
39
+ transform: translateY(-1px);
40
+ box-shadow: 0 12px 32px rgba(96, 165, 250, 0.35);
41
+ }
42
+
43
+ /* Ghost */
44
+ .btn-ghost {
45
+ background: var(--glass-bg-subtle);
46
+ color: var(--text-secondary);
47
+ border: 1px solid var(--glass-border);
48
+ }
49
+ .btn-ghost:hover {
50
+ background: var(--glass-bg);
51
+ color: var(--text-primary);
52
+ border-color: var(--border-strong);
53
+ }
54
+
55
+ /* Danger */
56
+ .btn-danger {
57
+ background: var(--danger-light);
58
+ color: var(--danger);
59
+ border-color: rgba(239,68,68,0.2);
60
+ }
61
+ .btn-danger:hover {
62
+ background: var(--danger);
63
+ color: white;
64
+ }
65
+
66
+ /* Success */
67
+ .btn-success {
68
+ background: var(--success-light);
69
+ color: var(--success);
70
+ border-color: rgba(16,185,129,0.2);
71
+ }
72
+ .btn-success:hover {
73
+ background: var(--success);
74
+ color: white;
75
+ }
76
+
77
+ /* Icon button */
78
+ .btn-icon {
79
+ padding: var(--space-2);
80
+ min-height: 36px;
81
+ min-width: 36px;
82
+ border-radius: var(--radius-md);
83
+ }
84
+
85
+ /* Small — min 44px touch target via padding (WCAG 2.2 AA) */
86
+ .btn-sm {
87
+ padding: 0.4rem 0.85rem;
88
+ font-size: var(--text-xs);
89
+ min-height: 32px;
90
+ position: relative;
91
+ }
92
+ /* Invisible touch target expansion for small buttons */
93
+ .btn-sm::after {
94
+ content: '';
95
+ position: absolute;
96
+ inset: -6px;
97
+ pointer-events: auto;
98
+ }
99
+
100
+ /* Chip / pill */
101
+ .chip {
102
+ display: inline-flex;
103
+ align-items: center;
104
+ gap: var(--space-1);
105
+ padding: 0.25rem 0.75rem;
106
+ font-size: var(--text-xs);
107
+ font-weight: 600;
108
+ border-radius: var(--radius-full);
109
+ border: 1px solid var(--border);
110
+ background: var(--surface-4);
111
+ color: var(--text-secondary);
112
+ cursor: pointer;
113
+ transition:
114
+ background var(--duration-fast) var(--ease-out),
115
+ border-color var(--duration-fast) var(--ease-out),
116
+ color var(--duration-fast) var(--ease-out);
117
+ }
118
+ .chip:hover {
119
+ background: var(--surface-3);
120
+ border-color: var(--border-strong);
121
+ color: var(--text-primary);
122
+ }
123
+ .chip.is-active {
124
+ background: var(--accent-light);
125
+ border-color: var(--border-accent);
126
+ color: var(--text-accent);
127
+ }
128
+
129
+ /* ───────────────────────────────────
130
+ BADGES / TAGS
131
+ ─────────────────────────────────── */
132
+ .badge {
133
+ display: inline-flex;
134
+ align-items: center;
135
+ gap: var(--space-1);
136
+ padding: 0.2rem 0.6rem;
137
+ font-size: var(--text-xs);
138
+ font-weight: 700;
139
+ border-radius: var(--radius-full);
140
+ white-space: nowrap;
141
+ letter-spacing: 0.04em;
142
+ }
143
+
144
+ .badge-accent { background: var(--accent-light); color: var(--accent); border: 1px solid rgba(96,165,250,0.2); }
145
+ .badge-success { background: var(--success-light); color: var(--success); border: 1px solid rgba(16,185,129,0.2); }
146
+ .badge-warning { background: var(--warning-light); color: var(--warning); border: 1px solid rgba(245,158,11,0.2); }
147
+ .badge-danger { background: var(--danger-light); color: var(--danger); border: 1px solid rgba(239,68,68,0.2); }
148
+ .badge-muted { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
149
+ .badge-info { background: var(--info-light); color: var(--info); border: 1px solid rgba(59,130,246,0.2); }
150
+
151
+ /* Priority badges */
152
+ .badge-p0 { background: rgba(239,68,68,0.12); color: var(--p0); border: 1px solid rgba(239,68,68,0.2); }
153
+ .badge-p1 { background: rgba(245,158,11,0.12); color: var(--p1); border: 1px solid rgba(245,158,11,0.2); }
154
+ .badge-p2 { background: var(--accent-light); color: var(--accent); border: 1px solid rgba(99,102,241,0.2); }
155
+ .badge-p3 { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
156
+
157
+ /* Status badges */
158
+ .status-pending { background: rgba(245,158,11,0.1); color: var(--warning); border: 1px solid rgba(245,158,11,0.15); }
159
+ .status-in_progress { background: var(--info-light); color: var(--info); border: 1px solid rgba(59,130,246,0.2); }
160
+ .status-in_review { background: var(--accent-light); color: var(--text-accent); border: 1px solid rgba(99,102,241,0.2); }
161
+ .status-blocked { background: var(--danger-light); color: var(--danger); border: 1px solid rgba(239,68,68,0.2); }
162
+ .status-completed { background: var(--success-light); color: var(--success); border: 1px solid rgba(16,185,129,0.2); }
163
+ .status-cancelled { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
164
+
165
+ /* ── Glass Card ── */
166
+ .glass-card {
167
+ background: var(--glass-bg);
168
+ backdrop-filter: blur(var(--glass-blur));
169
+ -webkit-backdrop-filter: blur(var(--glass-blur));
170
+ border: 1px solid var(--glass-border);
171
+ border-radius: var(--radius-xl);
172
+ box-shadow: var(--glass-shadow), var(--glass-inner);
173
+ }
174
+ .glass-card:hover {
175
+ background: var(--glass-bg-strong);
176
+ border-color: var(--glass-border-hover);
177
+ box-shadow: var(--shadow-md);
178
+ }
179
+
180
+ /* ───────────────────────────────────
181
+ CARDS
182
+ ─────────────────────────────────── */
183
+ .card {
184
+ background: var(--glass-bg);
185
+ backdrop-filter: blur(var(--glass-blur));
186
+ -webkit-backdrop-filter: blur(var(--glass-blur));
187
+ border: 1px solid var(--glass-border);
188
+ border-radius: var(--radius-lg);
189
+ box-shadow: var(--glass-shadow), var(--glass-inner);
190
+ transition:
191
+ border-color var(--duration-base) var(--ease-out),
192
+ box-shadow var(--duration-base) var(--ease-out),
193
+ background var(--duration-base) var(--ease-out);
194
+ }
195
+ .card:hover { border-color: var(--glass-border-hover); box-shadow: var(--shadow-md); }
196
+
197
+ /* Fallback for browsers without backdrop-filter */
198
+ @supports not (backdrop-filter: blur(1px)) {
199
+ .card, .glass-card, .kpi-card, .chart-card, .task-card, .project-card {
200
+ background: var(--gray-800);
201
+ }
202
+ }
203
+
204
+ .card-body { padding: var(--space-5); }
205
+ .card-sm .card-body { padding: var(--space-4); }
206
+ .card-lg .card-body { padding: var(--space-6); }
207
+
208
+ /* KPI metric card */
209
+ .kpi-card {
210
+ background: var(--glass-bg);
211
+ backdrop-filter: blur(var(--glass-blur));
212
+ -webkit-backdrop-filter: blur(var(--glass-blur));
213
+ border: 1px solid var(--glass-border);
214
+ border-radius: var(--radius-lg);
215
+ padding: var(--space-5);
216
+ display: flex;
217
+ flex-direction: column;
218
+ gap: var(--space-2);
219
+ position: relative;
220
+ overflow: hidden;
221
+ transition:
222
+ border-color var(--duration-base) var(--ease-out),
223
+ box-shadow var(--duration-base) var(--ease-out);
224
+ }
225
+ .kpi-card::before {
226
+ content: '';
227
+ position: absolute;
228
+ top: 0; left: 0; right: 0;
229
+ height: 2px;
230
+ background: linear-gradient(90deg, var(--accent), transparent);
231
+ opacity: 0;
232
+ transition: opacity var(--duration-base) var(--ease-out);
233
+ }
234
+ .kpi-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
235
+ .kpi-card:hover::before { opacity: 1; }
236
+
237
+ .kpi-card.kpi-accent { border-top: 2px solid var(--accent); }
238
+ .kpi-card.kpi-success { border-top: 2px solid var(--success); }
239
+ .kpi-card.kpi-warning { border-top: 2px solid var(--warning); }
240
+ .kpi-card.kpi-danger { border-top: 2px solid var(--danger); }
241
+
242
+ .kpi-header {
243
+ display: flex;
244
+ align-items: center;
245
+ justify-content: space-between;
246
+ }
247
+
248
+ .kpi-title {
249
+ font-size: var(--text-xs);
250
+ font-weight: 700;
251
+ letter-spacing: 0.08em;
252
+ text-transform: uppercase;
253
+ color: var(--text-muted);
254
+ }
255
+
256
+ .kpi-icon {
257
+ width: 32px;
258
+ height: 32px;
259
+ border-radius: var(--radius-sm);
260
+ display: flex;
261
+ align-items: center;
262
+ justify-content: center;
263
+ }
264
+ .kpi-icon.accent { background: var(--accent-light); color: var(--accent); }
265
+ .kpi-icon.success { background: var(--success-light); color: var(--success); }
266
+ .kpi-icon.warning { background: var(--warning-light); color: var(--warning); }
267
+ .kpi-icon.danger { background: var(--danger-light); color: var(--danger); }
268
+
269
+ .kpi-value {
270
+ font-family: var(--font-heading);
271
+ font-size: var(--text-3xl);
272
+ font-weight: 800;
273
+ letter-spacing: -0.04em;
274
+ line-height: 1;
275
+ color: var(--text-primary);
276
+ }
277
+
278
+ .kpi-sub {
279
+ font-size: var(--text-xs);
280
+ color: var(--text-muted);
281
+ }
282
+
283
+ .kpi-trend {
284
+ display: inline-flex;
285
+ align-items: center;
286
+ gap: var(--space-1);
287
+ font-size: var(--text-xs);
288
+ font-weight: 600;
289
+ }
290
+ .kpi-trend.up { color: var(--success); }
291
+ .kpi-trend.down { color: var(--danger); }
292
+
293
+ /* Task card (kanban) */
294
+ .task-card {
295
+ background: var(--glass-bg);
296
+ backdrop-filter: blur(var(--glass-blur-sm));
297
+ -webkit-backdrop-filter: blur(var(--glass-blur-sm));
298
+ border: 1px solid var(--glass-border);
299
+ border-radius: var(--radius-md);
300
+ padding: var(--space-4);
301
+ text-align: left;
302
+ width: 100%;
303
+ cursor: pointer;
304
+ transition:
305
+ border-color var(--duration-fast) var(--ease-out),
306
+ box-shadow var(--duration-fast) var(--ease-out),
307
+ background var(--duration-fast) var(--ease-out),
308
+ transform var(--duration-fast) var(--ease-out);
309
+ position: relative;
310
+ }
311
+ .task-card:hover {
312
+ border-color: var(--glass-border-hover);
313
+ box-shadow: var(--shadow-sm);
314
+ transform: translateY(-1px);
315
+ }
316
+ .task-card.is-selected {
317
+ border-color: var(--border-accent);
318
+ background: linear-gradient(135deg, rgba(99,102,241,0.06) 0%, var(--surface-2) 100%);
319
+ box-shadow: var(--shadow-accent);
320
+ }
321
+ .task-card[data-status="blocked"] {
322
+ border-left: 3px solid var(--danger);
323
+ }
324
+ .task-card[data-status="completed"] {
325
+ opacity: 0.65;
326
+ }
327
+ .task-card[data-status="completed"]:hover {
328
+ opacity: 1;
329
+ }
330
+
331
+ .task-card-title {
332
+ font-size: var(--text-sm);
333
+ font-weight: 700;
334
+ color: var(--text-primary);
335
+ margin-bottom: var(--space-1);
336
+ display: -webkit-box;
337
+ -webkit-line-clamp: 2;
338
+ -webkit-box-orient: vertical;
339
+ overflow: hidden;
340
+ }
341
+ .task-card-id {
342
+ font-family: var(--font-mono);
343
+ font-size: 0.7rem;
344
+ color: var(--text-muted);
345
+ display: block;
346
+ margin-bottom: var(--space-2);
347
+ }
348
+ .task-card-summary {
349
+ font-size: var(--text-xs);
350
+ color: var(--text-secondary);
351
+ margin-bottom: var(--space-3);
352
+ display: -webkit-box;
353
+ -webkit-line-clamp: 2;
354
+ -webkit-box-orient: vertical;
355
+ overflow: hidden;
356
+ min-height: 2.4em;
357
+ }
358
+ .task-card-meta {
359
+ display: flex;
360
+ flex-wrap: wrap;
361
+ gap: var(--space-1);
362
+ }
363
+
364
+ /* Dragging state */
365
+ .task-card[draggable]:hover { cursor: grab; }
366
+ .task-card.is-dragging {
367
+ opacity: 0.4;
368
+ transform: rotate(2deg) scale(0.98);
369
+ }
370
+
371
+ /* ───────────────────────────────────
372
+ FORMS
373
+ ─────────────────────────────────── */
374
+ .field { display: flex; flex-direction: column; gap: var(--space-2); }
375
+
376
+ .field label {
377
+ font-size: var(--text-xs);
378
+ font-weight: 700;
379
+ letter-spacing: 0.06em;
380
+ text-transform: uppercase;
381
+ color: var(--text-muted);
382
+ }
383
+
384
+ input[type="text"],
385
+ input[type="search"],
386
+ input[type="email"],
387
+ textarea,
388
+ select {
389
+ width: 100%;
390
+ padding: 0.65rem 0.85rem;
391
+ font-size: var(--text-sm);
392
+ font-family: var(--font-ui);
393
+ color: var(--text-primary);
394
+ background: var(--surface-1);
395
+ border: 1px solid var(--border);
396
+ border-radius: var(--radius-md);
397
+ outline: none;
398
+ transition:
399
+ border-color var(--duration-fast) var(--ease-out),
400
+ box-shadow var(--duration-fast) var(--ease-out),
401
+ background var(--duration-fast) var(--ease-out);
402
+ min-height: 40px;
403
+ appearance: none;
404
+ -webkit-appearance: none;
405
+ }
406
+
407
+ input:hover, textarea:hover, select:hover {
408
+ border-color: var(--border-strong);
409
+ }
410
+
411
+ input:focus, textarea:focus, select:focus {
412
+ border-color: var(--accent);
413
+ box-shadow: 0 0 0 3px var(--accent-light);
414
+ }
415
+
416
+ textarea {
417
+ resize: vertical;
418
+ min-height: 80px;
419
+ line-height: 1.5;
420
+ }
421
+
422
+ select {
423
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2394A3B8' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
424
+ background-repeat: no-repeat;
425
+ background-position: right 12px center;
426
+ padding-right: 36px;
427
+ }
428
+
429
+ /* Checkbox custom */
430
+ input[type="checkbox"] {
431
+ width: 18px;
432
+ height: 18px;
433
+ min-height: 18px;
434
+ min-width: 18px;
435
+ border-radius: var(--radius-xs);
436
+ border: 2px solid var(--border-strong);
437
+ background: var(--surface-1);
438
+ cursor: pointer;
439
+ accent-color: var(--accent);
440
+ }
441
+
442
+ .checkbox-field {
443
+ display: flex;
444
+ align-items: center;
445
+ gap: var(--space-3);
446
+ }
447
+ .checkbox-field label {
448
+ font-size: var(--text-sm);
449
+ font-weight: 500;
450
+ letter-spacing: 0;
451
+ text-transform: none;
452
+ color: var(--text-secondary);
453
+ cursor: pointer;
454
+ }
455
+
456
+ .field-row {
457
+ display: grid;
458
+ grid-template-columns: repeat(2, 1fr);
459
+ gap: var(--space-3);
460
+ }
461
+
462
+ .form-actions {
463
+ display: flex;
464
+ gap: var(--space-3);
465
+ padding-top: var(--space-2);
466
+ }
467
+
468
+ /* Search bar */
469
+ .search-wrapper {
470
+ position: relative;
471
+ display: flex;
472
+ align-items: center;
473
+ }
474
+ .search-wrapper .search-icon {
475
+ position: absolute;
476
+ left: var(--space-3);
477
+ color: var(--text-muted);
478
+ pointer-events: none;
479
+ flex-shrink: 0;
480
+ }
481
+ .search-wrapper input {
482
+ padding-left: 2.4rem;
483
+ }
484
+ .search-wrapper .search-kbd {
485
+ position: absolute;
486
+ right: var(--space-3);
487
+ font-family: var(--font-mono);
488
+ font-size: 0.65rem;
489
+ color: var(--text-muted);
490
+ background: var(--surface-3);
491
+ padding: 2px 6px;
492
+ border-radius: var(--radius-xs);
493
+ border: 1px solid var(--border);
494
+ pointer-events: none;
495
+ }
496
+
497
+ /* ───────────────────────────────────
498
+ EMPTY STATE
499
+ ─────────────────────────────────── */
500
+ .empty-state {
501
+ display: flex;
502
+ flex-direction: column;
503
+ align-items: center;
504
+ justify-content: center;
505
+ gap: var(--space-3);
506
+ padding: var(--space-10) var(--space-6);
507
+ text-align: center;
508
+ color: var(--text-muted);
509
+ font-size: var(--text-sm);
510
+ border: 1px dashed var(--border);
511
+ border-radius: var(--radius-lg);
512
+ }
513
+ .empty-state svg { opacity: 0.4; }
514
+
515
+ /* ───────────────────────────────────
516
+ INFO ROWS
517
+ ─────────────────────────────────── */
518
+ .info-row {
519
+ padding: var(--space-3) var(--space-4);
520
+ border-radius: var(--radius-md);
521
+ background: var(--surface-4);
522
+ border: 1px solid var(--border);
523
+ display: flex;
524
+ flex-direction: column;
525
+ gap: var(--space-1);
526
+ }
527
+ .info-row .label-sm { margin-bottom: var(--space-1); }
528
+ .info-row .value {
529
+ font-size: var(--text-sm);
530
+ font-weight: 500;
531
+ font-family: var(--font-mono);
532
+ color: var(--text-primary);
533
+ overflow: hidden;
534
+ text-overflow: ellipsis;
535
+ white-space: nowrap;
536
+ }
537
+
538
+ /* ───────────────────────────────────
539
+ SECTION HEADER (dentro de vistas)
540
+ ─────────────────────────────────── */
541
+ .section-header {
542
+ display: flex;
543
+ align-items: flex-start;
544
+ justify-content: space-between;
545
+ gap: var(--space-4);
546
+ margin-bottom: var(--space-5);
547
+ }
548
+ .section-header-left { display: flex; flex-direction: column; gap: var(--space-1); }
549
+ .section-header h2, .section-header h3 { margin: 0; }
550
+ .section-subtitle { font-size: var(--text-sm); color: var(--text-secondary); }
551
+
552
+ /* ───────────────────────────────────
553
+ STACK LIST
554
+ ─────────────────────────────────── */
555
+ .stack { display: flex; flex-direction: column; gap: var(--space-2); }
556
+ .stack-sm { gap: var(--space-2); }
557
+ .stack-md { gap: var(--space-3); }
558
+ .stack-lg { gap: var(--space-4); }
559
+
560
+ /* ───────────────────────────────────
561
+ GRID LAYOUTS COMUNES
562
+ ─────────────────────────────────── */
563
+ .grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
564
+ .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }
565
+ .grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
566
+ .grid-split { display: grid; grid-template-columns: 1fr 380px; gap: var(--space-4); align-items: start; }
567
+
568
+ @media (max-width: 1280px) {
569
+ .grid-4 { grid-template-columns: repeat(2, 1fr); }
570
+ .grid-3 { grid-template-columns: repeat(2, 1fr); }
571
+ .grid-split { grid-template-columns: 1fr; }
572
+ }
573
+ @media (max-width: 768px) {
574
+ .grid-4, .grid-3, .grid-2 { grid-template-columns: 1fr; }
575
+ .field-row { grid-template-columns: 1fr; }
576
+ }
577
+
578
+ /* ───────────────────────────────────
579
+ SPINNER DE CARGA
580
+ ─────────────────────────────────── */
581
+ .spinner {
582
+ width: 20px; height: 20px;
583
+ border: 2px solid var(--border-strong);
584
+ border-top-color: var(--accent);
585
+ border-radius: 50%;
586
+ animation: spin 0.7s linear infinite;
587
+ }
588
+
589
+ /* ───────────────────────────────────
590
+ THEME TOGGLE BUTTON
591
+ ─────────────────────────────────── */
592
+ .theme-toggle {
593
+ position: relative;
594
+ overflow: hidden;
595
+ color: var(--text-secondary);
596
+ }
597
+ .theme-toggle:hover {
598
+ color: var(--accent);
599
+ background: var(--accent-light);
600
+ border-color: var(--border-accent);
601
+ }
602
+ .theme-toggle svg {
603
+ transition: transform var(--duration-slow) var(--ease-out), opacity var(--duration-base);
604
+ }
605
+ .theme-toggle:hover svg {
606
+ transform: rotate(20deg) scale(1.1);
607
+ }
608
+
609
+ /* ───────────────────────────────────
610
+ FILTER BAR
611
+ ─────────────────────────────────── */
612
+ .filter-bar {
613
+ display: flex;
614
+ flex-direction: column;
615
+ gap: var(--space-3);
616
+ margin-bottom: var(--space-4);
617
+ }
618
+ .filter-controls {
619
+ display: flex;
620
+ gap: var(--space-2);
621
+ flex-wrap: wrap;
622
+ align-items: center;
623
+ }
624
+ .filter-select {
625
+ min-width: 130px;
626
+ height: 36px;
627
+ font-size: var(--text-sm);
628
+ padding: 0 2rem 0 0.75rem;
629
+ }
630
+ .filter-search {
631
+ flex: 1;
632
+ min-width: 180px;
633
+ }
634
+ .filter-search-input {
635
+ height: 36px;
636
+ font-size: var(--text-sm);
637
+ }
638
+ .filter-active-bar {
639
+ display: flex;
640
+ align-items: center;
641
+ gap: var(--space-2);
642
+ flex-wrap: wrap;
643
+ }
644
+ .filter-clear-all {
645
+ margin-left: auto;
646
+ }
647
+
648
+ /* ───────────────────────────────────
649
+ KEYBOARD HELP PANEL
650
+ ─────────────────────────────────── */
651
+ .kb-help-group {
652
+ margin-bottom: var(--space-4);
653
+ }
654
+ .kb-help-group:last-child {
655
+ margin-bottom: 0;
656
+ }
657
+ .kb-help-group-title {
658
+ font-size: var(--text-xs);
659
+ font-weight: 700;
660
+ letter-spacing: 0.1em;
661
+ text-transform: uppercase;
662
+ color: var(--text-muted);
663
+ margin-bottom: var(--space-3);
664
+ padding-bottom: var(--space-2);
665
+ border-bottom: 1px solid var(--border);
666
+ }
667
+ .kb-help-items {
668
+ display: flex;
669
+ flex-direction: column;
670
+ gap: var(--space-2);
671
+ }
672
+ .kb-help-item {
673
+ display: flex;
674
+ align-items: center;
675
+ justify-content: space-between;
676
+ gap: var(--space-4);
677
+ padding: var(--space-1) 0;
678
+ }
679
+ .kb-help-key {
680
+ display: inline-flex;
681
+ align-items: center;
682
+ gap: var(--space-1);
683
+ padding: 0.2rem 0.5rem;
684
+ background: var(--surface-3);
685
+ border: 1px solid var(--border-strong);
686
+ border-radius: var(--radius-xs);
687
+ font-family: var(--font-mono);
688
+ font-size: var(--text-xs);
689
+ font-weight: 600;
690
+ color: var(--text-primary);
691
+ min-width: 24px;
692
+ text-align: center;
693
+ justify-content: center;
694
+ white-space: nowrap;
695
+ }
696
+ .kb-help-label {
697
+ font-size: var(--text-sm);
698
+ color: var(--text-secondary);
699
+ }
700
+
701
+ /* ───────────────────────────────────
702
+ SKELETON LOADER
703
+ ─────────────────────────────────── */
704
+ .skeleton {
705
+ background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-4) 50%, var(--surface-3) 75%);
706
+ background-size: 200% 100%;
707
+ animation: skeleton-pulse 1.5s ease-in-out infinite;
708
+ border-radius: var(--radius-sm);
709
+ }
710
+ .skeleton-text {
711
+ height: 14px;
712
+ margin-bottom: var(--space-2);
713
+ }
714
+ .skeleton-text:last-child {
715
+ width: 60%;
716
+ }
717
+ .skeleton-card {
718
+ height: 120px;
719
+ border-radius: var(--radius-lg);
720
+ }
721
+ .skeleton-circle {
722
+ border-radius: 50%;
723
+ }
724
+
725
+ @keyframes skeleton-pulse {
726
+ 0% { background-position: 200% 0; }
727
+ 100% { background-position: -200% 0; }
728
+ }
729
+
730
+ /* ───────────────────────────────────
731
+ PROJECT CARDS (vista Projects)
732
+ ─────────────────────────────────── */
733
+ .projects-grid {
734
+ display: grid;
735
+ grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
736
+ gap: var(--space-4);
737
+ }
738
+ @media (max-width: 960px) {
739
+ .projects-grid { grid-template-columns: 1fr; }
740
+ }
741
+
742
+ .project-card {
743
+ background: var(--glass-bg);
744
+ backdrop-filter: blur(var(--glass-blur));
745
+ -webkit-backdrop-filter: blur(var(--glass-blur));
746
+ border: 1px solid var(--glass-border);
747
+ border-radius: var(--radius-xl);
748
+ padding: var(--space-5);
749
+ display: flex;
750
+ flex-direction: column;
751
+ gap: var(--space-4);
752
+ box-shadow: var(--glass-shadow), var(--glass-inner);
753
+ transition:
754
+ border-color var(--duration-fast) var(--ease-out),
755
+ box-shadow var(--duration-base) var(--ease-out),
756
+ transform var(--duration-base) var(--ease-out);
757
+ }
758
+ .project-card:hover {
759
+ border-color: var(--glass-border-hover);
760
+ box-shadow: var(--shadow-md);
761
+ transform: translateY(-2px);
762
+ }
763
+ .project-card.is-current {
764
+ border-color: var(--border-accent);
765
+ background: linear-gradient(135deg, var(--surface-2), rgba(99,102,241,0.04));
766
+ }
767
+ .project-card.is-unavailable {
768
+ opacity: 0.6;
769
+ }
770
+ .project-card.is-unavailable:hover {
771
+ transform: none;
772
+ box-shadow: none;
773
+ }
774
+
775
+ .project-card-header {
776
+ display: flex;
777
+ align-items: flex-start;
778
+ justify-content: space-between;
779
+ gap: var(--space-3);
780
+ }
781
+ .project-card-info { min-width: 0; flex: 1; }
782
+ .project-card-name {
783
+ font-size: var(--text-md);
784
+ font-weight: 800;
785
+ font-family: var(--font-heading);
786
+ color: var(--text-primary);
787
+ margin: 0;
788
+ }
789
+ .project-card-path {
790
+ font-size: var(--text-xs);
791
+ font-family: var(--font-mono);
792
+ color: var(--text-muted);
793
+ overflow: hidden;
794
+ text-overflow: ellipsis;
795
+ white-space: nowrap;
796
+ margin-top: var(--space-1);
797
+ }
798
+ .project-card-badges {
799
+ display: flex;
800
+ gap: var(--space-2);
801
+ flex-wrap: wrap;
802
+ flex-shrink: 0;
803
+ }
804
+
805
+ .project-metrics-grid {
806
+ display: grid;
807
+ grid-template-columns: repeat(5, 1fr);
808
+ gap: var(--space-2);
809
+ }
810
+ .project-metric {
811
+ text-align: center;
812
+ padding: var(--space-2);
813
+ background: var(--surface-3);
814
+ border-radius: var(--radius-md);
815
+ border: 1px solid var(--border);
816
+ }
817
+ .project-metric-value {
818
+ display: block;
819
+ font-family: var(--font-heading);
820
+ font-size: var(--text-lg);
821
+ font-weight: 800;
822
+ color: var(--text-primary);
823
+ line-height: 1.2;
824
+ }
825
+ .project-metric-label {
826
+ display: block;
827
+ font-size: 0.65rem;
828
+ font-weight: 600;
829
+ color: var(--text-muted);
830
+ text-transform: uppercase;
831
+ letter-spacing: 0.08em;
832
+ margin-top: var(--space-1);
833
+ }
834
+
835
+ .project-progress-track {
836
+ width: 100%;
837
+ height: 6px;
838
+ background: var(--surface-3);
839
+ border-radius: var(--radius-full);
840
+ overflow: hidden;
841
+ }
842
+ .project-progress-fill {
843
+ height: 100%;
844
+ background: linear-gradient(90deg, var(--accent), var(--success));
845
+ border-radius: var(--radius-full);
846
+ transition: width var(--duration-slow) var(--ease-out);
847
+ }
848
+
849
+ .project-card-meta {
850
+ display: flex;
851
+ gap: var(--space-4);
852
+ flex-wrap: wrap;
853
+ }
854
+
855
+ .project-card-actions {
856
+ display: flex;
857
+ gap: var(--space-2);
858
+ flex-wrap: wrap;
859
+ padding-top: var(--space-3);
860
+ border-top: 1px solid var(--border);
861
+ }
862
+
863
+ .project-card-metrics.is-disabled {
864
+ opacity: 0.4;
865
+ pointer-events: none;
866
+ }
867
+
868
+ /* ── Project card name row + info tooltip ── */
869
+ .project-card-name-row {
870
+ display: flex;
871
+ align-items: center;
872
+ gap: var(--space-2);
873
+ position: relative;
874
+ }
875
+ .project-info-btn {
876
+ display: flex;
877
+ align-items: center;
878
+ justify-content: center;
879
+ color: var(--text-muted);
880
+ opacity: 0;
881
+ transition: opacity var(--duration-fast), color var(--duration-fast);
882
+ }
883
+ .project-card:hover .project-info-btn { opacity: 1; }
884
+ .project-info-btn:hover { color: var(--accent); }
885
+ .project-info-tooltip {
886
+ position: absolute;
887
+ top: 100%;
888
+ left: 0;
889
+ z-index: var(--z-panel);
890
+ min-width: 280px;
891
+ background: var(--glass-bg-strong);
892
+ backdrop-filter: blur(var(--glass-blur-lg));
893
+ -webkit-backdrop-filter: blur(var(--glass-blur-lg));
894
+ border: 1px solid var(--glass-border);
895
+ border-radius: var(--radius-md);
896
+ padding: var(--space-3);
897
+ box-shadow: var(--shadow-lg);
898
+ margin-top: var(--space-2);
899
+ display: flex;
900
+ flex-direction: column;
901
+ gap: var(--space-1);
902
+ }
903
+ .project-info-tooltip.is-hidden { display: none; }
904
+ .tooltip-row {
905
+ display: flex;
906
+ justify-content: space-between;
907
+ gap: var(--space-3);
908
+ font-size: var(--text-xs);
909
+ }
910
+ .tooltip-label {
911
+ color: var(--text-muted);
912
+ white-space: nowrap;
913
+ }
914
+ .tooltip-value {
915
+ color: var(--text-secondary);
916
+ font-family: var(--font-mono);
917
+ text-align: right;
918
+ overflow: hidden;
919
+ text-overflow: ellipsis;
920
+ white-space: nowrap;
921
+ max-width: 200px;
922
+ }
923
+
924
+ /* ── Card indicators (health, deadline, priority) ── */
925
+ .project-card-indicators {
926
+ display: flex;
927
+ align-items: center;
928
+ gap: var(--space-3);
929
+ flex-wrap: wrap;
930
+ }
931
+ .project-indicator {
932
+ display: flex;
933
+ align-items: center;
934
+ gap: var(--space-1);
935
+ font-size: var(--text-xs);
936
+ color: var(--text-secondary);
937
+ }
938
+ .indicator-dot {
939
+ width: 8px;
940
+ height: 8px;
941
+ border-radius: 50%;
942
+ flex-shrink: 0;
943
+ }
944
+ .indicator-label {
945
+ font-weight: 600;
946
+ }
947
+
948
+ /* ── Portfolio KPIs ── */
949
+ .portfolio-kpi-grid {
950
+ display: grid;
951
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
952
+ gap: var(--space-3);
953
+ margin-bottom: var(--space-4);
954
+ }
955
+ .portfolio-kpi {
956
+ display: flex;
957
+ align-items: center;
958
+ gap: var(--space-3);
959
+ padding: var(--space-4);
960
+ }
961
+ .portfolio-kpi-icon {
962
+ display: flex;
963
+ align-items: center;
964
+ justify-content: center;
965
+ color: var(--text-muted);
966
+ flex-shrink: 0;
967
+ }
968
+ .portfolio-kpi-value {
969
+ display: block;
970
+ font-family: var(--font-heading);
971
+ font-size: var(--text-2xl);
972
+ font-weight: 800;
973
+ line-height: 1;
974
+ color: var(--text-primary);
975
+ }
976
+ .portfolio-kpi-label {
977
+ display: block;
978
+ font-size: var(--text-xs);
979
+ color: var(--text-muted);
980
+ margin-top: 2px;
981
+ }
982
+ .portfolio-kpi.kpi-danger { border-color: rgba(248,113,113,0.3); }
983
+ .portfolio-kpi.kpi-warning { border-color: rgba(250,204,21,0.3); }
984
+
985
+ /* ── Portfolio analytics ── */
986
+ .portfolio-analytics {
987
+ display: grid;
988
+ grid-template-columns: 1fr 1fr 1fr;
989
+ gap: var(--space-4);
990
+ margin-bottom: var(--space-5);
991
+ }
992
+ @media (max-width: 1100px) {
993
+ .portfolio-analytics { grid-template-columns: 1fr; }
994
+ }
995
+ .portfolio-chart, .portfolio-attention {
996
+ padding: var(--space-4);
997
+ }
998
+ .portfolio-attention {
999
+ max-height: 260px;
1000
+ overflow-y: auto;
1001
+ }
1002
+ .attention-item {
1003
+ display: flex;
1004
+ align-items: center;
1005
+ gap: var(--space-2);
1006
+ padding: var(--space-2) 0;
1007
+ border-bottom: 1px solid var(--border);
1008
+ }
1009
+ .attention-item:last-child { border-bottom: none; }
1010
+ .attention-dot {
1011
+ width: 6px;
1012
+ height: 6px;
1013
+ border-radius: 50%;
1014
+ flex-shrink: 0;
1015
+ }
1016
+
1017
+ /* ── Donut legend ── */
1018
+ .donut-legend {
1019
+ display: flex;
1020
+ flex-direction: column;
1021
+ gap: var(--space-1);
1022
+ }
1023
+ .donut-legend-item {
1024
+ display: flex;
1025
+ align-items: center;
1026
+ gap: var(--space-2);
1027
+ font-size: var(--text-xs);
1028
+ color: var(--text-secondary);
1029
+ }
1030
+ .donut-legend-dot {
1031
+ width: 8px;
1032
+ height: 8px;
1033
+ border-radius: 50%;
1034
+ flex-shrink: 0;
1035
+ }
1036
+
1037
+ /* Section header (reusable en views) */
1038
+ .section-header {
1039
+ display: flex;
1040
+ align-items: flex-start;
1041
+ justify-content: space-between;
1042
+ gap: var(--space-4);
1043
+ margin-bottom: var(--space-5);
1044
+ flex-wrap: wrap;
1045
+ }
1046
+ .section-header-left { min-width: 0; }
1047
+ .section-header-right {
1048
+ display: flex;
1049
+ align-items: center;
1050
+ gap: var(--space-2);
1051
+ flex-shrink: 0;
1052
+ }
1053
+ .eyebrow {
1054
+ font-size: var(--text-xs);
1055
+ font-weight: 700;
1056
+ letter-spacing: 0.12em;
1057
+ text-transform: uppercase;
1058
+ color: var(--accent);
1059
+ margin-bottom: var(--space-1);
1060
+ }
1061
+
1062
+ /* ───────────────────────────────────
1063
+ TAB PILLS
1064
+ ─────────────────────────────────── */
1065
+ .tab-pills {
1066
+ display: inline-flex;
1067
+ gap: 2px;
1068
+ padding: 3px;
1069
+ background: var(--glass-bg-subtle);
1070
+ backdrop-filter: blur(var(--glass-blur-sm));
1071
+ -webkit-backdrop-filter: blur(var(--glass-blur-sm));
1072
+ border: 1px solid var(--glass-border);
1073
+ border-radius: var(--radius-full);
1074
+ }
1075
+ .tab-pill {
1076
+ padding: 0.4rem 1rem;
1077
+ border: none;
1078
+ background: transparent;
1079
+ color: var(--text-secondary);
1080
+ font-family: var(--font-ui);
1081
+ font-size: var(--text-sm);
1082
+ font-weight: 600;
1083
+ border-radius: var(--radius-full);
1084
+ cursor: pointer;
1085
+ transition: all var(--duration-fast) var(--ease-out);
1086
+ white-space: nowrap;
1087
+ }
1088
+ .tab-pill:hover {
1089
+ color: var(--text-primary);
1090
+ background: var(--surface-4);
1091
+ }
1092
+ .tab-pill.is-active {
1093
+ background: var(--accent);
1094
+ color: #fff;
1095
+ box-shadow: 0 2px 8px rgba(96, 165, 250, 0.25);
1096
+ }
1097
+
1098
+ /* ───────────────────────────────────
1099
+ CHART CARD (glass)
1100
+ ─────────────────────────────────── */
1101
+ .chart-card {
1102
+ background: var(--glass-bg);
1103
+ backdrop-filter: blur(var(--glass-blur));
1104
+ -webkit-backdrop-filter: blur(var(--glass-blur));
1105
+ border: 1px solid var(--glass-border);
1106
+ box-shadow: var(--glass-shadow), var(--glass-inner);
1107
+ }