monol-plugin-scout 2.1.3 → 4.1.0

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 (87) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +244 -0
  3. package/monol-plugin-scout-pkg/CLAUDE.md +125 -8
  4. package/monol-plugin-scout-pkg/api/mock/categories.json +81 -0
  5. package/monol-plugin-scout-pkg/api/mock/insights.json +111 -0
  6. package/monol-plugin-scout-pkg/api/mock/marketplace.json +501 -0
  7. package/monol-plugin-scout-pkg/api/mock/trending.json +96 -0
  8. package/monol-plugin-scout-pkg/commands/console.md +79 -0
  9. package/monol-plugin-scout-pkg/commands/frequency.md +32 -0
  10. package/monol-plugin-scout-pkg/commands/install.md +32 -0
  11. package/monol-plugin-scout-pkg/commands/priority.md +30 -0
  12. package/monol-plugin-scout-pkg/commands/quiet.md +32 -0
  13. package/monol-plugin-scout-pkg/commands/schedule.md +32 -0
  14. package/monol-plugin-scout-pkg/commands/scout.md +8 -5
  15. package/monol-plugin-scout-pkg/commands/skills.md +160 -0
  16. package/monol-plugin-scout-pkg/commands/team.md +32 -0
  17. package/monol-plugin-scout-pkg/commands/timing.md +32 -0
  18. package/monol-plugin-scout-pkg/commands/trust.md +85 -0
  19. package/monol-plugin-scout-pkg/commands/trusted-install.md +98 -0
  20. package/monol-plugin-scout-pkg/commands/uninstall.md +31 -0
  21. package/monol-plugin-scout-pkg/config.yaml +57 -0
  22. package/monol-plugin-scout-pkg/data/.cache/676d5ab664292155e5f509c69d4edae1 +10 -0
  23. package/monol-plugin-scout-pkg/data/.session +8 -0
  24. package/monol-plugin-scout-pkg/data/analytics.json +102 -0
  25. package/monol-plugin-scout-pkg/data/history.json +67 -11
  26. package/monol-plugin-scout-pkg/data/logs/scout.log +1 -0
  27. package/monol-plugin-scout-pkg/data/schedules.json +17 -0
  28. package/monol-plugin-scout-pkg/data/team.json +53 -0
  29. package/monol-plugin-scout-pkg/data/usage.json +100 -7
  30. package/monol-plugin-scout-pkg/docs/ARCHITECTURE.md +201 -0
  31. package/monol-plugin-scout-pkg/hooks/generate-insights.sh +102 -0
  32. package/monol-plugin-scout-pkg/hooks/hooks.json +36 -1
  33. package/monol-plugin-scout-pkg/hooks/on-session-end.sh +136 -0
  34. package/monol-plugin-scout-pkg/hooks/on-session-start.sh +43 -0
  35. package/monol-plugin-scout-pkg/hooks/on-stop.md +79 -0
  36. package/monol-plugin-scout-pkg/hooks/open-console.sh +111 -0
  37. package/monol-plugin-scout-pkg/hooks/open-dashboard.sh +61 -0
  38. package/monol-plugin-scout-pkg/hooks/track-usage.sh +59 -0
  39. package/monol-plugin-scout-pkg/lib/ai-recommender.sh +505 -0
  40. package/monol-plugin-scout-pkg/lib/cache.sh +194 -0
  41. package/monol-plugin-scout-pkg/lib/data-validator.sh +360 -0
  42. package/monol-plugin-scout-pkg/lib/error-handler.sh +296 -0
  43. package/monol-plugin-scout-pkg/lib/logger.sh +263 -0
  44. package/monol-plugin-scout-pkg/lib/plugin-manager.sh +239 -0
  45. package/monol-plugin-scout-pkg/lib/priority-scorer.sh +262 -0
  46. package/monol-plugin-scout-pkg/lib/profile-learner.sh +339 -0
  47. package/monol-plugin-scout-pkg/lib/project-analyzer.sh +281 -0
  48. package/monol-plugin-scout-pkg/lib/recommendation-controller.sh +290 -0
  49. package/monol-plugin-scout-pkg/lib/rejection-learner.sh +232 -0
  50. package/monol-plugin-scout-pkg/lib/scheduler.sh +275 -0
  51. package/monol-plugin-scout-pkg/lib/skill-scout.sh +729 -0
  52. package/monol-plugin-scout-pkg/lib/sync.sh +221 -0
  53. package/monol-plugin-scout-pkg/lib/team-learner.sh +450 -0
  54. package/monol-plugin-scout-pkg/lib/team-manager.sh +369 -0
  55. package/monol-plugin-scout-pkg/lib/trend-learner.sh +428 -0
  56. package/monol-plugin-scout-pkg/lib/trust-manager.sh +261 -0
  57. package/monol-plugin-scout-pkg/lib/trusted-installer.sh +738 -0
  58. package/monol-plugin-scout-pkg/plugin.json +3 -2
  59. package/monol-plugin-scout-pkg/skills/audit.md +6 -0
  60. package/monol-plugin-scout-pkg/skills/cleanup.md +6 -0
  61. package/monol-plugin-scout-pkg/skills/compare.md +6 -0
  62. package/monol-plugin-scout-pkg/skills/console.md +315 -0
  63. package/monol-plugin-scout-pkg/skills/explore.md +6 -0
  64. package/monol-plugin-scout-pkg/skills/fork.md +6 -0
  65. package/monol-plugin-scout-pkg/skills/frequency.md +93 -0
  66. package/monol-plugin-scout-pkg/skills/install.md +127 -0
  67. package/monol-plugin-scout-pkg/skills/priority.md +77 -0
  68. package/monol-plugin-scout-pkg/skills/quiet.md +73 -0
  69. package/monol-plugin-scout-pkg/skills/schedule.md +95 -0
  70. package/monol-plugin-scout-pkg/skills/scout.md +27 -17
  71. package/monol-plugin-scout-pkg/skills/skills.md +230 -0
  72. package/monol-plugin-scout-pkg/skills/team.md +117 -0
  73. package/monol-plugin-scout-pkg/skills/timing.md +97 -0
  74. package/monol-plugin-scout-pkg/skills/trust.md +120 -0
  75. package/monol-plugin-scout-pkg/skills/trusted-install.md +264 -0
  76. package/monol-plugin-scout-pkg/skills/uninstall.md +100 -0
  77. package/monol-plugin-scout-pkg/web/components/activity-chart.js +208 -0
  78. package/monol-plugin-scout-pkg/web/components/index.js +27 -0
  79. package/monol-plugin-scout-pkg/web/components/insight-card.js +365 -0
  80. package/monol-plugin-scout-pkg/web/components/overview.js +154 -0
  81. package/monol-plugin-scout-pkg/web/components/plugin-list.js +242 -0
  82. package/monol-plugin-scout-pkg/web/components/stats-card.js +126 -0
  83. package/monol-plugin-scout-pkg/web/components/team-list.js +346 -0
  84. package/monol-plugin-scout-pkg/web/console.html +2098 -0
  85. package/monol-plugin-scout-pkg/web/dashboard.html +2106 -0
  86. package/monol-plugin-scout-pkg/web/manifest.json +29 -0
  87. package/package.json +1 -1
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Scout Overview Component
3
+ * 오버뷰 탭 - 다른 컴포넌트들을 조합
4
+ */
5
+
6
+ import { MonolComponent } from '/design-system/component-base.js';
7
+ import { ScoutStatsCard } from './stats-card.js';
8
+ import { ScoutPluginList } from './plugin-list.js';
9
+ import { ScoutActivityChart } from './activity-chart.js';
10
+
11
+ export class ScoutOverview extends MonolComponent {
12
+ constructor(container, options = {}) {
13
+ super(container, options);
14
+ this.components = {};
15
+ }
16
+
17
+ async init() {
18
+ this.render();
19
+ await this.initComponents();
20
+ }
21
+
22
+ render() {
23
+ this.container.innerHTML = this.html`
24
+ <div class="scout-overview">
25
+ <div class="overview-section">
26
+ <div id="scout-stats-container"></div>
27
+ </div>
28
+
29
+ <div class="overview-grid">
30
+ <div class="overview-main">
31
+ <div id="scout-chart-container"></div>
32
+ </div>
33
+ <div class="overview-sidebar">
34
+ <h3 class="section-title">Installed Plugins</h3>
35
+ <div id="scout-plugins-container"></div>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ `;
40
+ }
41
+
42
+ async initComponents() {
43
+ // Stats Card
44
+ this.components.stats = new ScoutStatsCard(
45
+ this.container.querySelector('#scout-stats-container'),
46
+ {
47
+ apiUrl: this.options.apiBaseUrl ? `${this.options.apiBaseUrl}/stats` : null,
48
+ stats: this.options.stats || { installed: 12, active: 8, score: 85, updates: 3 }
49
+ }
50
+ );
51
+ await this.components.stats.init();
52
+
53
+ // Activity Chart
54
+ this.components.chart = new ScoutActivityChart(
55
+ this.container.querySelector('#scout-chart-container'),
56
+ {
57
+ id: 'overview-activity',
58
+ title: 'Plugin Activity',
59
+ apiUrl: this.options.apiBaseUrl ? `${this.options.apiBaseUrl}/activity` : null
60
+ }
61
+ );
62
+ await this.components.chart.init();
63
+
64
+ // Plugin List
65
+ this.components.plugins = new ScoutPluginList(
66
+ this.container.querySelector('#scout-plugins-container'),
67
+ {
68
+ apiUrl: this.options.apiBaseUrl ? `${this.options.apiBaseUrl}/plugins` : null,
69
+ plugins: this.options.plugins || this.getMockPlugins()
70
+ }
71
+ );
72
+ await this.components.plugins.init();
73
+
74
+ // 컴포넌트 간 이벤트 연결
75
+ this.setupEventHandlers();
76
+ }
77
+
78
+ setupEventHandlers() {
79
+ // 플러그인 선택 시 이벤트 발행
80
+ this.components.plugins.on('plugin-select', (plugin) => {
81
+ this.emit('plugin-select', plugin);
82
+ });
83
+
84
+ // Stats 클릭 시 필터 적용
85
+ this.components.stats.on('stat-click', ({ type }) => {
86
+ if (type === 'active') {
87
+ this.components.plugins.state.filter = 'active';
88
+ this.components.plugins.render();
89
+ }
90
+ });
91
+ }
92
+
93
+ getMockPlugins() {
94
+ return [
95
+ { id: 'code-review', name: 'Code Review', icon: '🔍', version: '1.2.0', status: 'active', score: 92 },
96
+ { id: 'git-helper', name: 'Git Helper', icon: '📦', version: '2.0.1', status: 'active', score: 88 },
97
+ { id: 'test-runner', name: 'Test Runner', icon: '🧪', version: '1.5.0', status: 'active', score: 85 },
98
+ { id: 'doc-gen', name: 'Doc Generator', icon: '📝', version: '1.0.0', status: 'inactive', score: 78 },
99
+ { id: 'lint-fixer', name: 'Lint Fixer', icon: '✨', version: '1.1.0', status: 'active', score: 90 }
100
+ ];
101
+ }
102
+
103
+ // 외부에서 호출 가능한 메서드들
104
+ refreshStats() {
105
+ this.components.stats.fetchStats();
106
+ }
107
+
108
+ highlightPlugin(pluginId) {
109
+ this.components.plugins.selectPlugin(pluginId);
110
+ }
111
+
112
+ getSelectedPlugin() {
113
+ const id = this.components.plugins.state.selectedId;
114
+ return this.components.plugins.state.plugins.find(p => p.id === id);
115
+ }
116
+
117
+ destroy() {
118
+ Object.values(this.components).forEach(c => c.destroy());
119
+ super.destroy();
120
+ }
121
+ }
122
+
123
+ // CSS 스타일
124
+ const style = document.createElement('style');
125
+ style.textContent = `
126
+ .scout-overview {
127
+ display: flex;
128
+ flex-direction: column;
129
+ gap: 24px;
130
+ padding: 24px;
131
+ }
132
+ .scout-overview .overview-section {
133
+ margin-bottom: 8px;
134
+ }
135
+ .scout-overview .overview-grid {
136
+ display: grid;
137
+ grid-template-columns: 1fr 350px;
138
+ gap: 24px;
139
+ }
140
+ .scout-overview .section-title {
141
+ font-size: 14px;
142
+ font-weight: 600;
143
+ color: var(--text-primary);
144
+ margin-bottom: 12px;
145
+ }
146
+ @media (max-width: 1024px) {
147
+ .scout-overview .overview-grid {
148
+ grid-template-columns: 1fr;
149
+ }
150
+ }
151
+ `;
152
+ document.head.appendChild(style);
153
+
154
+ export default ScoutOverview;
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Scout Plugin List Component
3
+ * 설치된 플러그인 목록을 표시하는 컴포넌트
4
+ */
5
+
6
+ import { MonolComponent } from '/design-system/component-base.js';
7
+
8
+ export class ScoutPluginList extends MonolComponent {
9
+ constructor(container, options = {}) {
10
+ super(container, options);
11
+ this.state = {
12
+ plugins: options.plugins || [],
13
+ filter: 'all',
14
+ sortBy: 'name',
15
+ selectedId: null
16
+ };
17
+ }
18
+
19
+ async init() {
20
+ if (this.options.apiUrl) {
21
+ await this.fetchPlugins();
22
+ }
23
+ this.render();
24
+ }
25
+
26
+ async fetchPlugins() {
27
+ try {
28
+ const response = await fetch(this.options.apiUrl);
29
+ const data = await response.json();
30
+ this.state.plugins = data;
31
+ } catch (error) {
32
+ console.error('Failed to fetch plugins:', error);
33
+ }
34
+ }
35
+
36
+ getFilteredPlugins() {
37
+ let plugins = [...this.state.plugins];
38
+
39
+ // 필터 적용
40
+ if (this.state.filter !== 'all') {
41
+ plugins = plugins.filter(p => p.status === this.state.filter);
42
+ }
43
+
44
+ // 정렬 적용
45
+ plugins.sort((a, b) => {
46
+ switch (this.state.sortBy) {
47
+ case 'score': return (b.score || 0) - (a.score || 0);
48
+ case 'usage': return (b.usage || 0) - (a.usage || 0);
49
+ default: return (a.name || '').localeCompare(b.name || '');
50
+ }
51
+ });
52
+
53
+ return plugins;
54
+ }
55
+
56
+ render() {
57
+ const plugins = this.getFilteredPlugins();
58
+
59
+ this.container.innerHTML = this.html`
60
+ <div class="scout-plugin-list">
61
+ <div class="list-header">
62
+ <div class="list-filters">
63
+ <select class="filter-select" data-action="filter">
64
+ <option value="all" ${this.state.filter === 'all' ? 'selected' : ''}>All</option>
65
+ <option value="active" ${this.state.filter === 'active' ? 'selected' : ''}>Active</option>
66
+ <option value="inactive" ${this.state.filter === 'inactive' ? 'selected' : ''}>Inactive</option>
67
+ </select>
68
+ <select class="sort-select" data-action="sort">
69
+ <option value="name" ${this.state.sortBy === 'name' ? 'selected' : ''}>Name</option>
70
+ <option value="score" ${this.state.sortBy === 'score' ? 'selected' : ''}>Score</option>
71
+ <option value="usage" ${this.state.sortBy === 'usage' ? 'selected' : ''}>Usage</option>
72
+ </select>
73
+ </div>
74
+ <span class="list-count">${plugins.length} plugins</span>
75
+ </div>
76
+ <div class="list-items">
77
+ ${plugins.map(plugin => this.renderPlugin(plugin)).join('')}
78
+ </div>
79
+ </div>
80
+ `;
81
+
82
+ this.bindEvents();
83
+ }
84
+
85
+ renderPlugin(plugin) {
86
+ const isSelected = this.state.selectedId === plugin.id;
87
+ const scoreColor = this.getScoreColor(plugin.score);
88
+
89
+ return this.html`
90
+ <div class="plugin-item ${isSelected ? 'selected' : ''}" data-id="${plugin.id}">
91
+ <div class="plugin-icon">${plugin.icon || '🔌'}</div>
92
+ <div class="plugin-info">
93
+ <div class="plugin-name">${plugin.name}</div>
94
+ <div class="plugin-meta">
95
+ <span class="plugin-version">v${plugin.version || '1.0.0'}</span>
96
+ <span class="plugin-status ${plugin.status}">${plugin.status || 'unknown'}</span>
97
+ </div>
98
+ </div>
99
+ <div class="plugin-score" style="color: ${scoreColor}">
100
+ ${plugin.score || '-'}
101
+ </div>
102
+ </div>
103
+ `;
104
+ }
105
+
106
+ getScoreColor(score) {
107
+ if (!score) return 'var(--text-muted)';
108
+ if (score >= 90) return 'var(--accent-green)';
109
+ if (score >= 75) return 'var(--accent-blue)';
110
+ if (score >= 60) return 'var(--accent-orange)';
111
+ return 'var(--accent-red)';
112
+ }
113
+
114
+ bindEvents() {
115
+ // 필터 변경
116
+ this.container.querySelector('[data-action="filter"]')?.addEventListener('change', (e) => {
117
+ this.state.filter = e.target.value;
118
+ this.render();
119
+ this.emit('filter-change', { filter: this.state.filter });
120
+ });
121
+
122
+ // 정렬 변경
123
+ this.container.querySelector('[data-action="sort"]')?.addEventListener('change', (e) => {
124
+ this.state.sortBy = e.target.value;
125
+ this.render();
126
+ this.emit('sort-change', { sortBy: this.state.sortBy });
127
+ });
128
+
129
+ // 플러그인 선택
130
+ this.container.querySelectorAll('.plugin-item').forEach(item => {
131
+ item.addEventListener('click', () => {
132
+ const id = item.dataset.id;
133
+ this.state.selectedId = id;
134
+ const plugin = this.state.plugins.find(p => p.id === id);
135
+ this.render();
136
+ this.emit('plugin-select', plugin);
137
+ });
138
+ });
139
+ }
140
+
141
+ selectPlugin(id) {
142
+ this.state.selectedId = id;
143
+ this.render();
144
+ }
145
+
146
+ highlightPlugins(ids) {
147
+ this.container.querySelectorAll('.plugin-item').forEach(item => {
148
+ if (ids.includes(item.dataset.id)) {
149
+ item.classList.add('highlighted');
150
+ } else {
151
+ item.classList.remove('highlighted');
152
+ }
153
+ });
154
+ }
155
+ }
156
+
157
+ // CSS 스타일
158
+ const style = document.createElement('style');
159
+ style.textContent = `
160
+ .scout-plugin-list {
161
+ background: var(--bg-secondary);
162
+ border: 1px solid var(--border-color);
163
+ border-radius: var(--radius-md, 8px);
164
+ overflow: hidden;
165
+ }
166
+ .scout-plugin-list .list-header {
167
+ display: flex;
168
+ justify-content: space-between;
169
+ align-items: center;
170
+ padding: 12px 16px;
171
+ border-bottom: 1px solid var(--border-color);
172
+ background: var(--bg-tertiary);
173
+ }
174
+ .scout-plugin-list .list-filters {
175
+ display: flex;
176
+ gap: 8px;
177
+ }
178
+ .scout-plugin-list select {
179
+ padding: 6px 10px;
180
+ background: var(--bg-secondary);
181
+ border: 1px solid var(--border-color);
182
+ border-radius: 6px;
183
+ color: var(--text-primary);
184
+ font-size: 12px;
185
+ }
186
+ .scout-plugin-list .list-count {
187
+ font-size: 12px;
188
+ color: var(--text-secondary);
189
+ }
190
+ .scout-plugin-list .list-items {
191
+ max-height: 400px;
192
+ overflow-y: auto;
193
+ }
194
+ .scout-plugin-list .plugin-item {
195
+ display: flex;
196
+ align-items: center;
197
+ gap: 12px;
198
+ padding: 12px 16px;
199
+ border-bottom: 1px solid var(--border-color);
200
+ cursor: pointer;
201
+ transition: background 0.2s;
202
+ }
203
+ .scout-plugin-list .plugin-item:hover {
204
+ background: var(--bg-hover);
205
+ }
206
+ .scout-plugin-list .plugin-item.selected {
207
+ background: var(--bg-active, rgba(56, 139, 253, 0.1));
208
+ border-left: 3px solid var(--accent-blue);
209
+ }
210
+ .scout-plugin-list .plugin-item.highlighted {
211
+ background: var(--bg-active, rgba(56, 139, 253, 0.1));
212
+ }
213
+ .scout-plugin-list .plugin-icon {
214
+ font-size: 20px;
215
+ }
216
+ .scout-plugin-list .plugin-info {
217
+ flex: 1;
218
+ }
219
+ .scout-plugin-list .plugin-name {
220
+ font-weight: 500;
221
+ color: var(--text-primary);
222
+ }
223
+ .scout-plugin-list .plugin-meta {
224
+ display: flex;
225
+ gap: 8px;
226
+ font-size: 11px;
227
+ color: var(--text-secondary);
228
+ }
229
+ .scout-plugin-list .plugin-status.active {
230
+ color: var(--accent-green);
231
+ }
232
+ .scout-plugin-list .plugin-status.inactive {
233
+ color: var(--text-muted);
234
+ }
235
+ .scout-plugin-list .plugin-score {
236
+ font-size: 18px;
237
+ font-weight: 700;
238
+ }
239
+ `;
240
+ document.head.appendChild(style);
241
+
242
+ export default ScoutPluginList;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Scout Stats Card Component
3
+ * 플러그인 통계를 표시하는 카드 컴포넌트
4
+ */
5
+
6
+ import { MonolComponent } from '/design-system/component-base.js';
7
+
8
+ export class ScoutStatsCard extends MonolComponent {
9
+ constructor(container, options = {}) {
10
+ super(container, options);
11
+ this.state = {
12
+ stats: options.stats || {
13
+ installed: 0,
14
+ active: 0,
15
+ score: 0,
16
+ updates: 0
17
+ }
18
+ };
19
+ }
20
+
21
+ async init() {
22
+ if (this.options.apiUrl) {
23
+ await this.fetchStats();
24
+ }
25
+ this.render();
26
+ }
27
+
28
+ async fetchStats() {
29
+ try {
30
+ const response = await fetch(this.options.apiUrl);
31
+ const data = await response.json();
32
+ this.state.stats = data;
33
+ } catch (error) {
34
+ console.error('Failed to fetch stats:', error);
35
+ }
36
+ }
37
+
38
+ render() {
39
+ const { stats } = this.state;
40
+
41
+ this.container.innerHTML = this.html`
42
+ <div class="scout-stats-grid">
43
+ <div class="stat-card" data-stat="installed">
44
+ <div class="stat-icon">🔌</div>
45
+ <div class="stat-content">
46
+ <div class="stat-value">${stats.installed}</div>
47
+ <div class="stat-label">Installed</div>
48
+ </div>
49
+ </div>
50
+ <div class="stat-card" data-stat="active">
51
+ <div class="stat-icon">✅</div>
52
+ <div class="stat-content">
53
+ <div class="stat-value">${stats.active}</div>
54
+ <div class="stat-label">Active</div>
55
+ </div>
56
+ </div>
57
+ <div class="stat-card" data-stat="score">
58
+ <div class="stat-icon">⭐</div>
59
+ <div class="stat-content">
60
+ <div class="stat-value">${stats.score}</div>
61
+ <div class="stat-label">Avg Score</div>
62
+ </div>
63
+ </div>
64
+ <div class="stat-card" data-stat="updates">
65
+ <div class="stat-icon">🔄</div>
66
+ <div class="stat-content">
67
+ <div class="stat-value">${stats.updates}</div>
68
+ <div class="stat-label">Updates</div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ `;
73
+
74
+ // 클릭 이벤트 바인딩
75
+ this.container.querySelectorAll('.stat-card').forEach(card => {
76
+ card.addEventListener('click', () => {
77
+ const statType = card.dataset.stat;
78
+ this.emit('stat-click', { type: statType, value: stats[statType] });
79
+ });
80
+ });
81
+ }
82
+
83
+ updateStats(newStats) {
84
+ this.setState({ stats: { ...this.state.stats, ...newStats } });
85
+ }
86
+ }
87
+
88
+ // CSS 스타일 (컴포넌트 전용)
89
+ const style = document.createElement('style');
90
+ style.textContent = `
91
+ .scout-stats-grid {
92
+ display: grid;
93
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
94
+ gap: 16px;
95
+ }
96
+ .scout-stats-grid .stat-card {
97
+ display: flex;
98
+ align-items: center;
99
+ gap: 12px;
100
+ padding: 16px;
101
+ background: var(--bg-secondary);
102
+ border: 1px solid var(--border-color);
103
+ border-radius: var(--radius-md, 8px);
104
+ cursor: pointer;
105
+ transition: all 0.2s;
106
+ }
107
+ .scout-stats-grid .stat-card:hover {
108
+ border-color: var(--accent-blue);
109
+ transform: translateY(-2px);
110
+ }
111
+ .scout-stats-grid .stat-icon {
112
+ font-size: 24px;
113
+ }
114
+ .scout-stats-grid .stat-value {
115
+ font-size: 24px;
116
+ font-weight: 700;
117
+ color: var(--text-primary);
118
+ }
119
+ .scout-stats-grid .stat-label {
120
+ font-size: 12px;
121
+ color: var(--text-secondary);
122
+ }
123
+ `;
124
+ document.head.appendChild(style);
125
+
126
+ export default ScoutStatsCard;