@cat-factory/app 0.308.0 → 0.310.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 (265) hide show
  1. package/README.md +32 -2
  2. package/app/assets/css/main.css +22 -0
  3. package/app/assets/css/prose.css +4 -4
  4. package/app/assets/css/type.css +24 -0
  5. package/app/components/assistant/AssistantModal.vue +8 -6
  6. package/app/components/auth/BackendMisconfiguredScreen.vue +4 -3
  7. package/app/components/auth/LoginScreen.vue +40 -26
  8. package/app/components/auth/ResetPasswordScreen.vue +9 -4
  9. package/app/components/auth/UserMenu.vue +5 -4
  10. package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +48 -37
  11. package/app/components/binaryOutput/BinaryOutputReport.vue +10 -14
  12. package/app/components/binaryOutput/StoredAssetView.vue +13 -11
  13. package/app/components/board/AddTaskModal.vue +30 -27
  14. package/app/components/board/AgentFailureCard.vue +21 -18
  15. package/app/components/board/AgentFailureHistory.vue +18 -9
  16. package/app/components/board/CreateInitiativeModal.vue +7 -6
  17. package/app/components/board/FailureDetail.vue +22 -12
  18. package/app/components/board/FailureHistoryList.vue +5 -5
  19. package/app/components/board/RecurringPipelineModal.vue +12 -11
  20. package/app/components/board/ReviewFrictionDialog.vue +8 -6
  21. package/app/components/board/StepExecutionHistory.vue +8 -8
  22. package/app/components/board/nodes/AgentChip.vue +1 -1
  23. package/app/components/board/nodes/BlockNode.vue +25 -24
  24. package/app/components/board/nodes/DecisionBadge.vue +4 -3
  25. package/app/components/board/nodes/EpicNode.vue +4 -4
  26. package/app/components/board/nodes/FrameSwimlanes.vue +8 -10
  27. package/app/components/board/nodes/InitiativeCard.vue +4 -4
  28. package/app/components/board/nodes/LaneGroup.vue +3 -5
  29. package/app/components/board/nodes/TaskCard.vue +20 -15
  30. package/app/components/board/nodes/TaskLane.vue +3 -3
  31. package/app/components/board/nodes/TaskPipelineMini.vue +21 -18
  32. package/app/components/bootstrap/AdoptionReviewModal.vue +36 -26
  33. package/app/components/bootstrap/BootstrapModal.vue +14 -13
  34. package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
  35. package/app/components/brainstorm/BrainstormWindow.vue +13 -10
  36. package/app/components/bugFishing/BugFishingWindow.vue +81 -58
  37. package/app/components/clarity/ClarityReviewWindow.vue +13 -10
  38. package/app/components/common/AsyncViewError.vue +1 -1
  39. package/app/components/common/ClarificationItem.vue +6 -6
  40. package/app/components/common/CopyButton.vue +12 -11
  41. package/app/components/common/DescriptorFields.vue +1 -1
  42. package/app/components/common/EmptyState.vue +1 -1
  43. package/app/components/common/IconButton.vue +34 -9
  44. package/app/components/common/InterviewGateNotice.vue +4 -4
  45. package/app/components/common/MarkdownProse.vue +8 -2
  46. package/app/components/common/SectionLabel.vue +38 -0
  47. package/app/components/consensus/ConsensusSessionWindow.vue +10 -9
  48. package/app/components/context/ContextAttachmentFields.vue +32 -20
  49. package/app/components/docs/DocInterviewWindow.vue +10 -9
  50. package/app/components/documents/ContextDocumentPicker.vue +22 -21
  51. package/app/components/documents/DocumentImportModal.vue +7 -5
  52. package/app/components/documents/DocumentOriginLink.vue +12 -9
  53. package/app/components/documents/DocumentSourceConnectModal.vue +2 -2
  54. package/app/components/documents/DocumentSyncState.vue +4 -4
  55. package/app/components/documents/DocumentTemplatesModal.vue +5 -4
  56. package/app/components/documents/RepoContextDocPicker.vue +7 -9
  57. package/app/components/documents/StartFromDesignModal.vue +4 -4
  58. package/app/components/documents/TaskContextDocs.vue +1 -1
  59. package/app/components/environments/EnvSetupStepper.vue +3 -3
  60. package/app/components/environments/EnvironmentStatusPanel.vue +15 -13
  61. package/app/components/environments/steps/EnvPreflightStep.vue +8 -8
  62. package/app/components/environments/steps/EnvReviewStep.vue +23 -22
  63. package/app/components/environments/steps/EnvSaveStep.vue +5 -5
  64. package/app/components/focus/BlockFocusView.vue +11 -10
  65. package/app/components/followUp/FollowUpWindow.vue +18 -15
  66. package/app/components/forkDecision/ForkDecisionWindow.vue +85 -97
  67. package/app/components/foundational/FoundationalContractSummary.vue +2 -2
  68. package/app/components/foundational/FoundationalServiceCatalogList.vue +6 -5
  69. package/app/components/foundational/FoundationalServiceRegistry.vue +10 -9
  70. package/app/components/foundational/FoundationalServiceSources.vue +7 -6
  71. package/app/components/foundational/FoundationalSuppressions.vue +2 -2
  72. package/app/components/fragments/FragmentLibraryManager.vue +8 -7
  73. package/app/components/fragments/FragmentSelector.vue +22 -20
  74. package/app/components/gates/GateFailingCheckList.vue +7 -6
  75. package/app/components/gates/GateResultView.vue +55 -49
  76. package/app/components/github/AddServiceFromRepoModal.vue +16 -11
  77. package/app/components/github/BranchProtectionPreflight.vue +5 -5
  78. package/app/components/github/GitHubConnect.vue +5 -3
  79. package/app/components/github/GitHubOnboarding.vue +7 -2
  80. package/app/components/github/GitHubPanel.vue +23 -19
  81. package/app/components/github/RepoTreeBrowser.vue +16 -13
  82. package/app/components/humanTest/HumanTestWindow.vue +29 -24
  83. package/app/components/initiative/InitiativePlanNotice.vue +3 -3
  84. package/app/components/initiative/InitiativePlanReview.vue +46 -38
  85. package/app/components/initiative/InitiativePlanningWindow.vue +5 -5
  86. package/app/components/initiative/InitiativeTrackerWindow.vue +213 -165
  87. package/app/components/judge/JudgeResultView.vue +28 -27
  88. package/app/components/kaizen/KaizenPanel.vue +70 -56
  89. package/app/components/kaizen/KaizenStepStatus.vue +7 -6
  90. package/app/components/layout/AccountAuditLog.vue +1 -1
  91. package/app/components/layout/AccountDeploymentSettings.vue +10 -10
  92. package/app/components/layout/AccountFailureKindRules.vue +13 -13
  93. package/app/components/layout/AccountFoundationalSettings.vue +1 -1
  94. package/app/components/layout/AccountFragmentSettings.vue +1 -1
  95. package/app/components/layout/AccountModelPolicySettings.vue +7 -7
  96. package/app/components/layout/AccountPlatformAlertSettings.vue +8 -8
  97. package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
  98. package/app/components/layout/AccountRunCredentialSettings.vue +3 -3
  99. package/app/components/layout/AccountSkillSettings.vue +1 -1
  100. package/app/components/layout/AccountTeamSettings.vue +13 -9
  101. package/app/components/layout/AiProvidersBanner.vue +1 -1
  102. package/app/components/layout/AppearanceSwitcher.vue +5 -4
  103. package/app/components/layout/BoardSwitcher.vue +13 -10
  104. package/app/components/layout/BoardToolbar.vue +10 -5
  105. package/app/components/layout/CommandBar.vue +8 -5
  106. package/app/components/layout/DefaultTestEnvBanner.vue +6 -5
  107. package/app/components/layout/IntegrationsHub.vue +12 -9
  108. package/app/components/layout/LanguageSwitcher.vue +5 -4
  109. package/app/components/layout/ModelProvidersHub.vue +10 -7
  110. package/app/components/layout/NotificationsInbox.vue +47 -36
  111. package/app/components/layout/PersonalSetupModal.vue +9 -6
  112. package/app/components/layout/RolePrompt.vue +5 -4
  113. package/app/components/layout/SideBar.vue +7 -8
  114. package/app/components/layout/SpendWarningBanner.vue +3 -3
  115. package/app/components/layout/TranslationWarningBanner.vue +5 -4
  116. package/app/components/layout/UiModeSwitcher.vue +15 -12
  117. package/app/components/layout/UiRoleSwitcher.vue +10 -8
  118. package/app/components/layout/WorkspaceMembersSettings.vue +2 -2
  119. package/app/components/media/ArtifactLightbox.vue +74 -44
  120. package/app/components/media/ImageCompare.vue +80 -85
  121. package/app/components/merge/MergeEffortChips.vue +4 -6
  122. package/app/components/notifications/NotificationSettingsPanel.vue +6 -5
  123. package/app/components/observability/OutcomeFilterChips.vue +6 -5
  124. package/app/components/observability/RunFailureSummary.vue +22 -23
  125. package/app/components/observability/StepMetricsBar.vue +9 -8
  126. package/app/components/observability/StepModelActivity.vue +8 -5
  127. package/app/components/observability/ToolCallList.vue +19 -20
  128. package/app/components/outcome/OutcomeSummaryWindow.vue +48 -46
  129. package/app/components/palettes/AgentPalette.vue +21 -15
  130. package/app/components/palettes/AgentTierSelect.vue +1 -1
  131. package/app/components/palettes/PipelinePurposeSelect.vue +1 -1
  132. package/app/components/panels/AgentStepDetail.vue +57 -49
  133. package/app/components/panels/AttemptEntryHeader.vue +2 -2
  134. package/app/components/panels/DecisionModal.vue +1 -1
  135. package/app/components/panels/GenericStructuredResultView.vue +6 -5
  136. package/app/components/panels/InspectorPanel.vue +15 -13
  137. package/app/components/panels/MergerResultView.vue +10 -9
  138. package/app/components/panels/ObservabilityPanel.vue +211 -186
  139. package/app/components/panels/OperatorDashboardPanel.vue +124 -115
  140. package/app/components/panels/ReportsPanel.vue +87 -83
  141. package/app/components/panels/ReportsSpendBreakdown.vue +2 -2
  142. package/app/components/panels/ResultWindowShell.vue +152 -137
  143. package/app/components/panels/RunDetailLoadState.vue +1 -1
  144. package/app/components/panels/StepContainerStatus.vue +17 -16
  145. package/app/components/panels/StepDelegatedStatus.vue +24 -21
  146. package/app/components/panels/StepEffortReport.vue +12 -17
  147. package/app/components/panels/StepFragmentAdherence.vue +9 -10
  148. package/app/components/panels/StepMetadataCard.vue +41 -43
  149. package/app/components/panels/StepReproductionReport.vue +18 -20
  150. package/app/components/panels/StepRestartControl.vue +3 -2
  151. package/app/components/panels/StepRunMeta.vue +27 -26
  152. package/app/components/panels/StepTestReport.vue +16 -15
  153. package/app/components/panels/StepToolServers.vue +7 -8
  154. package/app/components/panels/StepValidationReport.vue +5 -5
  155. package/app/components/panels/inspector/ContainerSummary.vue +4 -4
  156. package/app/components/panels/inspector/DocReferenceRepos.vue +5 -4
  157. package/app/components/panels/inspector/EnvProbeReport.vue +16 -13
  158. package/app/components/panels/inspector/EpicChildren.vue +12 -10
  159. package/app/components/panels/inspector/FrontendBindingsResolved.vue +5 -4
  160. package/app/components/panels/inspector/FrontendConfig.vue +29 -36
  161. package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
  162. package/app/components/panels/inspector/InspectorSection.vue +25 -17
  163. package/app/components/panels/inspector/RecurringScheduleSettings.vue +9 -8
  164. package/app/components/panels/inspector/ServiceConnections.vue +5 -4
  165. package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -2
  166. package/app/components/panels/inspector/ServiceSelfTests.vue +9 -13
  167. package/app/components/panels/inspector/ServiceTestConfig.vue +46 -49
  168. package/app/components/panels/inspector/ServiceTestSecrets.vue +3 -3
  169. package/app/components/panels/inspector/ServiceTestingContext.vue +2 -2
  170. package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
  171. package/app/components/panels/inspector/TaskAgentConfig.vue +2 -2
  172. package/app/components/panels/inspector/TaskAprioriBranches.vue +6 -5
  173. package/app/components/panels/inspector/TaskDependencies.vue +1 -1
  174. package/app/components/panels/inspector/TaskEstimateBadge.vue +3 -7
  175. package/app/components/panels/inspector/TaskExecution.vue +18 -16
  176. package/app/components/panels/inspector/TaskRunSettings.vue +45 -44
  177. package/app/components/panels/inspector/TaskStructure.vue +5 -4
  178. package/app/components/pipeline/AgentPromptEditor.vue +15 -14
  179. package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -52
  180. package/app/components/pipeline/EstimateThresholdFields.vue +14 -11
  181. package/app/components/pipeline/GateConfigFields.vue +19 -23
  182. package/app/components/pipeline/IterationCapPrompt.vue +1 -1
  183. package/app/components/pipeline/PipelineBuilder.vue +113 -99
  184. package/app/components/pipeline/PipelineHealthModal.vue +7 -7
  185. package/app/components/pipeline/PipelinePicker.vue +11 -9
  186. package/app/components/pipeline/PipelinePreview.vue +6 -7
  187. package/app/components/pipeline/PipelineProgress.vue +49 -45
  188. package/app/components/prReview/PrReviewWindow.vue +87 -65
  189. package/app/components/providers/AiPresetMismatchDialog.vue +4 -3
  190. package/app/components/providers/AiProviderOnboardingModal.vue +2 -2
  191. package/app/components/providers/ApiKeysSection.vue +11 -9
  192. package/app/components/providers/PersonalSubscriptionSection.vue +4 -3
  193. package/app/components/providers/VendorCredentialsModal.vue +5 -4
  194. package/app/components/provisioning/ProvisioningLogsDrawer.vue +10 -9
  195. package/app/components/ralph/RalphLoopResultView.vue +29 -29
  196. package/app/components/requirements/RequirementsReviewWindow.vue +22 -17
  197. package/app/components/riskPolicy/RiskPolicyPicker.vue +13 -11
  198. package/app/components/riskPolicy/RiskPolicyPreview.vue +16 -15
  199. package/app/components/sandbox/SandboxPanel.vue +93 -73
  200. package/app/components/settings/ApiTokensPanel.vue +1 -1
  201. package/app/components/settings/BudgetSettings.vue +18 -17
  202. package/app/components/settings/CapabilityCredentialsPanel.vue +5 -5
  203. package/app/components/settings/CloudflareHandlerSection.vue +44 -41
  204. package/app/components/settings/ComposeEnvironmentSetupSection.vue +14 -12
  205. package/app/components/settings/ConnectionTestVerdict.vue +1 -1
  206. package/app/components/settings/ConsensusGroupsSection.vue +58 -47
  207. package/app/components/settings/CustomManifestTypeEditor.vue +8 -7
  208. package/app/components/settings/DefaultProvisionTypeSection.vue +5 -5
  209. package/app/components/settings/InfraHandlersConfigurator.vue +26 -24
  210. package/app/components/settings/InfrastructureBackendPicker.vue +18 -18
  211. package/app/components/settings/IssueTrackerPanel.vue +30 -21
  212. package/app/components/settings/KubernetesEngineForm.vue +9 -8
  213. package/app/components/settings/KubernetesEnvironmentForm.vue +4 -3
  214. package/app/components/settings/LocalContainerPoolSettings.vue +2 -2
  215. package/app/components/settings/LocalModelEndpointsPanel.vue +13 -11
  216. package/app/components/settings/MergeClassRulesEditor.vue +6 -5
  217. package/app/components/settings/MergeRolePolicyEditor.vue +13 -12
  218. package/app/components/settings/ModelConfigurationPanel.vue +17 -19
  219. package/app/components/settings/ModelPresetHealthModal.vue +3 -3
  220. package/app/components/settings/ObservabilityConnectionPanel.vue +1 -1
  221. package/app/components/settings/OpenRouterCatalogPanel.vue +10 -8
  222. package/app/components/settings/PackageRegistriesPanel.vue +4 -4
  223. package/app/components/settings/ProviderConnectionTab.vue +5 -4
  224. package/app/components/settings/ProviderManifestEditor.vue +9 -8
  225. package/app/components/settings/ProviderPreferenceEditor.vue +13 -13
  226. package/app/components/settings/RiskPolicyCreateForm.vue +40 -26
  227. package/app/components/settings/RiskPolicyEditorRow.vue +21 -19
  228. package/app/components/settings/RiskPolicyHealthModal.vue +3 -3
  229. package/app/components/settings/RiskPolicyPanel.vue +11 -13
  230. package/app/components/settings/ServiceFragmentDefaultsPanel.vue +15 -12
  231. package/app/components/settings/SharedStacksPanel.vue +5 -5
  232. package/app/components/settings/TaskSourceCard.vue +2 -2
  233. package/app/components/settings/TaskTypeSuppressionsPanel.vue +4 -4
  234. package/app/components/settings/ToolServerChecklist.vue +22 -22
  235. package/app/components/settings/UsageSettings.vue +13 -13
  236. package/app/components/settings/UserSecretsSection.vue +4 -3
  237. package/app/components/settings/WorkspaceMetadataSettings.vue +6 -5
  238. package/app/components/settings/WorkspaceSettingsPanel.vue +72 -58
  239. package/app/components/skills/ReviewSkillQueue.vue +12 -10
  240. package/app/components/skills/SkillLibraryManager.vue +9 -8
  241. package/app/components/slack/SlackPanel.vue +17 -12
  242. package/app/components/spec/ServiceSpecWindow.vue +19 -19
  243. package/app/components/tasks/BugHuntModal.vue +1 -1
  244. package/app/components/tasks/ContextIssuePicker.vue +16 -15
  245. package/app/components/tasks/TaskContextIssues.vue +5 -4
  246. package/app/components/tasks/TaskImportModal.vue +3 -2
  247. package/app/components/tasks/TaskSourceConnectModal.vue +5 -5
  248. package/app/components/testing/TestReportWindow.vue +67 -60
  249. package/app/components/theme/ThemeImportModal.vue +2 -2
  250. package/app/components/tutorial/TutorialNudge.vue +3 -2
  251. package/app/components/tutorial/TutorialOverlay.vue +3 -2
  252. package/app/components/vcs/GitLabConnect.vue +1 -1
  253. package/app/components/visualConfirm/VisualConfirmationWindow.vue +79 -54
  254. package/app/utils/theme/builtins.ts +7 -1
  255. package/i18n/locales/de.json +7 -3
  256. package/i18n/locales/en.json +7 -3
  257. package/i18n/locales/es.json +7 -3
  258. package/i18n/locales/fr.json +7 -3
  259. package/i18n/locales/he.json +7 -3
  260. package/i18n/locales/it.json +7 -3
  261. package/i18n/locales/ja.json +7 -3
  262. package/i18n/locales/pl.json +7 -3
  263. package/i18n/locales/tr.json +7 -3
  264. package/i18n/locales/uk.json +7 -3
  265. package/package.json +1 -1
@@ -549,7 +549,7 @@ const STATUS_KEYS: Record<BugHuntAnalysisStatus, string> = {
549
549
  <p v-if="candidate.analysis?.rationale" class="text-xs text-toned">
550
550
  {{ candidate.analysis.rationale }}
551
551
  </p>
552
- <div class="flex flex-wrap items-center gap-2 text-[11px] text-dimmed">
552
+ <div class="flex flex-wrap items-center gap-2 text-2xs text-dimmed">
553
553
  <span v-if="candidate.priority">{{ candidate.priority }}</span>
554
554
  <span v-for="label in candidate.labels" :key="label">{{ label }}</span>
555
555
  <span v-if="createdAtDate(candidate.createdAt)">
@@ -28,6 +28,7 @@ import {
28
28
  reconcileSource,
29
29
  sourceMenuItems,
30
30
  } from '~/utils/sourcePicker'
31
+ import SectionLabel from '~/components/common/SectionLabel.vue'
31
32
 
32
33
  const props = defineProps<{
33
34
  /** contextKeys already staged by the caller, so they're filtered out / not re-offered. */
@@ -291,12 +292,9 @@ onMounted(() => {
291
292
  promises a choice that isn't there. `id` labels the trigger, whose own content is the
292
293
  tracker name rather than what that name means. -->
293
294
  <div class="flex items-center gap-1.5">
294
- <span
295
- :id="sourceLabelId"
296
- class="shrink-0 text-[11px] font-semibold uppercase tracking-wide text-dimmed"
297
- >
295
+ <SectionLabel as="span" :id="sourceLabelId" class="shrink-0">
298
296
  {{ t('tasks.picker.sourceLabel') }}
299
- </span>
297
+ </SectionLabel>
300
298
  <UDropdownMenu
301
299
  v-if="sourcePickable"
302
300
  :items="sourceMenu"
@@ -335,16 +333,17 @@ onMounted(() => {
335
333
  @keydown.enter="refRow && pickRef(refRow)"
336
334
  />
337
335
 
338
- <p v-if="searchError" class="px-1 text-[11px] text-app-warning-400">
336
+ <p v-if="searchError" class="px-1 text-2xs text-app-warning-400">
339
337
  {{ searchError }}
340
338
  </p>
341
339
 
342
340
  <div class="max-h-56 space-y-0.5 overflow-y-auto">
343
341
  <!-- Already-imported issues (linked directly, no re-fetch). -->
344
- <button
342
+ <UButton
343
+ color="neutral"
344
+ variant="ghost"
345
345
  v-for="row in importedRows"
346
346
  :key="`imp:${row.externalId}`"
347
- type="button"
348
347
  class="flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-start text-xs text-toned hover:bg-elevated/70"
349
348
  @click="pickImported(row)"
350
349
  >
@@ -353,13 +352,14 @@ onMounted(() => {
353
352
  <UBadge color="neutral" variant="soft" size="xs" class="ms-auto shrink-0">{{
354
353
  t('tasks.picker.imported')
355
354
  }}</UBadge>
356
- </button>
355
+ </UButton>
357
356
 
358
357
  <!-- Tracker search hits (imported on add). -->
359
- <button
358
+ <UButton
359
+ color="neutral"
360
+ variant="ghost"
360
361
  v-for="r in searchRows"
361
362
  :key="`hit:${r.externalId}`"
362
- type="button"
363
363
  class="flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-start text-xs text-toned hover:bg-elevated/70"
364
364
  @click="pickSearch(r)"
365
365
  >
@@ -368,12 +368,13 @@ onMounted(() => {
368
368
  <UBadge v-if="r.status" color="neutral" variant="soft" size="xs" class="ms-auto shrink-0">
369
369
  {{ r.status }}
370
370
  </UBadge>
371
- </button>
371
+ </UButton>
372
372
 
373
373
  <!-- Explicit URL/key reference (imported on add). -->
374
- <button
374
+ <UButton
375
+ color="neutral"
376
+ variant="ghost"
375
377
  v-if="refRow"
376
- type="button"
377
378
  class="flex w-full items-center gap-1.5 rounded-md px-2 py-1.5 text-start text-xs text-toned hover:bg-elevated/70"
378
379
  @click="pickRef(refRow)"
379
380
  >
@@ -385,7 +386,7 @@ onMounted(() => {
385
386
  </template>
386
387
  </i18n-t>
387
388
  </span>
388
- </button>
389
+ </UButton>
389
390
 
390
391
  <EmptyState
391
392
  v-if="empty"
@@ -132,10 +132,11 @@ async function attach(item: PendingContext) {
132
132
  />
133
133
 
134
134
  <div v-if="linked.length" class="space-y-1">
135
- <a
135
+ <ULink
136
+ raw
136
137
  v-for="issue in linked"
137
138
  :key="`${issue.source}:${issue.externalId}`"
138
- :href="issue.url"
139
+ :to="issue.url"
139
140
  target="_blank"
140
141
  rel="noopener"
141
142
  class="flex items-center gap-1.5 rounded-md border border-default bg-default/60 px-2 py-1.5 text-xs text-toned hover:bg-elevated/60"
@@ -148,9 +149,9 @@ async function attach(item: PendingContext) {
148
149
  <UBadge color="neutral" variant="soft" size="xs" class="ms-auto shrink-0">
149
150
  {{ issue.status }}
150
151
  </UBadge>
151
- </a>
152
+ </ULink>
152
153
  </div>
153
- <p v-else class="text-[11px] text-dimmed">
154
+ <p v-else class="text-2xs text-dimmed">
154
155
  {{ emptyHint }}
155
156
  </p>
156
157
  </InspectorSection>
@@ -17,6 +17,7 @@ import type { PendingContext } from '~/composables/useContextLinking'
17
17
  import { type AddSourceLabels, addChoicesOf, buildSourceChoices } from '~/utils/sourcePicker'
18
18
  import ContextIssuePicker from '~/components/tasks/ContextIssuePicker.vue'
19
19
  import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
20
+ import SectionLabel from '~/components/common/SectionLabel.vue'
20
21
 
21
22
  const { t } = useI18n()
22
23
  const ui = useUiStore()
@@ -183,9 +184,9 @@ async function doSpawnEpic() {
183
184
 
184
185
  <!-- Secondary: spawn a parent/epic issue as a whole linked task group. -->
185
186
  <div class="space-y-2 border-t border-default pt-3">
186
- <span class="text-[11px] font-semibold uppercase tracking-wide text-muted">
187
+ <SectionLabel as="span">
187
188
  {{ t('tasks.import.asEpic') }}
188
- </span>
189
+ </SectionLabel>
189
190
  <div class="flex items-end gap-2">
190
191
  <UFormField :label="descriptor?.refLabel ?? t('tasks.import.refLabel')" class="flex-1">
191
192
  <UInput
@@ -128,10 +128,10 @@ async function toggleEnabled(enabled: boolean) {
128
128
 
129
129
  <!-- Credentialless source (GitHub Issues): no form, just the on/off toggle. -->
130
130
  <template v-if="credentialless">
131
- <p class="text-[11px] text-dimmed">
131
+ <p class="text-2xs text-dimmed">
132
132
  {{ t('tasks.connect.credentialless') }}
133
133
  </p>
134
- <p v-if="!available" class="text-[11px] text-app-warning-400">
134
+ <p v-if="!available" class="text-2xs text-app-warning-400">
135
135
  {{ t('tasks.connect.installAppHint', { label: descriptor.label }) }}
136
136
  </p>
137
137
  </template>
@@ -149,7 +149,7 @@ async function toggleEnabled(enabled: boolean) {
149
149
  >
150
150
  {{ t('tasks.connect.oauthButton', { label: descriptor.label }) }}
151
151
  </UButton>
152
- <p class="text-center text-[11px] text-dimmed">
152
+ <p class="text-center text-2xs text-dimmed">
153
153
  {{ t('tasks.connect.oauthOr') }}
154
154
  </p>
155
155
  </template>
@@ -167,7 +167,7 @@ async function toggleEnabled(enabled: boolean) {
167
167
  />
168
168
  </UFormField>
169
169
  </div>
170
- <p v-else class="text-[11px] text-dimmed">
170
+ <p v-else class="text-2xs text-dimmed">
171
171
  {{
172
172
  connection?.label
173
173
  ? t('tasks.connect.connectedTo', { label: connection.label })
@@ -184,7 +184,7 @@ async function toggleEnabled(enabled: boolean) {
184
184
  <div class="font-medium text-default">
185
185
  {{ t('tasks.connect.offerToWorkspace') }}
186
186
  </div>
187
- <div class="text-[11px] text-dimmed">
187
+ <div class="text-2xs text-dimmed">
188
188
  {{ t('tasks.connect.offerHint', { label: descriptor.label }) }}
189
189
  </div>
190
190
  </div>
@@ -22,6 +22,7 @@ import EnvironmentStatusPanel from '~/components/environments/EnvironmentStatusP
22
22
  import ProvisioningLogsDrawer from '~/components/provisioning/ProvisioningLogsDrawer.vue'
23
23
  import MarkdownProse from '~/components/common/MarkdownProse.vue'
24
24
  import { runIsActive } from '~/utils/pipelineRender'
25
+ import SectionLabel from '~/components/common/SectionLabel.vue'
25
26
 
26
27
  const board = useBoardStore()
27
28
  const execution = useExecutionStore()
@@ -361,7 +362,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
361
362
  </UBadge>
362
363
  <span
363
364
  v-if="testState && testState.attempts > 0"
364
- class="text-[11px] text-muted"
365
+ class="text-2xs text-muted"
365
366
  :title="t('testing.fixerAttempts')"
366
367
  >
367
368
  {{ t('testing.fixCount', { attempts: testState.attempts, max: testState.maxAttempts }) }}
@@ -384,9 +385,9 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
384
385
  data-testid="tester-infrastructure"
385
386
  class="space-y-3"
386
387
  >
387
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
388
+ <SectionLabel as="h3">
388
389
  {{ t('testing.infrastructure') }}
389
- </h3>
390
+ </SectionLabel>
390
391
  <StepContainerStatus :step="step" :run-failed="runFailed" :run-active="runActive" />
391
392
  <EnvironmentStatusPanel
392
393
  v-if="stepEnvironment"
@@ -414,10 +415,10 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
414
415
  class="h-3.5 w-3.5 shrink-0"
415
416
  :class="infraSetup.started ? 'text-app-success-400' : 'text-app-error-400'"
416
417
  />
417
- <span class="text-[13px] font-medium text-default">
418
+ <span class="text-sm font-medium text-default">
418
419
  {{ standupHeadline }}
419
420
  </span>
420
- <span v-if="infraSetup.durationMs != null" class="ms-auto text-[11px] text-dimmed">
421
+ <span v-if="infraSetup.durationMs != null" class="ms-auto text-2xs text-dimmed">
421
422
  {{
422
423
  t('testing.standup.took', {
423
424
  seconds: n(infraSetup.durationMs / 1000, 'decimal'),
@@ -425,12 +426,12 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
425
426
  }}
426
427
  </span>
427
428
  </div>
428
- <p v-if="infraSetup.composePath" class="mt-1 font-mono text-[11px] text-dimmed">
429
+ <p v-if="infraSetup.composePath" class="mt-1 font-mono text-2xs text-dimmed">
429
430
  {{ infraSetup.composePath }}
430
431
  </p>
431
432
  <p
432
433
  v-if="infraSetup.error"
433
- class="mt-1 text-[12px] leading-snug text-app-error-300"
434
+ class="mt-1 text-xs leading-snug text-app-error-300"
434
435
  data-testid="tester-infra-setup-error"
435
436
  >
436
437
  {{ infraSetup.error }}
@@ -455,7 +456,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
455
456
  <pre
456
457
  v-if="showInfraSetupLogs"
457
458
  data-testid="tester-infra-setup-logs"
458
- class="mt-2 max-h-64 overflow-auto rounded bg-app-950/70 p-2 font-mono text-[11px] leading-relaxed text-toned"
459
+ class="mt-2 max-h-64 overflow-auto rounded-sm bg-app-950/70 p-2 font-mono text-2xs leading-relaxed text-toned"
459
460
  >{{ infraSetup.logs }}</pre>
460
461
  </template>
461
462
  </div>
@@ -467,7 +468,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
467
468
  <div
468
469
  v-if="infraReady"
469
470
  data-testid="tester-env-ready"
470
- class="flex items-center gap-2 rounded-lg border border-app-success-500/30 bg-app-success-500/10 px-3 py-2 text-[13px] text-app-success-200"
471
+ class="flex items-center gap-2 rounded-lg border border-app-success-500/30 bg-app-success-500/10 px-3 py-2 text-sm text-app-success-200"
471
472
  >
472
473
  <UIcon name="i-lucide-rocket" class="h-4 w-4 shrink-0 text-app-success-400" />
473
474
  <span>{{ t('testing.readyBanner') }}</span>
@@ -504,9 +505,9 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
504
505
  how it ended), so the otherwise-opaque fixer sub-jobs have a surface — the
505
506
  analogue of the polling gate's attempt history. -->
506
507
  <section v-if="fixerAttempts.length" data-testid="tester-fixer-attempts" class="space-y-2">
507
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
508
+ <SectionLabel as="h3">
508
509
  {{ t('testing.fixerAttempts') }}
509
- </h3>
510
+ </SectionLabel>
510
511
  <ol class="space-y-2">
511
512
  <li
512
513
  v-for="a in fixerAttempts"
@@ -531,20 +532,20 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
531
532
  <MarkdownProse
532
533
  v-if="a.summary"
533
534
  :text="a.summary"
534
- class="mt-1 max-w-3xl text-[12px] leading-snug text-muted"
535
+ class="mt-1 max-w-3xl text-xs leading-snug text-muted"
535
536
  />
536
537
  <div v-if="a.concerns && a.concerns.length" class="mt-1.5">
537
- <p class="text-[11px] text-dimmed">
538
+ <p class="text-2xs text-dimmed">
538
539
  {{ t('testing.fixerTimeline.addressed') }}
539
540
  </p>
540
541
  <ul class="mt-1 space-y-0.5">
541
542
  <li
542
543
  v-for="(c, ci) in a.concerns"
543
544
  :key="`fa${a.attempt}-c${ci}`"
544
- class="flex items-center gap-1.5 text-[12px] text-toned"
545
+ class="flex items-center gap-1.5 text-xs text-toned"
545
546
  >
546
547
  <span
547
- class="rounded px-1 text-[10px] uppercase"
548
+ class="rounded-sm px-1 text-3xs uppercase"
548
549
  :class="SEVERITY_META[c.severity].chip"
549
550
  >{{ SEVERITY_LABELS[c.severity] }}</span
550
551
  >
@@ -566,12 +567,12 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
566
567
  class="space-y-2"
567
568
  >
568
569
  <div class="flex items-center gap-2">
569
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
570
+ <SectionLabel as="h3">
570
571
  {{ t('testing.quality.heading') }}
571
- </h3>
572
+ </SectionLabel>
572
573
  <span
573
574
  v-if="quality.attempts"
574
- class="text-[11px] text-muted"
575
+ class="text-2xs text-muted"
575
576
  :title="t('testing.quality.reruns')"
576
577
  >
577
578
  {{
@@ -604,30 +605,30 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
604
605
  class="h-3.5 w-3.5 shrink-0"
605
606
  :class="vd.adequate ? 'text-app-success-400' : 'text-app-warning-300'"
606
607
  />
607
- <span class="text-[13px] font-medium text-default">
608
+ <span class="text-sm font-medium text-default">
608
609
  {{
609
610
  vd.adequate ? t('testing.quality.adequate') : t('testing.quality.inadequate')
610
611
  }}
611
612
  </span>
612
- <span v-if="vd.model" class="ms-auto font-mono text-[10px] text-dimmed">{{
613
+ <span v-if="vd.model" class="ms-auto font-mono text-3xs text-dimmed">{{
613
614
  vd.model
614
615
  }}</span>
615
- <span class="text-[11px] text-dimmed" :class="{ 'ms-auto': !vd.model }">{{
616
+ <span class="text-2xs text-dimmed" :class="{ 'ms-auto': !vd.model }">{{
616
617
  d(new Date(vd.at), 'short')
617
618
  }}</span>
618
619
  </div>
619
620
  <MarkdownProse
620
621
  v-if="vd.feedback"
621
622
  :text="vd.feedback"
622
- class="mt-1 text-[12px] leading-snug text-muted"
623
+ class="mt-1 text-xs leading-snug text-muted"
623
624
  />
624
625
  <div v-if="vd.gaps.length" class="mt-1.5">
625
- <p class="text-[11px] text-dimmed">{{ t('testing.quality.gaps') }}</p>
626
+ <p class="text-2xs text-dimmed">{{ t('testing.quality.gaps') }}</p>
626
627
  <ul class="mt-1 space-y-0.5">
627
628
  <li
628
629
  v-for="(gap, gi) in vd.gaps"
629
630
  :key="`qc${vi}-g${gi}`"
630
- class="flex items-start gap-1.5 text-[12px] text-toned"
631
+ class="flex items-start gap-1.5 text-xs text-toned"
631
632
  >
632
633
  <UIcon
633
634
  name="i-lucide-dot"
@@ -647,7 +648,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
647
648
  >
648
649
  <UIcon name="i-lucide-flask-conical" class="h-8 w-8 opacity-40" />
649
650
  <p class="text-sm">{{ t('testing.empty.title') }}</p>
650
- <p class="max-w-sm text-[11px] text-dimmed">
651
+ <p class="max-w-sm text-2xs text-dimmed">
651
652
  {{ t('testing.empty.hint') }}
652
653
  </p>
653
654
  </div>
@@ -659,19 +660,21 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
659
660
  <MarkdownProse
660
661
  v-if="report.summary"
661
662
  :text="report.summary"
662
- class="mb-4 max-w-3xl text-[13px] leading-relaxed text-toned"
663
+ class="mb-4 max-w-3xl text-sm leading-relaxed text-toned"
663
664
  />
664
665
 
665
- <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
666
+ <SectionLabel as="h3" class="mb-2">
666
667
  {{ t('testing.scenariosOutcomes') }}
667
- </h3>
668
+ </SectionLabel>
668
669
  <ul class="space-y-2">
669
670
  <li
670
671
  v-for="g in groups"
671
672
  :key="g.key"
672
673
  class="overflow-hidden rounded-lg border border-default bg-default/60"
673
674
  >
674
- <button
675
+ <UButton
676
+ color="neutral"
677
+ variant="ghost"
675
678
  class="flex w-full items-center gap-2 px-3 py-2 text-start hover:bg-elevated/40"
676
679
  @click="toggle(g.key)"
677
680
  >
@@ -685,7 +688,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
685
688
  :class="GROUP_STATUS_META[g.status].text"
686
689
  />
687
690
  <span
688
- class="min-w-0 flex-1 truncate text-[13px]"
691
+ class="min-w-0 flex-1 truncate text-sm"
689
692
  :class="g.other ? 'text-muted' : 'font-medium text-default'"
690
693
  >
691
694
  {{ g.title }}
@@ -702,14 +705,14 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
702
705
  )
703
706
  "
704
707
  />
705
- <span class="shrink-0 text-[11px] text-dimmed">
708
+ <span class="shrink-0 text-2xs text-dimmed">
706
709
  {{ t('testing.checkCount', { count: g.outcomes.length }, g.outcomes.length) }}
707
710
  <template v-if="g.concerns.length">
708
711
  ·
709
712
  {{ t('testing.concernCount', { count: g.concerns.length }, g.concerns.length) }}
710
713
  </template>
711
714
  </span>
712
- </button>
715
+ </UButton>
713
716
 
714
717
  <div v-if="!collapsed.has(g.key)" class="space-y-1 px-3 pb-3 ps-9">
715
718
  <!-- Outcomes -->
@@ -724,15 +727,15 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
724
727
  :class="STATUS_META[o.status].text"
725
728
  />
726
729
  <div class="min-w-0">
727
- <span class="text-[13px] text-default">{{ o.name }}</span>
730
+ <span class="text-sm text-default">{{ o.name }}</span>
728
731
  <MarkdownProse
729
732
  v-if="o.detail"
730
733
  :text="o.detail"
731
- class="max-w-3xl text-[12px] leading-snug text-muted"
734
+ class="max-w-3xl text-xs leading-snug text-muted"
732
735
  />
733
736
  </div>
734
737
  </div>
735
- <p v-if="!g.outcomes.length" class="py-0.5 text-[12px] italic text-dimmed">
738
+ <p v-if="!g.outcomes.length" class="py-0.5 text-xs italic text-dimmed">
736
739
  {{ t('testing.noDiscreteCheck') }}
737
740
  </p>
738
741
 
@@ -749,9 +752,9 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
749
752
  />
750
753
  <div class="min-w-0">
751
754
  <div class="flex items-center gap-1.5">
752
- <span class="text-[12px] font-medium text-default">{{ c.title }}</span>
755
+ <span class="text-xs font-medium text-default">{{ c.title }}</span>
753
756
  <span
754
- class="rounded px-1 text-[10px] uppercase"
757
+ class="rounded-sm px-1 text-3xs uppercase"
755
758
  :class="SEVERITY_META[c.severity].chip"
756
759
  >
757
760
  {{ SEVERITY_LABELS[c.severity] }}
@@ -760,18 +763,20 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
760
763
  <MarkdownProse
761
764
  v-if="c.detail"
762
765
  :text="c.detail"
763
- class="max-w-3xl text-[12px] leading-snug text-muted"
766
+ class="max-w-3xl text-xs leading-snug text-muted"
764
767
  />
765
768
  </div>
766
769
  </div>
767
770
 
768
771
  <!-- Screenshots captured for this scenario -->
769
772
  <div v-if="g.screenshots.length" class="mt-2 flex flex-wrap gap-2">
770
- <button
773
+ <UButton
774
+ color="neutral"
775
+ variant="ghost"
771
776
  v-for="(s, si) in g.screenshots"
772
777
  :key="`shot${si}`"
773
778
  data-testid="tester-screenshot"
774
- class="group relative h-20 w-28 shrink-0 overflow-hidden rounded border border-default bg-app-950/60 hover:border-app-600"
779
+ class="group relative block h-20 w-28 shrink-0 overflow-hidden rounded-sm border border-default bg-app-950/60 hover:bg-app-950/60 focus-visible:bg-app-950/60 disabled:bg-app-950/60 p-0 hover:border-app-600"
775
780
  :title="s.view"
776
781
  @click="openShot(s.artifactId)"
777
782
  >
@@ -783,7 +788,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
783
788
  />
784
789
  <span
785
790
  v-else
786
- class="flex h-full w-full items-center justify-center text-[10px] text-app-600"
791
+ class="flex h-full w-full items-center justify-center text-3xs text-app-600"
787
792
  >
788
793
  {{
789
794
  blobs.statusFor(s.artifactId) === 'error'
@@ -792,10 +797,10 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
792
797
  }}
793
798
  </span>
794
799
  <span
795
- class="absolute inset-x-0 bottom-0 truncate bg-app-950/80 px-1 py-0.5 text-[9px] text-toned"
800
+ class="absolute inset-x-0 bottom-0 truncate bg-app-950/80 px-1 py-0.5 text-3xs text-toned"
796
801
  >{{ s.view }}</span
797
802
  >
798
- </button>
803
+ </UButton>
799
804
  </div>
800
805
  </div>
801
806
  </li>
@@ -803,14 +808,16 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
803
808
 
804
809
  <!-- Standalone gallery: any captures not mapped to a scenario above -->
805
810
  <section v-if="ungroupedScreenshots.length" class="mt-5">
806
- <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
811
+ <SectionLabel as="h3" class="mb-2">
807
812
  {{ t('testing.screenshots') }}
808
- </h3>
813
+ </SectionLabel>
809
814
  <div class="grid grid-cols-2 gap-3 sm:grid-cols-3">
810
- <button
815
+ <UButton
816
+ color="neutral"
817
+ variant="ghost"
811
818
  v-for="(s, si) in ungroupedScreenshots"
812
819
  :key="`gal${si}`"
813
- class="group relative aspect-video overflow-hidden rounded-lg border border-default bg-app-950/60 hover:border-app-600"
820
+ class="group relative block aspect-video overflow-hidden rounded-lg border border-default bg-app-950/60 hover:bg-app-950/60 focus-visible:bg-app-950/60 disabled:bg-app-950/60 p-0 hover:border-app-600"
814
821
  :title="s.view"
815
822
  @click="openShot(s.artifactId)"
816
823
  >
@@ -822,7 +829,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
822
829
  />
823
830
  <span
824
831
  v-else
825
- class="flex h-full w-full items-center justify-center text-[11px] text-app-600"
832
+ class="flex h-full w-full items-center justify-center text-2xs text-app-600"
826
833
  >
827
834
  {{
828
835
  blobs.statusFor(s.artifactId) === 'error'
@@ -831,10 +838,10 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
831
838
  }}
832
839
  </span>
833
840
  <span
834
- class="absolute inset-x-0 bottom-0 truncate bg-app-950/80 px-1.5 py-0.5 text-[10px] text-toned"
841
+ class="absolute inset-x-0 bottom-0 truncate bg-app-950/80 px-1.5 py-0.5 text-3xs text-toned"
835
842
  >{{ s.view }}</span
836
843
  >
837
- </button>
844
+ </UButton>
838
845
  </div>
839
846
  </section>
840
847
  </template>
@@ -845,10 +852,10 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
845
852
  class="hidden w-60 shrink-0 flex-col gap-4 border-s border-default bg-default/50 px-4 py-4 lg:flex"
846
853
  >
847
854
  <div v-if="report">
848
- <h4 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
855
+ <SectionLabel as="h4" class="mb-2">
849
856
  {{ t('testing.verdict.heading') }}
850
- </h4>
851
- <div class="flex items-center gap-2 text-[13px]">
857
+ </SectionLabel>
858
+ <div class="flex items-center gap-2 text-sm">
852
859
  <UIcon
853
860
  :name="report.greenlight ? 'i-lucide-circle-check' : 'i-lucide-circle-x'"
854
861
  class="h-4 w-4"
@@ -861,10 +868,10 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
861
868
  </div>
862
869
 
863
870
  <div v-if="report">
864
- <h4 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
871
+ <SectionLabel as="h4" class="mb-2">
865
872
  {{ t('testing.outcomes.heading') }}
866
- </h4>
867
- <dl class="space-y-1 text-[12px]">
873
+ </SectionLabel>
874
+ <dl class="space-y-1 text-xs">
868
875
  <div class="flex items-center justify-between">
869
876
  <dt class="text-muted">{{ t('testing.outcomes.passed') }}</dt>
870
877
  <dd class="text-app-success-300">{{ counts.passed }}</dd>
@@ -892,10 +899,10 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
892
899
  </div>
893
900
 
894
901
  <div v-if="report?.environment">
895
- <h4 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
902
+ <SectionLabel as="h4" class="mb-1">
896
903
  {{ t('testing.environment') }}
897
- </h4>
898
- <p class="text-[12px] capitalize text-toned">{{ report.environment }}</p>
904
+ </SectionLabel>
905
+ <p class="text-xs capitalize text-toned">{{ report.environment }}</p>
899
906
  </div>
900
907
 
901
908
  <!-- Shared run metadata + embedded observability (model, run id, timing,
@@ -910,7 +917,7 @@ const GROUP_STATUS_META: Record<ScenarioGroup['status'], { icon: string; text: s
910
917
  :failure-at="instance?.failure?.occurredAt"
911
918
  />
912
919
 
913
- <p class="mt-auto text-[10px] leading-relaxed text-app-600">
920
+ <p class="mt-auto text-3xs leading-relaxed text-app-600">
914
921
  {{ t('testing.footer') }}
915
922
  </p>
916
923
  </aside>
@@ -66,7 +66,7 @@ async function submit() {
66
66
  :description="t('appearance.import.description')"
67
67
  >
68
68
  <template #body>
69
- <form class="space-y-4" data-testid="theme-import-form" @submit.prevent="submit">
69
+ <UForm class="space-y-4" data-testid="theme-import-form" @submit="submit">
70
70
  <UFormField
71
71
  :label="t('appearance.import.linkLabel')"
72
72
  :error="error ? t(ERROR_KEYS[error]) : undefined"
@@ -109,7 +109,7 @@ async function submit() {
109
109
  {{ t('appearance.import.submit') }}
110
110
  </UButton>
111
111
  </div>
112
- </form>
112
+ </UForm>
113
113
  </template>
114
114
  </UModal>
115
115
  </template>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
+ import SectionLabel from '~/components/common/SectionLabel.vue'
3
4
 
4
5
  // The contextual offer's surface: one walkthrough, offered beside the work that just made it
5
6
  // relevant. Deliberately NOT a modal — the whole point is the moment, and a modal would
@@ -75,9 +76,9 @@ function take(tourId: string) {
75
76
  class="text-primary mt-0.5 h-4 w-4 shrink-0"
76
77
  />
77
78
  <div class="min-w-0 flex-1">
78
- <p class="text-[11px] tracking-wide text-muted uppercase">
79
+ <SectionLabel as="p">
79
80
  {{ t('tutorial.nudge.label') }}
80
- </p>
81
+ </SectionLabel>
81
82
  <p class="mt-0.5 text-sm font-medium text-app-100">{{ t(offered.titleKey) }}</p>
82
83
  <p class="mt-0.5 text-xs text-muted">{{ t(offered.descriptionKey) }}</p>
83
84
  </div>
@@ -20,6 +20,7 @@ import {
20
20
  waitBudgetMs,
21
21
  } from './TutorialOverlay.logic'
22
22
  import type { TutorialAdvanceCause, TutorialDirection } from './TutorialOverlay.logic'
23
+ import SectionLabel from '~/components/common/SectionLabel.vue'
23
24
 
24
25
  // The one shared tour runtime: resolves the running tour from the `tutorialTours` slot,
25
26
  // anchors a highlight ring + tooltip to the current step's `data-testid`, and advances
@@ -628,9 +629,9 @@ onUnmounted(() => {
628
629
  class="mt-3 rounded-lg border border-muted/70 bg-elevated/40 p-2.5"
629
630
  data-testid="tutorial-next-tour"
630
631
  >
631
- <p class="text-[11px] tracking-wide text-muted uppercase">
632
+ <SectionLabel as="p">
632
633
  {{ t('tutorial.overlay.nextUp') }}
633
- </p>
634
+ </SectionLabel>
634
635
  <p class="mt-0.5 text-sm font-medium text-app-100">{{ t(nextTour.titleKey) }}</p>
635
636
  <p class="mt-0.5 text-xs text-muted">{{ t(nextTour.descriptionKey) }}</p>
636
637
  <UButton
@@ -67,7 +67,7 @@ async function connect() {
67
67
  />
68
68
  </UFormField>
69
69
 
70
- <p class="text-[11px] text-dimmed">
70
+ <p class="text-2xs text-dimmed">
71
71
  <ULink :to="tokenUrl" target="_blank" class="text-primary hover:underline">
72
72
  {{ t('vcs.connect.gitlab.createToken') }}
73
73
  </ULink>