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.
- package/package.json +5 -2
- package/packages/dashboard/dist/assets/index-DHbVrCnq.css +1 -0
- package/packages/dashboard/dist/assets/index-qx7yiwun.js +17 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/server/index.js +111 -104
- package/packages/dashboard/server/watcher.js +203 -131
- package/packages/dashboard/src/App.vue +14 -3
- package/packages/dashboard/src/components/ActionBar.vue +6 -6
- package/packages/dashboard/src/components/CommandPalette.vue +5 -5
- package/packages/dashboard/src/components/DetailPanel.vue +10 -10
- package/packages/dashboard/src/components/LogStream.vue +5 -5
- package/packages/dashboard/src/components/PipelineView.vue +18 -10
- package/packages/dashboard/src/components/ProjectList.vue +94 -11
- package/packages/dashboard/src/composables/useDashboard.js +6 -4
- package/packages/dashboard/src/style.css +11 -11
- package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +0 -1
- package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +0 -17
|
@@ -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
|
-
|
|
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;"
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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;"
|
|
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;"
|
|
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
|
-
|
|
76
|
-
|
|
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;"
|
|
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
|
-
|
|
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;"
|
|
42
|
-
<p class="text-[10px] mt-1" style="color: #525252;"
|
|
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.
|
|
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 }}
|
|
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 {
|
|
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?.
|
|
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(
|
|
25
|
-
return state.projects.find(p => p.
|
|
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
|
|
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.
|
|
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: #
|
|
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: #
|
|
10
|
-
--color-surface: #
|
|
11
|
-
--color-surface-2: #
|
|
12
|
-
--color-border: #
|
|
13
|
-
--color-border-light: #
|
|
14
|
-
--color-text: #
|
|
15
|
-
--color-text-secondary: #
|
|
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, #
|
|
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: #
|
|
115
|
+
background: #2A3040;
|
|
116
116
|
border-radius: 10px;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
::-webkit-scrollbar-thumb:hover {
|
|
120
|
-
background: #
|
|
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}}
|