repo-wrapped 0.0.6 → 0.0.9

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 (176) hide show
  1. package/.github/agents/complete.agent.md +257 -0
  2. package/.github/agents/feature-scaffold.agent.md +248 -0
  3. package/.github/agents/jsdoc.agent.md +243 -0
  4. package/.github/agents/plan.agent.md +202 -0
  5. package/.github/agents/spec-writer.agent.md +169 -0
  6. package/.github/agents/test-writer.agent.md +169 -0
  7. package/.stylelintrc.json +27 -0
  8. package/README.md +94 -94
  9. package/coverage/base.css +224 -0
  10. package/coverage/block-navigation.js +87 -0
  11. package/coverage/favicon.png +0 -0
  12. package/coverage/index.html +446 -0
  13. package/coverage/lcov-report/base.css +224 -0
  14. package/coverage/lcov-report/block-navigation.js +87 -0
  15. package/coverage/lcov-report/favicon.png +0 -0
  16. package/coverage/lcov-report/index.html +446 -0
  17. package/coverage/lcov-report/prettify.css +1 -0
  18. package/coverage/lcov-report/prettify.js +2 -0
  19. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  20. package/coverage/lcov-report/sorter.js +210 -0
  21. package/coverage/lcov.info +7039 -0
  22. package/coverage/prettify.css +1 -0
  23. package/coverage/prettify.js +2 -0
  24. package/coverage/sort-arrow-sprite.png +0 -0
  25. package/coverage/sorter.js +210 -0
  26. package/dist/commands/generate.js +262 -5
  27. package/dist/config/defaults.js +158 -0
  28. package/dist/config/index.js +10 -0
  29. package/dist/features/achievements/data/achievements.json +284 -0
  30. package/dist/features/achievements/engine.js +140 -0
  31. package/dist/features/achievements/evaluators.js +246 -0
  32. package/dist/features/achievements/helpers.js +58 -0
  33. package/dist/features/achievements/index.js +57 -0
  34. package/dist/features/achievements/loader.js +88 -0
  35. package/dist/features/achievements/template.js +155 -0
  36. package/dist/features/achievements/types.js +7 -0
  37. package/dist/features/commit-quality/analyzer.js +378 -0
  38. package/dist/features/commit-quality/analyzer.test.js +484 -0
  39. package/dist/features/commit-quality/index.js +28 -0
  40. package/dist/features/commit-quality/template.js +114 -0
  41. package/dist/features/commit-quality/types.js +2 -0
  42. package/dist/features/comparison/analyzer.js +222 -0
  43. package/dist/features/comparison/index.js +28 -0
  44. package/dist/features/comparison/template.js +119 -0
  45. package/dist/features/comparison/types.js +2 -0
  46. package/dist/features/contribution-graph/index.js +9 -0
  47. package/dist/features/contribution-graph/template.js +89 -0
  48. package/dist/features/events/index.js +31 -0
  49. package/dist/features/events/parser.js +253 -0
  50. package/dist/features/events/template.js +113 -0
  51. package/dist/features/events/types.js +2 -0
  52. package/dist/features/executive-summary/generator.js +275 -0
  53. package/dist/features/executive-summary/index.js +27 -0
  54. package/dist/features/executive-summary/template.js +80 -0
  55. package/dist/features/executive-summary/types.js +2 -0
  56. package/dist/features/gaps/analyzer.js +298 -0
  57. package/dist/features/gaps/analyzer.test.js +517 -0
  58. package/dist/features/gaps/index.js +27 -0
  59. package/dist/features/gaps/template.js +190 -0
  60. package/dist/features/gaps/types.js +2 -0
  61. package/dist/features/impact/analyzer.js +248 -0
  62. package/dist/features/impact/index.js +26 -0
  63. package/dist/features/impact/template.js +118 -0
  64. package/dist/features/impact/types.js +2 -0
  65. package/dist/features/index.js +40 -0
  66. package/dist/features/knowledge/analyzer.js +385 -0
  67. package/dist/features/knowledge/index.js +26 -0
  68. package/dist/features/knowledge/template.js +239 -0
  69. package/dist/features/knowledge/types.js +2 -0
  70. package/dist/features/streaks/calculator.js +184 -0
  71. package/dist/features/streaks/calculator.test.js +366 -0
  72. package/dist/features/streaks/index.js +36 -0
  73. package/dist/features/streaks/template.js +41 -0
  74. package/dist/features/streaks/types.js +9 -0
  75. package/dist/features/team/analyzer.js +316 -0
  76. package/dist/features/team/index.js +30 -0
  77. package/dist/features/team/template.js +146 -0
  78. package/dist/features/team/types.js +2 -0
  79. package/dist/features/time-patterns/analyzer.js +319 -0
  80. package/dist/features/time-patterns/analyzer.test.js +278 -0
  81. package/dist/features/time-patterns/index.js +37 -0
  82. package/dist/features/time-patterns/template.js +109 -0
  83. package/dist/features/time-patterns/types.js +9 -0
  84. package/dist/features/velocity/analyzer.js +257 -0
  85. package/dist/features/velocity/analyzer.test.js +383 -0
  86. package/dist/features/velocity/index.js +27 -0
  87. package/dist/features/velocity/template.js +189 -0
  88. package/dist/features/velocity/types.js +2 -0
  89. package/dist/generators/html/scripts/knowledge.js +17 -0
  90. package/dist/generators/html/styles/base.css +10 -6
  91. package/dist/generators/html/styles/components.css +121 -1
  92. package/dist/generators/html/styles/knowledge.css +21 -0
  93. package/dist/generators/html/styles/leaddev.css +1335 -0
  94. package/dist/generators/html/styles/strategic-insights.css +1337 -0
  95. package/dist/generators/html/templates/commitQualitySection.js +28 -2
  96. package/dist/generators/html/templates/comparisonSection.js +119 -0
  97. package/dist/generators/html/templates/eventsSection.js +113 -0
  98. package/dist/generators/html/templates/executiveSummarySection.js +80 -0
  99. package/dist/generators/html/templates/gapSection.js +190 -0
  100. package/dist/generators/html/templates/impactSection.js +8 -6
  101. package/dist/generators/html/templates/knowledgeSection.js +16 -2
  102. package/dist/generators/html/templates/teamSection.js +146 -0
  103. package/dist/generators/html/templates/velocitySection.js +189 -0
  104. package/dist/generators/html/types.js +7 -0
  105. package/dist/generators/html/utils/analysisRunner.js +93 -0
  106. package/dist/generators/html/utils/cardBuilder.js +47 -0
  107. package/dist/generators/html/utils/contextBuilder.js +54 -0
  108. package/dist/generators/html/utils/htmlDocumentBuilder.js +396 -0
  109. package/dist/generators/html/utils/kpiBuilder.js +76 -0
  110. package/dist/generators/html/utils/sectionWrapper.js +71 -0
  111. package/dist/generators/html/utils/styleLoader.js +2 -1
  112. package/dist/html/analysisRunner.js +93 -0
  113. package/dist/html/htmlDocumentBuilder.js +396 -0
  114. package/dist/html/index.js +29 -0
  115. package/dist/html/shared/colorUtils.js +61 -0
  116. package/dist/html/shared/commitMapBuilder.js +23 -0
  117. package/dist/html/shared/components/cardBuilder.js +47 -0
  118. package/dist/html/shared/components/index.js +18 -0
  119. package/dist/html/shared/components/kpiBuilder.js +76 -0
  120. package/dist/html/shared/components/sectionWrapper.js +71 -0
  121. package/dist/html/shared/contextBuilder.js +54 -0
  122. package/dist/html/shared/dateRangeCalculator.js +56 -0
  123. package/dist/html/shared/developerStatsCalculator.js +28 -0
  124. package/dist/html/shared/index.js +39 -0
  125. package/dist/html/shared/scriptLoader.js +15 -0
  126. package/dist/html/shared/scripts/export.js +125 -0
  127. package/dist/html/shared/scripts/knowledge.js +137 -0
  128. package/dist/html/shared/scripts/modal.js +68 -0
  129. package/dist/html/shared/scripts/navigation.js +156 -0
  130. package/dist/html/shared/scripts/tabs.js +18 -0
  131. package/dist/html/shared/scripts/tooltip.js +21 -0
  132. package/dist/html/shared/styleLoader.js +18 -0
  133. package/dist/html/shared/styles/achievements.css +387 -0
  134. package/dist/html/shared/styles/base.css +822 -0
  135. package/dist/html/shared/styles/components.css +1511 -0
  136. package/dist/html/shared/styles/knowledge.css +242 -0
  137. package/dist/html/shared/styles/strategic-insights.css +1337 -0
  138. package/dist/html/shared/weekGrouper.js +27 -0
  139. package/dist/html/types.js +7 -0
  140. package/dist/index.js +54 -21
  141. package/dist/test/helpers/commitFactory.js +166 -0
  142. package/dist/test/helpers/dateUtils.js +101 -0
  143. package/dist/test/helpers/index.js +29 -0
  144. package/dist/test/setup.js +17 -0
  145. package/dist/test/smoke.test.js +94 -0
  146. package/dist/types/achievements.js +7 -0
  147. package/dist/types/analysis.js +7 -0
  148. package/dist/types/core.js +7 -0
  149. package/dist/types/index.js +38 -0
  150. package/dist/types/options.js +7 -0
  151. package/dist/types/shared.js +7 -0
  152. package/dist/types/strategic.js +7 -0
  153. package/dist/types/summary.js +7 -0
  154. package/dist/utils/achievementDefinitions.js +22 -22
  155. package/dist/utils/analyzerContextBuilder.js +124 -0
  156. package/dist/utils/commitQualityAnalyzer.js +13 -2
  157. package/dist/utils/emptyResults.js +95 -0
  158. package/dist/utils/eventAnnotationParser.js +253 -0
  159. package/dist/utils/executiveSummaryGenerator.js +275 -0
  160. package/dist/utils/fileHotspotAnalyzer.js +4 -12
  161. package/dist/utils/gapAnalyzer.js +298 -0
  162. package/dist/utils/gitParser.test.js +363 -0
  163. package/dist/utils/htmlGenerator.js +126 -450
  164. package/dist/utils/impactAnalyzer.js +20 -19
  165. package/dist/utils/knowledgeDistributionAnalyzer.js +32 -27
  166. package/dist/utils/matrixGenerator.js +13 -13
  167. package/dist/utils/rangeComparisonAnalyzer.js +222 -0
  168. package/dist/utils/streakCalculator.js +77 -27
  169. package/dist/utils/teamAnalyzer.js +316 -0
  170. package/dist/utils/timePatternAnalyzer.js +18 -3
  171. package/dist/utils/velocityAnalyzer.js +257 -0
  172. package/dist/utils/wrappedGenerator.js +8 -8
  173. package/package.json +74 -55
  174. package/vitest.config.ts +46 -0
  175. package/dist/cli.js +0 -24
  176. package/dist/commands/index.js +0 -24
@@ -0,0 +1,156 @@
1
+ // Navigation and Collapsible Sections
2
+ function initNavigation() {
3
+ // Sidebar navigation - tab switching
4
+ const sidebarNavItems = document.querySelectorAll('.sidebar .nav-item[data-tab]');
5
+ const tabButtons = document.querySelectorAll('.tab-button');
6
+ const tabContents = document.querySelectorAll('.tab-content');
7
+
8
+ // Handle sidebar nav clicks for tab switching
9
+ sidebarNavItems.forEach(item => {
10
+ item.addEventListener('click', (e) => {
11
+ e.preventDefault();
12
+ const targetTab = item.dataset.tab;
13
+
14
+ if (targetTab) {
15
+ // Update sidebar nav active state
16
+ sidebarNavItems.forEach(nav => nav.classList.remove('active'));
17
+ item.classList.add('active');
18
+
19
+ // Update tab button active state
20
+ tabButtons.forEach(btn => {
21
+ btn.classList.toggle('active', btn.dataset.tab === targetTab);
22
+ });
23
+
24
+ // Show target tab content
25
+ tabContents.forEach(content => {
26
+ content.classList.toggle('active', content.id === `${targetTab}-content`);
27
+ });
28
+ }
29
+ });
30
+ });
31
+
32
+ // Keep sidebar nav in sync when tab buttons are clicked
33
+ tabButtons.forEach(btn => {
34
+ btn.addEventListener('click', () => {
35
+ const targetTab = btn.dataset.tab;
36
+ sidebarNavItems.forEach(nav => {
37
+ nav.classList.toggle('active', nav.dataset.tab === targetTab);
38
+ });
39
+ });
40
+ });
41
+
42
+ // Quick jump links - handle tab switching and smooth scroll
43
+ const quickJumpLinks = document.querySelectorAll('.sidebar .nav-item-small[href^="#"]');
44
+ quickJumpLinks.forEach(link => {
45
+ link.addEventListener('click', (e) => {
46
+ e.preventDefault();
47
+ const href = link.getAttribute('href');
48
+ const targetTab = link.dataset.tab;
49
+
50
+ // If link specifies a tab, switch to it first
51
+ if (targetTab) {
52
+ // Update sidebar nav active state
53
+ sidebarNavItems.forEach(nav => nav.classList.remove('active'));
54
+ const tabNavItem = document.querySelector(`.sidebar .nav-item[data-tab="${targetTab}"]`);
55
+ if (tabNavItem) tabNavItem.classList.add('active');
56
+
57
+ // Update tab button active state
58
+ tabButtons.forEach(btn => {
59
+ btn.classList.toggle('active', btn.dataset.tab === targetTab);
60
+ });
61
+
62
+ // Show target tab content
63
+ tabContents.forEach(content => {
64
+ content.classList.toggle('active', content.id === `${targetTab}-content`);
65
+ });
66
+ }
67
+
68
+ // Scroll to section after a short delay to allow tab switch
69
+ setTimeout(() => {
70
+ const targetSection = document.querySelector(href);
71
+ if (targetSection) {
72
+ targetSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
73
+ }
74
+ }, targetTab ? 50 : 0);
75
+ });
76
+ });
77
+ }
78
+
79
+ // Collapsible sections
80
+ function initCollapsibleSections() {
81
+ const sectionHeaders = document.querySelectorAll('.section-header[role="button"]');
82
+
83
+ // Load saved states from localStorage
84
+ const savedStates = JSON.parse(localStorage.getItem('git-wrapped-sections') || '{}');
85
+
86
+ sectionHeaders.forEach(header => {
87
+ const section = header.closest('.dashboard-section');
88
+ const sectionId = section?.id;
89
+ const content = header.nextElementSibling;
90
+ const icon = header.querySelector('.collapse-icon');
91
+
92
+ // Restore saved state
93
+ if (sectionId && savedStates[sectionId] === false) {
94
+ content.classList.add('collapsed');
95
+ header.setAttribute('aria-expanded', 'false');
96
+ if (icon) icon.textContent = '▶';
97
+ }
98
+
99
+ header.addEventListener('click', () => {
100
+ const isExpanded = header.getAttribute('aria-expanded') !== 'false';
101
+ header.setAttribute('aria-expanded', !isExpanded);
102
+ content.classList.toggle('collapsed');
103
+
104
+ if (icon) {
105
+ icon.textContent = isExpanded ? '▶' : '▼';
106
+ }
107
+
108
+ // Save state
109
+ if (sectionId) {
110
+ savedStates[sectionId] = !isExpanded;
111
+ localStorage.setItem('git-wrapped-sections', JSON.stringify(savedStates));
112
+ }
113
+ });
114
+ });
115
+ }
116
+
117
+ // Mobile hamburger menu
118
+ function initMobileNav() {
119
+ const hamburger = document.querySelector('.mobile-nav-toggle');
120
+ const sidebar = document.querySelector('.sidebar');
121
+
122
+ if (hamburger && sidebar) {
123
+ hamburger.addEventListener('click', () => {
124
+ sidebar.classList.toggle('open');
125
+ hamburger.classList.toggle('open');
126
+ });
127
+
128
+ // Close sidebar when clicking outside on mobile
129
+ document.addEventListener('click', (e) => {
130
+ if (window.innerWidth <= 1024) {
131
+ if (!sidebar.contains(e.target) && !hamburger.contains(e.target)) {
132
+ sidebar.classList.remove('open');
133
+ hamburger.classList.remove('open');
134
+ }
135
+ }
136
+ });
137
+
138
+ // Close sidebar when clicking a nav item on mobile
139
+ const navItems = sidebar.querySelectorAll('.nav-item');
140
+ navItems.forEach(item => {
141
+ item.addEventListener('click', () => {
142
+ if (window.innerWidth <= 1024) {
143
+ sidebar.classList.remove('open');
144
+ hamburger.classList.remove('open');
145
+ }
146
+ });
147
+ });
148
+ }
149
+ }
150
+
151
+ // Initialize all navigation features
152
+ document.addEventListener('DOMContentLoaded', () => {
153
+ initNavigation();
154
+ initCollapsibleSections();
155
+ initMobileNav();
156
+ });
@@ -0,0 +1,18 @@
1
+ // Tab switching functionality
2
+ const tabButtons = document.querySelectorAll('.tab-button');
3
+ const tabContents = document.querySelectorAll('.tab-content');
4
+
5
+ tabButtons.forEach(button => {
6
+ button.addEventListener('click', () => {
7
+ const tabName = button.getAttribute('data-tab');
8
+
9
+ // Remove active class from all buttons and contents
10
+ tabButtons.forEach(btn => btn.classList.remove('active'));
11
+ tabContents.forEach(content => content.classList.remove('active'));
12
+
13
+ // Add active class to clicked button and corresponding content
14
+ button.classList.add('active');
15
+ const targetContent = document.getElementById(tabName + '-content');
16
+ if (targetContent) targetContent.classList.add('active');
17
+ });
18
+ });
@@ -0,0 +1,21 @@
1
+ // Tooltip functionality for contribution graph
2
+ const days = document.querySelectorAll('.day');
3
+ const tooltip = document.getElementById('tooltip');
4
+
5
+ days.forEach(day => {
6
+ day.addEventListener('mouseenter', (e) => {
7
+ const count = day.getAttribute('data-count');
8
+ const date = day.getAttribute('data-date');
9
+ tooltip.textContent = `${date}: ${count} contribution${count !== '1' ? 's' : ''}`;
10
+ tooltip.style.display = 'block';
11
+ });
12
+
13
+ day.addEventListener('mousemove', (e) => {
14
+ tooltip.style.left = (e.clientX + 10) + 'px';
15
+ tooltip.style.top = (e.clientY + 10) + 'px';
16
+ });
17
+
18
+ day.addEventListener('mouseleave', () => {
19
+ tooltip.style.display = 'none';
20
+ });
21
+ });
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadStyles = loadStyles;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ /**
7
+ * Loads all CSS files and returns them as a concatenated string
8
+ * for inlining in the HTML output
9
+ */
10
+ function loadStyles() {
11
+ const stylesDir = (0, path_1.join)(__dirname, 'styles');
12
+ const baseCSS = (0, fs_1.readFileSync)((0, path_1.join)(stylesDir, 'base.css'), 'utf-8');
13
+ const componentsCSS = (0, fs_1.readFileSync)((0, path_1.join)(stylesDir, 'components.css'), 'utf-8');
14
+ const achievementsCSS = (0, fs_1.readFileSync)((0, path_1.join)(stylesDir, 'achievements.css'), 'utf-8');
15
+ const knowledgeCSS = (0, fs_1.readFileSync)((0, path_1.join)(stylesDir, 'knowledge.css'), 'utf-8');
16
+ const strategicInsightsCSS = (0, fs_1.readFileSync)((0, path_1.join)(stylesDir, 'strategic-insights.css'), 'utf-8');
17
+ return `${baseCSS}\n\n${componentsCSS}\n\n${achievementsCSS}\n\n${knowledgeCSS}\n\n${strategicInsightsCSS}`;
18
+ }
@@ -0,0 +1,387 @@
1
+ /* === Achievements Section === */
2
+ .achievements-section {
3
+ margin-top: var(--spacing-xl);
4
+ padding-top: var(--spacing-lg);
5
+ border-top: 1px solid var(--border-default);
6
+ }
7
+
8
+ .achievements-section h2 {
9
+ font-size: var(--font-size-xl);
10
+ margin-bottom: var(--spacing-md);
11
+ color: var(--text-primary);
12
+ }
13
+
14
+ /* === Growth Narrative === */
15
+ .growth-narrative {
16
+ padding: var(--spacing-md);
17
+ background: var(--bg-primary);
18
+ border: 1px solid var(--border-default);
19
+ border-radius: var(--radius-md);
20
+ margin-bottom: var(--spacing-lg);
21
+ }
22
+
23
+ .growth-narrative h3 {
24
+ font-size: var(--font-size-md);
25
+ font-weight: var(--font-weight-semibold);
26
+ color: var(--text-primary);
27
+ margin-bottom: var(--spacing-sm);
28
+ }
29
+
30
+ .growth-narrative .narrative-text {
31
+ font-size: var(--font-size-sm);
32
+ color: var(--text-secondary);
33
+ line-height: 1.6;
34
+ }
35
+
36
+ .growth-narrative .narrative-text strong {
37
+ color: var(--text-primary);
38
+ font-weight: var(--font-weight-semibold);
39
+ }
40
+
41
+ .achievement-stats {
42
+ display: flex;
43
+ gap: var(--spacing-md);
44
+ margin-bottom: var(--spacing-lg);
45
+ flex-wrap: wrap;
46
+ }
47
+
48
+ .stat-card {
49
+ flex: 1;
50
+ min-width: 200px;
51
+ background: var(--bg-primary);
52
+ border: 1px solid var(--border-default);
53
+ border-radius: var(--radius-md);
54
+ padding: var(--spacing-md);
55
+ text-align: center;
56
+ }
57
+
58
+ .stat-value {
59
+ font-size: 32px;
60
+ font-weight: var(--font-weight-semibold);
61
+ color: var(--accent-gold);
62
+ margin-bottom: var(--spacing-xs);
63
+ }
64
+
65
+ .stat-label {
66
+ font-size: var(--font-size-sm);
67
+ color: var(--text-secondary);
68
+ text-transform: uppercase;
69
+ letter-spacing: 0.5px;
70
+ font-weight: var(--font-weight-medium);
71
+ }
72
+
73
+ /* === Progress Ring (SVG) === */
74
+ .progress-ring {
75
+ display: block;
76
+ }
77
+
78
+ .achievement-ring-wrapper {
79
+ position: absolute;
80
+ top: var(--spacing-sm);
81
+ right: var(--spacing-sm);
82
+ }
83
+
84
+ .achievement-ring-wrapper .progress-ring {
85
+ width: 40px;
86
+ height: 40px;
87
+ }
88
+
89
+ .achievement-progress-text {
90
+ font-size: var(--font-size-xs);
91
+ color: var(--text-muted);
92
+ margin-top: var(--spacing-xs);
93
+ }
94
+
95
+ .achievements-grid {
96
+ display: grid;
97
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
98
+ gap: var(--spacing-md);
99
+ margin-top: var(--spacing-md);
100
+ }
101
+
102
+ .achievement-card {
103
+ background: var(--bg-primary);
104
+ border: 1px solid var(--border-default);
105
+ border-radius: var(--radius-md);
106
+ padding: var(--spacing-md);
107
+ text-align: center;
108
+ transition: border-color var(--transition-fast);
109
+ position: relative;
110
+ }
111
+
112
+ .achievement-card.unlocked {
113
+ border-color: var(--accent-gold);
114
+ }
115
+
116
+ /* Subtle unlock animation */
117
+ @keyframes achievement-unlock {
118
+ 0% {
119
+ opacity: 0;
120
+ transform: scale(0.95);
121
+ }
122
+ 100% {
123
+ opacity: 1;
124
+ transform: scale(1);
125
+ }
126
+ }
127
+
128
+ .achievement-card.recently-unlocked {
129
+ animation: achievement-unlock 0.3s ease-out;
130
+ }
131
+
132
+ .achievement-card.unlocked:hover {
133
+ border-color: var(--accent-gold-muted);
134
+ }
135
+
136
+ .achievement-card.locked {
137
+ opacity: 0.6;
138
+ filter: grayscale(80%);
139
+ }
140
+
141
+ .badge-emoji {
142
+ font-size: 48px;
143
+ margin-bottom: var(--spacing-sm);
144
+ }
145
+
146
+ .badge-name {
147
+ font-size: var(--font-size-md);
148
+ font-weight: var(--font-weight-semibold);
149
+ color: var(--text-primary);
150
+ margin-bottom: var(--spacing-xs);
151
+ }
152
+
153
+ .badge-description {
154
+ font-size: var(--font-size-xs);
155
+ color: var(--text-secondary);
156
+ line-height: 1.4;
157
+ margin-bottom: var(--spacing-sm);
158
+ min-height: 32px;
159
+ }
160
+
161
+ .badge-tier {
162
+ display: inline-block;
163
+ padding: 3px var(--spacing-sm);
164
+ border-radius: var(--radius-md);
165
+ font-size: 10px;
166
+ font-weight: var(--font-weight-semibold);
167
+ text-transform: uppercase;
168
+ margin-top: var(--spacing-xs);
169
+ }
170
+
171
+ /* Muted Tier Colors */
172
+ .badge-tier.bronze { background: var(--tier-bronze); color: white; }
173
+ .badge-tier.silver { background: var(--tier-silver); color: var(--bg-primary); }
174
+ .badge-tier.gold { background: var(--tier-gold); color: var(--bg-primary); }
175
+ .badge-tier.platinum { background: var(--tier-platinum); color: var(--bg-primary); }
176
+ .badge-tier.legendary { background: var(--tier-legendary); color: white; }
177
+
178
+ .achievement-progress {
179
+ margin-top: var(--spacing-sm);
180
+ height: 4px;
181
+ background: var(--border-subtle);
182
+ border-radius: var(--radius-sm);
183
+ overflow: hidden;
184
+ }
185
+
186
+ .achievement-progress-fill {
187
+ height: 100%;
188
+ background: var(--accent-blue);
189
+ transition: width 0.5s;
190
+ }
191
+
192
+ /* === Next Milestones === */
193
+ .next-milestones {
194
+ margin-top: var(--spacing-lg);
195
+ padding: var(--spacing-md);
196
+ background: var(--bg-primary);
197
+ border: 1px solid var(--border-default);
198
+ border-radius: var(--radius-md);
199
+ }
200
+
201
+ .next-milestones h3 {
202
+ font-size: var(--font-size-lg);
203
+ color: var(--accent-gold);
204
+ margin-bottom: var(--spacing-md);
205
+ }
206
+
207
+ .milestone-item {
208
+ padding: var(--spacing-md);
209
+ background: var(--bg-secondary);
210
+ border-radius: var(--radius-md);
211
+ margin-bottom: var(--spacing-sm);
212
+ border-left: 3px solid var(--accent-gold);
213
+ }
214
+
215
+ .milestone-header {
216
+ display: flex;
217
+ align-items: center;
218
+ gap: var(--spacing-sm);
219
+ margin-bottom: var(--spacing-sm);
220
+ }
221
+
222
+ .milestone-emoji {
223
+ font-size: 24px;
224
+ }
225
+
226
+ .milestone-name {
227
+ font-size: var(--font-size-md);
228
+ font-weight: var(--font-weight-semibold);
229
+ color: var(--text-primary);
230
+ }
231
+
232
+ .milestone-description {
233
+ font-size: var(--font-size-sm);
234
+ color: var(--text-secondary);
235
+ margin-bottom: var(--spacing-sm);
236
+ line-height: 1.4;
237
+ }
238
+
239
+ .milestone-progress-bar {
240
+ height: 20px;
241
+ background: var(--border-subtle);
242
+ border-radius: var(--radius-lg);
243
+ overflow: hidden;
244
+ position: relative;
245
+ }
246
+
247
+ .milestone-progress-fill {
248
+ height: 100%;
249
+ background: var(--accent-green);
250
+ transition: width 0.5s;
251
+ }
252
+
253
+ .milestone-progress-text {
254
+ position: absolute;
255
+ top: 50%;
256
+ left: 50%;
257
+ transform: translate(-50%, -50%);
258
+ font-size: var(--font-size-xs);
259
+ font-weight: var(--font-weight-semibold);
260
+ color: white;
261
+ text-shadow: 0 1px 2px rgba(0,0,0,0.5);
262
+ }
263
+
264
+ /* === Achievement Categories === */
265
+ .achievement-categories {
266
+ margin-top: var(--spacing-lg);
267
+ }
268
+
269
+ .category-section {
270
+ margin-bottom: var(--spacing-lg);
271
+ padding: var(--spacing-md);
272
+ background: var(--bg-primary);
273
+ border: 1px solid var(--border-default);
274
+ border-radius: var(--radius-md);
275
+ }
276
+
277
+ .category-section h3 {
278
+ font-size: var(--font-size-lg);
279
+ color: var(--text-primary);
280
+ margin-bottom: var(--spacing-md);
281
+ }
282
+
283
+ .category-progress {
284
+ display: flex;
285
+ align-items: center;
286
+ gap: var(--spacing-sm);
287
+ margin-bottom: var(--spacing-md);
288
+ }
289
+
290
+ .category-bar {
291
+ flex: 1;
292
+ height: 8px;
293
+ background: var(--border-subtle);
294
+ border-radius: var(--radius-md);
295
+ overflow: hidden;
296
+ }
297
+
298
+ .category-fill {
299
+ height: 100%;
300
+ background: var(--accent-gold);
301
+ transition: width 0.5s;
302
+ }
303
+
304
+ .category-count {
305
+ font-size: var(--font-size-sm);
306
+ color: var(--text-secondary);
307
+ font-weight: var(--font-weight-semibold);
308
+ }
309
+
310
+ .achievement-grid {
311
+ display: grid;
312
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
313
+ gap: var(--spacing-sm);
314
+ }
315
+
316
+ .achievement-item {
317
+ background: var(--bg-secondary);
318
+ border: 1px solid var(--border-default);
319
+ border-radius: var(--radius-md);
320
+ padding: var(--spacing-sm);
321
+ text-align: center;
322
+ transition: border-color var(--transition-fast);
323
+ position: relative;
324
+ }
325
+
326
+ .achievement-item.unlocked {
327
+ border-color: var(--accent-gold);
328
+ }
329
+
330
+ .achievement-item.unlocked:hover {
331
+ border-color: var(--accent-gold-muted);
332
+ }
333
+
334
+ .achievement-item.locked {
335
+ opacity: 0.6;
336
+ filter: grayscale(80%);
337
+ }
338
+
339
+ .achievement-emoji {
340
+ font-size: 36px;
341
+ margin-bottom: var(--spacing-sm);
342
+ }
343
+
344
+ .achievement-name {
345
+ font-size: var(--font-size-sm);
346
+ font-weight: var(--font-weight-semibold);
347
+ color: var(--text-primary);
348
+ margin-bottom: var(--spacing-xs);
349
+ }
350
+
351
+ .achievement-description {
352
+ font-size: 10px;
353
+ color: var(--text-secondary);
354
+ line-height: 1.3;
355
+ min-height: 26px;
356
+ }
357
+
358
+ /* === New Badges === */
359
+ .new-badges {
360
+ margin-top: var(--spacing-md);
361
+ padding: var(--spacing-md);
362
+ background: var(--bg-secondary);
363
+ border: 1px solid var(--border-default);
364
+ border-radius: var(--radius-md);
365
+ border-left: 3px solid var(--accent-gold);
366
+ }
367
+
368
+ .new-badges h3 {
369
+ font-size: var(--font-size-md);
370
+ color: var(--accent-gold);
371
+ margin-bottom: var(--spacing-sm);
372
+ }
373
+
374
+ .badge-list {
375
+ display: flex;
376
+ gap: var(--spacing-sm);
377
+ flex-wrap: wrap;
378
+ }
379
+
380
+ .badge-item-mini {
381
+ background: var(--bg-primary);
382
+ border: 1px solid var(--accent-gold);
383
+ border-radius: 20px;
384
+ padding: var(--spacing-xs) var(--spacing-sm);
385
+ font-size: var(--font-size-sm);
386
+ color: var(--text-primary);
387
+ }