sillyspec 3.7.9 → 3.7.11

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.
@@ -3,7 +3,7 @@
3
3
  <!-- Header -->
4
4
  <div class="px-6 pt-6 pb-4" style="border-bottom: 1px solid #1F1F22;">
5
5
  <h2 class="text-[11px] font-semibold uppercase tracking-[0.2em] font-[JetBrains_Mono,monospace]" style="color: #525252;">
6
- Pipeline
6
+ 项目流水线
7
7
  </h2>
8
8
  <p v-if="project" class="text-[12px] mt-1.5 font-[JetBrains_Mono,monospace]" style="color: #8B8B8E;">
9
9
  {{ project.name }} <span style="color: #2A2A2D;">/</span> <span style="color: #FBBF24;">{{ currentStage }}</span>
@@ -20,25 +20,25 @@
20
20
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
21
21
  </svg>
22
22
  </div>
23
- <p class="text-[12px] font-[JetBrains_Mono,monospace]" style="color: #525252;">Select a project</p>
23
+ <p class="text-[12px] font-[JetBrains_Mono,monospace]" style="color: #525252;">选择一个项目查看流水线</p>
24
24
  </div>
25
25
  </div>
26
26
 
27
27
  <div v-else class="space-y-5">
28
- <PipelineStage name="brainstorm" title="BRAINSTORM" :steps="getStageSteps('brainstorm')" :status="getStageStatus('brainstorm')" :is-active="currentStage === 'brainstorm'" :active-step="activeStep" @select-step="handleSelectStep" />
28
+ <PipelineStage name="brainstorm" title="头脑风暴" :steps="getStageSteps('brainstorm')" :status="getStageStatus('brainstorm')" :is-active="currentStage === 'brainstorm'" :active-step="activeStep" @select-step="handleSelectStep" />
29
29
  <div v-if="hasStage('plan')" class="flex items-center pl-[3px]"><div class="w-px h-4" style="background: #1F1F22;" /></div>
30
- <PipelineStage name="plan" title="PLAN" :steps="getStageSteps('plan')" :status="getStageStatus('plan')" :is-active="currentStage === 'plan'" :active-step="activeStep" @select-step="handleSelectStep" />
30
+ <PipelineStage name="plan" title="规划" :steps="getStageSteps('plan')" :status="getStageStatus('plan')" :is-active="currentStage === 'plan'" :active-step="activeStep" @select-step="handleSelectStep" />
31
31
  <div v-if="hasStage('execute')" class="flex items-center pl-[3px]"><div class="w-px h-4" style="background: #1F1F22;" /></div>
32
- <PipelineStage name="execute" title="EXECUTE" :steps="getStageSteps('execute')" :status="getStageStatus('execute')" :is-active="currentStage === 'execute'" :active-step="activeStep" @select-step="handleSelectStep" />
32
+ <PipelineStage name="execute" title="执行" :steps="getStageSteps('execute')" :status="getStageStatus('execute')" :is-active="currentStage === 'execute'" :active-step="activeStep" @select-step="handleSelectStep" />
33
33
  <div v-if="hasStage('verify')" class="flex items-center pl-[3px]"><div class="w-px h-4" style="background: #1F1F22;" /></div>
34
- <PipelineStage name="verify" title="VERIFY" :steps="getStageSteps('verify')" :status="getStageStatus('verify')" :is-active="currentStage === 'verify'" :active-step="activeStep" @select-step="handleSelectStep" />
34
+ <PipelineStage name="verify" title="验证" :steps="getStageSteps('verify')" :status="getStageStatus('verify')" :is-active="currentStage === 'verify'" :active-step="activeStep" @select-step="handleSelectStep" />
35
35
  </div>
36
36
  </div>
37
37
 
38
38
  <!-- Activity Log -->
39
39
  <div v-if="project?.state?.progress" style="border-top: 1px solid #1F1F22; background: rgba(10,10,11,0.6);">
40
40
  <div class="px-6 py-2.5 flex items-center justify-between">
41
- <div class="text-[9px] font-semibold uppercase tracking-[0.25em] font-[JetBrains_Mono,monospace]" style="color: #525252;">Activity</div>
41
+ <div class="text-[9px] font-semibold uppercase tracking-[0.25em] font-[JetBrains_Mono,monospace]" style="color: #525252;">活动日志</div>
42
42
  <div class="text-[10px] font-mono-log" style="color: #3A3A3D;">{{ activityLogs.length }}</div>
43
43
  </div>
44
44
  <div class="px-6 pb-3 space-y-0.5 max-h-32 overflow-y-auto">
@@ -47,7 +47,7 @@
47
47
  <span :style="{ color: log.status === 'completed' ? '#34D399' : '#FBBF24' }">›</span>
48
48
  <span style="color: #8B8B8E;">{{ log.description }}</span>
49
49
  </div>
50
- <div v-if="activityLogs.length === 0" class="text-[10px] py-1" style="color: #3A3A3D;">No activity</div>
50
+ <div v-if="activityLogs.length === 0" class="text-[10px] py-1" style="color: #3A3A3D;">暂无活动记录</div>
51
51
  </div>
52
52
  </div>
53
53
  </div>
@@ -68,12 +68,20 @@ const currentStage = computed(() => props.project?.state?.currentStage || 'unkno
68
68
  const progress = computed(() => props.project?.state?.progress || {})
69
69
  const stages = computed(() => progress.value.stages || {})
70
70
 
71
+ const stageNameMap = {
72
+ brainstorm: '头脑风暴',
73
+ plan: '规划',
74
+ execute: '执行',
75
+ verify: '验证'
76
+ }
77
+
71
78
  const activityLogs = computed(() => {
72
79
  if (!props.project?.state) return []
73
80
  const logs = []
74
81
  for (const [name, data] of Object.entries(progress.value.stages || {})) {
75
- if (data.status === 'completed') logs.push({ time: data.completedAt ? formatTime(data.completedAt) : '--:--', status: 'completed', description: `${name} completed` })
76
- else if (data.status === 'in-progress') logs.push({ time: '--:--', status: 'in-progress', description: `${name} running` })
82
+ const label = stageNameMap[name] || name
83
+ if (data.status === 'completed') logs.push({ time: data.completedAt ? formatTime(data.completedAt) : '--:--', status: 'completed', description: `${label} 已完成` })
84
+ else if (data.status === 'in-progress') logs.push({ time: '--:--', status: 'in-progress', description: `${label} 运行中` })
77
85
  }
78
86
  return logs.reverse()
79
87
  })
@@ -6,13 +6,67 @@
6
6
  <div class="w-8 h-8 rounded-md flex items-center justify-center" style="background: linear-gradient(135deg, #FBBF24 0%, #F59E0B 100%); clip-path: polygon(0 0, 100% 0, 85% 100%, 15% 100%);">
7
7
  <span class="text-[10px] font-bold text-black font-[JetBrains_Mono,monospace]">S</span>
8
8
  </div>
9
- <div>
9
+ <div class="flex-1">
10
10
  <h1 class="text-[13px] font-semibold tracking-tight font-[JetBrains_Mono,monospace]" style="color: #E4E4E7;">
11
11
  SillySpec
12
12
  </h1>
13
- <p class="text-[10px] tracking-widest uppercase" style="color: #525252;">Dashboard</p>
13
+ <p class="text-[10px] tracking-widest uppercase" style="color: #525252;">控制台</p>
14
14
  </div>
15
+ <!-- Scan paths gear button -->
16
+ <button
17
+ @click="showScanPanel = !showScanPanel"
18
+ class="p-1.5 rounded-sm transition-colors duration-100"
19
+ :style="{ color: showScanPanel ? '#FBBF24' : '#525252', background: showScanPanel ? 'rgba(251,191,36,0.08)' : 'transparent' }"
20
+ title="扫描路径设置"
21
+ >
22
+ <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
23
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
24
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
25
+ </svg>
26
+ </button>
15
27
  </div>
28
+
29
+ <!-- Scan paths panel (inline) -->
30
+ <Transition name="slide">
31
+ <div v-if="showScanPanel" class="mt-3 rounded-md p-3" style="background: #141416; border: 1px solid #1F1F22;">
32
+ <div class="text-[10px] font-semibold uppercase tracking-[0.15em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #525252;">扫描路径</div>
33
+
34
+ <div v-if="scanPaths.length === 0" class="text-[10px] py-1" style="color: #3A3A3D;">暂无自定义路径</div>
35
+ <div v-else class="space-y-1 mb-2">
36
+ <div v-for="(p, i) in scanPaths" :key="i" class="flex items-center gap-2 text-[10px] group">
37
+ <span class="flex-1 truncate font-mono-log" style="color: #8B8B8E;">{{ p }}</span>
38
+ <button
39
+ @click="removePath(p)"
40
+ class="opacity-0 group-hover:opacity-100 transition-opacity text-[9px] px-1 rounded-sm"
41
+ style="color: #EF4444; background: rgba(239,68,68,0.08);"
42
+ >✕</button>
43
+ </div>
44
+ </div>
45
+
46
+ <!-- Add path -->
47
+ <div v-if="showAddInput" class="flex items-center gap-2">
48
+ <input
49
+ ref="pathInput"
50
+ v-model="newPath"
51
+ type="text"
52
+ placeholder="输入目录路径..."
53
+ class="flex-1 px-2 py-1 rounded-sm text-[10px] font-mono-log outline-none"
54
+ style="background: #0A0A0B; border: 1px solid #2A2A2D; color: #E4E4E7;"
55
+ @keydown.enter="addPath"
56
+ @keydown.escape="showAddInput = false"
57
+ />
58
+ <button @click="addPath" class="px-2 py-1 text-[10px] rounded-sm" style="background: rgba(251,191,36,0.1); color: #FBBF24; border: 1px solid rgba(251,191,36,0.2);">添加</button>
59
+ </div>
60
+ <button
61
+ v-else
62
+ @click="showAddInput = true"
63
+ class="text-[10px] px-2 py-1 rounded-sm transition-colors duration-100"
64
+ style="color: #525252; border: 1px dashed #2A2A2D;"
65
+ >
66
+ + 添加目录
67
+ </button>
68
+ </div>
69
+ </Transition>
16
70
  </div>
17
71
 
18
72
  <!-- Divider -->
@@ -27,7 +81,7 @@
27
81
  <div class="h-2 rounded w-32 skeleton-shimmer"></div>
28
82
  </div>
29
83
  <p class="text-center text-[10px] mt-4 font-[JetBrains_Mono,monospace]" style="color: #525252;">
30
- scanning projects...
84
+ 正在扫描项目...
31
85
  </p>
32
86
  </div>
33
87
 
@@ -38,15 +92,15 @@
38
92
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
39
93
  </svg>
40
94
  </div>
41
- <p class="text-[11px]" style="color: #8B8B8E;">No projects found</p>
42
- <p class="text-[10px] mt-1" style="color: #525252;">Looking for .sillyspec dirs</p>
95
+ <p class="text-[11px]" style="color: #8B8B8E;">未发现 SillySpec 项目</p>
96
+ <p class="text-[10px] mt-1" style="color: #525252;">正在扫描项目目录...</p>
43
97
  </div>
44
98
 
45
99
  <!-- Projects -->
46
100
  <div v-else class="px-3 space-y-0.5">
47
101
  <div
48
102
  v-for="project in projects"
49
- :key="project.name"
103
+ :key="project.path"
50
104
  :class="[
51
105
  'relative rounded-md cursor-pointer transition-all duration-150 overflow-hidden group',
52
106
  ]"
@@ -94,7 +148,7 @@
94
148
  <!-- Footer -->
95
149
  <div class="relative z-10 px-4 py-2.5" style="border-top: 1px solid #1F1F22;">
96
150
  <div class="flex items-center justify-between">
97
- <span class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #525252;">{{ projects.length }} proj</span>
151
+ <span class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #525252;">{{ projects.length }} 个项目</span>
98
152
  <kbd class="text-[9px] px-1.5 py-0.5 rounded font-mono-log" style="color: #525252; background: #141416; border: 1px solid #2A2A2D;">⌘K</kbd>
99
153
  </div>
100
154
  </div>
@@ -102,19 +156,29 @@
102
156
  </template>
103
157
 
104
158
  <script setup>
105
- import { computed } from 'vue'
159
+ import { ref, nextTick, watch } from 'vue'
106
160
  import StageBadge from './StageBadge.vue'
107
161
 
108
162
  const props = defineProps({
109
163
  projects: { type: Array, default: () => [] },
110
164
  activeProject: { type: Object, default: null },
111
- isLoading: { type: Boolean, default: false }
165
+ isLoading: { type: Boolean, default: false },
166
+ scanPaths: { type: Array, default: () => [] }
112
167
  })
113
168
 
114
- const emit = defineEmits(['select'])
169
+ const emit = defineEmits(['select', 'scan:add-path', 'scan:remove-path'])
170
+
171
+ const showScanPanel = ref(false)
172
+ const showAddInput = ref(false)
173
+ const newPath = ref('')
174
+ const pathInput = ref(null)
175
+
176
+ watch(showAddInput, (v) => {
177
+ if (v) nextTick(() => { pathInput.value?.focus() })
178
+ })
115
179
 
116
180
  function isActive(project) {
117
- return props.activeProject?.name === project.name
181
+ return props.activeProject?.path === project.path
118
182
  }
119
183
 
120
184
  function getProjectStatus(project) {
@@ -149,4 +213,23 @@ function getProjectProgress(project) {
149
213
  }
150
214
  return total === 0 ? 0 : Math.round((done / total) * 100)
151
215
  }
216
+
217
+ function addPath() {
218
+ const p = newPath.value.trim()
219
+ if (p) {
220
+ emit('scan:add-path', p)
221
+ newPath.value = ''
222
+ showAddInput.value = false
223
+ }
224
+ }
225
+
226
+ function removePath(p) {
227
+ emit('scan:remove-path', p)
228
+ }
152
229
  </script>
230
+
231
+ <style scoped>
232
+ .slide-enter-active, .slide-leave-active { transition: all 200ms ease; }
233
+ .slide-enter-from, .slide-leave-to { opacity: 0; max-height: 0; overflow: hidden; }
234
+ .slide-enter-to, .slide-leave-from { max-height: 300px; }
235
+ </style>
@@ -21,13 +21,13 @@ export function useDashboard() {
21
21
  * @param {string} name - Project name
22
22
  * @returns {object|null} Project or null
23
23
  */
24
- function getProject(name) {
25
- return state.projects.find(p => p.name === name) || null
24
+ function getProject(path) {
25
+ return state.projects.find(p => p.path === path) || null
26
26
  }
27
27
 
28
28
  /**
29
29
  * Select a project as active
30
- * @param {object|string} project - Project object or name
30
+ * @param {object|string} project - Project object or path
31
31
  */
32
32
  function selectProject(project) {
33
33
  const proj = typeof project === 'string'
@@ -115,7 +115,7 @@ export function useDashboard() {
115
115
 
116
116
  // Restore active project if it still exists
117
117
  if (state.activeProject) {
118
- const updated = getProject(state.activeProject.name)
118
+ const updated = getProject(state.activeProject.path)
119
119
  if (updated) {
120
120
  state.activeProject = updated
121
121
  }
@@ -141,6 +141,7 @@ export function useDashboard() {
141
141
 
142
142
  // Computed properties
143
143
  const activeProjectName = computed(() => state.activeProject?.name || null)
144
+ const activeProjectPath = computed(() => state.activeProject?.path || null)
144
145
  const activeProjectStage = computed(() => state.activeProject?.state?.currentStage || null)
145
146
  const hasProjects = computed(() => state.projects.length > 0)
146
147
  const activeProjectSteps = computed(() => {
@@ -164,6 +165,7 @@ export function useDashboard() {
164
165
  setExecuting,
165
166
  isExecuting,
166
167
  activeProjectName,
168
+ activeProjectPath,
167
169
  activeProjectStage,
168
170
  hasProjects,
169
171
  activeProjectSteps
@@ -1,18 +1,18 @@
1
1
  @import "tailwindcss";
2
2
 
3
3
  @theme {
4
- --color-bg: #0A0A0B;
4
+ --color-bg: #111318;
5
5
  --color-primary: #FBBF24;
6
6
  --color-primary-dim: #B45309;
7
7
  --color-warning: #FB923C;
8
8
  --color-danger: #EF4444;
9
- --color-muted: #525252;
10
- --color-surface: #141416;
11
- --color-surface-2: #1C1C1F;
12
- --color-border: #2A2A2D;
13
- --color-border-light: #3A3A3D;
14
- --color-text: #E4E4E7;
15
- --color-text-secondary: #8B8B8E;
9
+ --color-muted: #6B7280;
10
+ --color-surface: #1A1D24;
11
+ --color-surface-2: #23272F;
12
+ --color-border: #2E3340;
13
+ --color-border-light: #3D4455;
14
+ --color-text: #F0F0F2;
15
+ --color-text-secondary: #9CA3AF;
16
16
  --color-info: #38BDF8;
17
17
  --color-success: #34D399;
18
18
 
@@ -96,7 +96,7 @@
96
96
 
97
97
  /* Skeleton shimmer */
98
98
  .skeleton-shimmer {
99
- background: linear-gradient(90deg, #1C1C1F 25%, #2A2A2D 50%, #1C1C1F 75%);
99
+ background: linear-gradient(90deg, #1A1E28 25%, #2A3040 50%, #1A1E28 75%);
100
100
  background-size: 200% 100%;
101
101
  animation: shimmer 1.5s ease-in-out infinite;
102
102
  }
@@ -112,12 +112,12 @@
112
112
  }
113
113
 
114
114
  ::-webkit-scrollbar-thumb {
115
- background: #2A2A2D;
115
+ background: #2A3040;
116
116
  border-radius: 10px;
117
117
  }
118
118
 
119
119
  ::-webkit-scrollbar-thumb:hover {
120
- background: #3A3A3D;
120
+ background: #3A4555;
121
121
  }
122
122
 
123
123
  * {
@@ -1 +0,0 @@
1
- .line-clamp-2[data-v-20b76823]{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.backdrop-enter-active[data-v-93004906],.backdrop-leave-active[data-v-93004906]{transition:opacity .15s ease}.backdrop-enter-from[data-v-93004906],.backdrop-leave-to[data-v-93004906]{opacity:0}.palette-enter-active[data-v-93004906],.palette-leave-active[data-v-93004906]{transition:all .2s cubic-bezier(.16,1,.3,1)}.palette-enter-from[data-v-93004906],.palette-leave-to[data-v-93004906]{opacity:0;transform:translate(-50%,-8px) scale(.98)}*{margin:0;padding:0;box-sizing:border-box}body{font-family:DM Sans,-apple-system,BlinkMacSystemFont,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#app{width:100vw;height:100vh;overflow:hidden}/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg:#0a0a0b;--color-primary:#fbbf24;--color-warning:#fb923c;--color-danger:#ef4444;--color-muted:#525252;--color-surface:#141416;--color-border:#2a2a2d;--color-text:#e4e4e7;--color-text-secondary:#8b8b8e;--animate-pulse-dot:pulse-dot 1.5s ease-in-out infinite}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-\[18\%\]{top:18%}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.flex{display:flex}.hidden{display:none}.inline-flex{display:inline-flex}.h-1{height:calc(var(--spacing) * 1)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-\[2px\]{height:2px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-72{max-height:calc(var(--spacing) * 72)}.w-0{width:calc(var(--spacing) * 0)}.w-1{width:calc(var(--spacing) * 1)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-14{width:calc(var(--spacing) * 14)}.w-20{width:calc(var(--spacing) * 20)}.w-32{width:calc(var(--spacing) * 32)}.w-\[2px\]{width:2px}.w-\[240px\]{width:240px}.w-\[340px\]{width:340px}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse-dot{animation:var(--animate-pulse-dot)}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-px>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(1px * var(--tw-space-y-reverse));margin-block-end:calc(1px * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-none{--tw-border-style:none;border-style:none}.bg-transparent{background-color:#0000}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-px{padding-block:1px}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-\[3px\]{padding-left:3px}.text-center{text-align:center}.font-\[DM_Sans\,sans-serif\]{font-family:DM Sans,sans-serif}.font-\[JetBrains_Mono\,monospace\]{font-family:JetBrains Mono,monospace}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.25em\]{--tw-tracking:.25em;letter-spacing:.25em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.whitespace-pre-wrap{white-space:pre-wrap}.text-black{color:var(--color-black)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.opacity-0{opacity:0}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}}}@keyframes pulse-glow{0%,to{box-shadow:0 0 #fbbf2466}50%{box-shadow:0 0 12px 2px #fbbf2426}}@keyframes pulse-dot{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.5)}}@keyframes breathe{0%,to{opacity:.5}50%{opacity:1}}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}@keyframes slide-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes glow-border{0%,to{border-color:#fbbf2426}50%{border-color:#fbbf2480}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.font-mono-log{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.noise-bg{position:relative}.noise-bg:before{content:"";pointer-events:none;z-index:0;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");position:absolute;top:0;right:0;bottom:0;left:0}.accent-stripe{background:repeating-linear-gradient(-45deg,#0000,#0000 8px,#fbbf2408 8px,#fbbf2408 9px)}.progress-gradient{background:linear-gradient(90deg,#fbbf24,#f59e0b,#fb923c)}.skeleton-shimmer{background:linear-gradient(90deg,#1c1c1f 25%,#2a2a2d,#1c1c1f 75%) 0 0/200% 100%;animation:1.5s ease-in-out infinite shimmer}::-webkit-scrollbar{width:5px;height:5px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:#2a2a2d;border-radius:10px}::-webkit-scrollbar-thumb:hover{background:#3a3a3d}*{scrollbar-width:thin;scrollbar-color:#2a2a2d transparent}::selection{color:#fbbf24;background:#fbbf2433}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}