@cat-factory/app 0.308.0 → 0.309.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 (243) hide show
  1. package/README.md +21 -0
  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 +3 -2
  6. package/app/components/auth/UserMenu.vue +1 -1
  7. package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +15 -15
  8. package/app/components/binaryOutput/BinaryOutputReport.vue +10 -14
  9. package/app/components/binaryOutput/StoredAssetView.vue +5 -5
  10. package/app/components/board/AddTaskModal.vue +16 -14
  11. package/app/components/board/AgentFailureCard.vue +9 -9
  12. package/app/components/board/AgentFailureHistory.vue +1 -1
  13. package/app/components/board/CreateInitiativeModal.vue +2 -2
  14. package/app/components/board/FailureDetail.vue +1 -1
  15. package/app/components/board/FailureHistoryList.vue +5 -5
  16. package/app/components/board/RecurringPipelineModal.vue +12 -11
  17. package/app/components/board/ReviewFrictionDialog.vue +4 -3
  18. package/app/components/board/StepExecutionHistory.vue +8 -8
  19. package/app/components/board/nodes/AgentChip.vue +1 -1
  20. package/app/components/board/nodes/BlockNode.vue +8 -9
  21. package/app/components/board/nodes/EpicNode.vue +4 -4
  22. package/app/components/board/nodes/FrameSwimlanes.vue +4 -7
  23. package/app/components/board/nodes/InitiativeCard.vue +4 -4
  24. package/app/components/board/nodes/LaneGroup.vue +3 -5
  25. package/app/components/board/nodes/TaskCard.vue +8 -8
  26. package/app/components/board/nodes/TaskLane.vue +3 -3
  27. package/app/components/board/nodes/TaskPipelineMini.vue +13 -12
  28. package/app/components/bootstrap/AdoptionReviewModal.vue +7 -6
  29. package/app/components/bootstrap/BootstrapModal.vue +11 -10
  30. package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
  31. package/app/components/brainstorm/BrainstormWindow.vue +8 -7
  32. package/app/components/bugFishing/BugFishingWindow.vue +37 -36
  33. package/app/components/clarity/ClarityReviewWindow.vue +8 -7
  34. package/app/components/common/AsyncViewError.vue +1 -1
  35. package/app/components/common/ClarificationItem.vue +6 -6
  36. package/app/components/common/DescriptorFields.vue +1 -1
  37. package/app/components/common/EmptyState.vue +1 -1
  38. package/app/components/common/InterviewGateNotice.vue +4 -4
  39. package/app/components/common/MarkdownProse.vue +8 -2
  40. package/app/components/common/SectionLabel.vue +38 -0
  41. package/app/components/consensus/ConsensusSessionWindow.vue +10 -9
  42. package/app/components/context/ContextAttachmentFields.vue +9 -8
  43. package/app/components/docs/DocInterviewWindow.vue +10 -9
  44. package/app/components/documents/ContextDocumentPicker.vue +10 -12
  45. package/app/components/documents/DocumentImportModal.vue +3 -2
  46. package/app/components/documents/DocumentSourceConnectModal.vue +2 -2
  47. package/app/components/documents/DocumentSyncState.vue +1 -1
  48. package/app/components/documents/DocumentTemplatesModal.vue +5 -4
  49. package/app/components/documents/RepoContextDocPicker.vue +3 -6
  50. package/app/components/documents/StartFromDesignModal.vue +4 -4
  51. package/app/components/documents/TaskContextDocs.vue +1 -1
  52. package/app/components/environments/EnvSetupStepper.vue +3 -3
  53. package/app/components/environments/EnvironmentStatusPanel.vue +11 -10
  54. package/app/components/environments/steps/EnvPreflightStep.vue +8 -8
  55. package/app/components/environments/steps/EnvReviewStep.vue +23 -22
  56. package/app/components/environments/steps/EnvSaveStep.vue +5 -5
  57. package/app/components/focus/BlockFocusView.vue +11 -10
  58. package/app/components/followUp/FollowUpWindow.vue +10 -10
  59. package/app/components/forkDecision/ForkDecisionWindow.vue +23 -26
  60. package/app/components/foundational/FoundationalContractSummary.vue +2 -2
  61. package/app/components/foundational/FoundationalServiceCatalogList.vue +3 -3
  62. package/app/components/foundational/FoundationalServiceRegistry.vue +3 -3
  63. package/app/components/foundational/FoundationalSuppressions.vue +2 -2
  64. package/app/components/fragments/FragmentLibraryManager.vue +3 -3
  65. package/app/components/fragments/FragmentSelector.vue +10 -11
  66. package/app/components/gates/GateFailingCheckList.vue +3 -3
  67. package/app/components/gates/GateResultView.vue +39 -38
  68. package/app/components/github/AddServiceFromRepoModal.vue +5 -4
  69. package/app/components/github/BranchProtectionPreflight.vue +5 -5
  70. package/app/components/github/GitHubConnect.vue +5 -3
  71. package/app/components/github/GitHubPanel.vue +14 -13
  72. package/app/components/github/RepoTreeBrowser.vue +1 -1
  73. package/app/components/humanTest/HumanTestWindow.vue +18 -17
  74. package/app/components/initiative/InitiativePlanNotice.vue +3 -3
  75. package/app/components/initiative/InitiativePlanReview.vue +19 -21
  76. package/app/components/initiative/InitiativePlanningWindow.vue +5 -5
  77. package/app/components/initiative/InitiativeTrackerWindow.vue +54 -53
  78. package/app/components/judge/JudgeResultView.vue +24 -25
  79. package/app/components/kaizen/KaizenPanel.vue +4 -4
  80. package/app/components/kaizen/KaizenStepStatus.vue +7 -6
  81. package/app/components/layout/AccountAuditLog.vue +1 -1
  82. package/app/components/layout/AccountDeploymentSettings.vue +10 -10
  83. package/app/components/layout/AccountFailureKindRules.vue +13 -13
  84. package/app/components/layout/AccountFoundationalSettings.vue +1 -1
  85. package/app/components/layout/AccountFragmentSettings.vue +1 -1
  86. package/app/components/layout/AccountModelPolicySettings.vue +7 -7
  87. package/app/components/layout/AccountPlatformAlertSettings.vue +8 -8
  88. package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
  89. package/app/components/layout/AccountRunCredentialSettings.vue +3 -3
  90. package/app/components/layout/AccountSkillSettings.vue +1 -1
  91. package/app/components/layout/AccountTeamSettings.vue +4 -0
  92. package/app/components/layout/AiProvidersBanner.vue +1 -1
  93. package/app/components/layout/AppearanceSwitcher.vue +1 -1
  94. package/app/components/layout/BoardSwitcher.vue +3 -2
  95. package/app/components/layout/BoardToolbar.vue +6 -2
  96. package/app/components/layout/CommandBar.vue +4 -2
  97. package/app/components/layout/DefaultTestEnvBanner.vue +2 -2
  98. package/app/components/layout/IntegrationsHub.vue +4 -3
  99. package/app/components/layout/LanguageSwitcher.vue +1 -1
  100. package/app/components/layout/ModelProvidersHub.vue +6 -4
  101. package/app/components/layout/NotificationsInbox.vue +8 -7
  102. package/app/components/layout/PersonalSetupModal.vue +5 -3
  103. package/app/components/layout/RolePrompt.vue +1 -1
  104. package/app/components/layout/SideBar.vue +3 -5
  105. package/app/components/layout/SpendWarningBanner.vue +3 -3
  106. package/app/components/layout/TranslationWarningBanner.vue +1 -1
  107. package/app/components/layout/UiModeSwitcher.vue +7 -6
  108. package/app/components/layout/UiRoleSwitcher.vue +2 -2
  109. package/app/components/media/ArtifactLightbox.vue +6 -6
  110. package/app/components/media/ImageCompare.vue +16 -16
  111. package/app/components/merge/MergeEffortChips.vue +4 -6
  112. package/app/components/notifications/NotificationSettingsPanel.vue +6 -5
  113. package/app/components/observability/OutcomeFilterChips.vue +1 -1
  114. package/app/components/observability/RunFailureSummary.vue +14 -17
  115. package/app/components/observability/StepMetricsBar.vue +9 -8
  116. package/app/components/observability/StepModelActivity.vue +4 -3
  117. package/app/components/observability/ToolCallList.vue +15 -18
  118. package/app/components/outcome/OutcomeSummaryWindow.vue +43 -42
  119. package/app/components/palettes/AgentPalette.vue +7 -5
  120. package/app/components/palettes/AgentTierSelect.vue +1 -1
  121. package/app/components/palettes/PipelinePurposeSelect.vue +1 -1
  122. package/app/components/panels/AgentStepDetail.vue +27 -30
  123. package/app/components/panels/AttemptEntryHeader.vue +2 -2
  124. package/app/components/panels/DecisionModal.vue +1 -1
  125. package/app/components/panels/GenericStructuredResultView.vue +6 -5
  126. package/app/components/panels/InspectorPanel.vue +15 -13
  127. package/app/components/panels/MergerResultView.vue +10 -9
  128. package/app/components/panels/ObservabilityPanel.vue +66 -76
  129. package/app/components/panels/OperatorDashboardPanel.vue +27 -26
  130. package/app/components/panels/ReportsPanel.vue +26 -25
  131. package/app/components/panels/ReportsSpendBreakdown.vue +2 -2
  132. package/app/components/panels/ResultWindowShell.vue +19 -18
  133. package/app/components/panels/RunDetailLoadState.vue +1 -1
  134. package/app/components/panels/StepContainerStatus.vue +8 -7
  135. package/app/components/panels/StepDelegatedStatus.vue +13 -12
  136. package/app/components/panels/StepEffortReport.vue +12 -17
  137. package/app/components/panels/StepFragmentAdherence.vue +9 -10
  138. package/app/components/panels/StepMetadataCard.vue +41 -43
  139. package/app/components/panels/StepReproductionReport.vue +18 -20
  140. package/app/components/panels/StepRunMeta.vue +27 -26
  141. package/app/components/panels/StepTestReport.vue +16 -15
  142. package/app/components/panels/StepToolServers.vue +7 -8
  143. package/app/components/panels/StepValidationReport.vue +5 -5
  144. package/app/components/panels/inspector/ContainerSummary.vue +4 -4
  145. package/app/components/panels/inspector/DocReferenceRepos.vue +5 -4
  146. package/app/components/panels/inspector/EnvProbeReport.vue +16 -13
  147. package/app/components/panels/inspector/EpicChildren.vue +8 -7
  148. package/app/components/panels/inspector/FrontendBindingsResolved.vue +5 -4
  149. package/app/components/panels/inspector/FrontendConfig.vue +26 -34
  150. package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
  151. package/app/components/panels/inspector/InspectorSection.vue +7 -4
  152. package/app/components/panels/inspector/RecurringScheduleSettings.vue +9 -8
  153. package/app/components/panels/inspector/ServiceConnections.vue +2 -2
  154. package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -2
  155. package/app/components/panels/inspector/ServiceSelfTests.vue +9 -13
  156. package/app/components/panels/inspector/ServiceTestConfig.vue +41 -45
  157. package/app/components/panels/inspector/ServiceTestSecrets.vue +3 -3
  158. package/app/components/panels/inspector/ServiceTestingContext.vue +2 -2
  159. package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
  160. package/app/components/panels/inspector/TaskAgentConfig.vue +2 -2
  161. package/app/components/panels/inspector/TaskAprioriBranches.vue +6 -5
  162. package/app/components/panels/inspector/TaskDependencies.vue +1 -1
  163. package/app/components/panels/inspector/TaskEstimateBadge.vue +3 -7
  164. package/app/components/panels/inspector/TaskExecution.vue +13 -12
  165. package/app/components/panels/inspector/TaskRunSettings.vue +35 -38
  166. package/app/components/panels/inspector/TaskStructure.vue +5 -4
  167. package/app/components/pipeline/AgentPromptEditor.vue +15 -14
  168. package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -52
  169. package/app/components/pipeline/EstimateThresholdFields.vue +2 -2
  170. package/app/components/pipeline/GateConfigFields.vue +6 -6
  171. package/app/components/pipeline/IterationCapPrompt.vue +1 -1
  172. package/app/components/pipeline/PipelineBuilder.vue +28 -27
  173. package/app/components/pipeline/PipelineHealthModal.vue +7 -7
  174. package/app/components/pipeline/PipelinePicker.vue +3 -3
  175. package/app/components/pipeline/PipelinePreview.vue +6 -7
  176. package/app/components/pipeline/PipelineProgress.vue +23 -24
  177. package/app/components/prReview/PrReviewWindow.vue +42 -41
  178. package/app/components/providers/AiPresetMismatchDialog.vue +4 -3
  179. package/app/components/providers/AiProviderOnboardingModal.vue +2 -2
  180. package/app/components/providers/ApiKeysSection.vue +7 -6
  181. package/app/components/providers/PersonalSubscriptionSection.vue +4 -3
  182. package/app/components/providers/VendorCredentialsModal.vue +5 -4
  183. package/app/components/provisioning/ProvisioningLogsDrawer.vue +10 -9
  184. package/app/components/ralph/RalphLoopResultView.vue +25 -26
  185. package/app/components/requirements/RequirementsReviewWindow.vue +13 -12
  186. package/app/components/riskPolicy/RiskPolicyPicker.vue +5 -5
  187. package/app/components/riskPolicy/RiskPolicyPreview.vue +16 -15
  188. package/app/components/sandbox/SandboxPanel.vue +21 -20
  189. package/app/components/settings/ApiTokensPanel.vue +1 -1
  190. package/app/components/settings/BudgetSettings.vue +18 -17
  191. package/app/components/settings/CapabilityCredentialsPanel.vue +5 -5
  192. package/app/components/settings/CloudflareHandlerSection.vue +16 -16
  193. package/app/components/settings/ComposeEnvironmentSetupSection.vue +14 -12
  194. package/app/components/settings/ConnectionTestVerdict.vue +1 -1
  195. package/app/components/settings/ConsensusGroupsSection.vue +21 -20
  196. package/app/components/settings/CustomManifestTypeEditor.vue +8 -7
  197. package/app/components/settings/DefaultProvisionTypeSection.vue +5 -5
  198. package/app/components/settings/InfraHandlersConfigurator.vue +14 -15
  199. package/app/components/settings/InfrastructureBackendPicker.vue +2 -2
  200. package/app/components/settings/IssueTrackerPanel.vue +9 -15
  201. package/app/components/settings/KubernetesEngineForm.vue +9 -8
  202. package/app/components/settings/KubernetesEnvironmentForm.vue +4 -3
  203. package/app/components/settings/LocalContainerPoolSettings.vue +2 -2
  204. package/app/components/settings/LocalModelEndpointsPanel.vue +10 -9
  205. package/app/components/settings/MergeClassRulesEditor.vue +6 -5
  206. package/app/components/settings/MergeRolePolicyEditor.vue +13 -12
  207. package/app/components/settings/ModelConfigurationPanel.vue +8 -11
  208. package/app/components/settings/ModelPresetHealthModal.vue +3 -3
  209. package/app/components/settings/ObservabilityConnectionPanel.vue +1 -1
  210. package/app/components/settings/OpenRouterCatalogPanel.vue +6 -5
  211. package/app/components/settings/PackageRegistriesPanel.vue +4 -4
  212. package/app/components/settings/ProviderConnectionTab.vue +5 -4
  213. package/app/components/settings/ProviderManifestEditor.vue +9 -8
  214. package/app/components/settings/ProviderPreferenceEditor.vue +8 -7
  215. package/app/components/settings/RiskPolicyCreateForm.vue +40 -26
  216. package/app/components/settings/RiskPolicyEditorRow.vue +18 -17
  217. package/app/components/settings/RiskPolicyHealthModal.vue +3 -3
  218. package/app/components/settings/RiskPolicyPanel.vue +11 -13
  219. package/app/components/settings/ServiceFragmentDefaultsPanel.vue +5 -4
  220. package/app/components/settings/SharedStacksPanel.vue +5 -5
  221. package/app/components/settings/TaskSourceCard.vue +2 -2
  222. package/app/components/settings/TaskTypeSuppressionsPanel.vue +4 -4
  223. package/app/components/settings/ToolServerChecklist.vue +22 -22
  224. package/app/components/settings/UsageSettings.vue +13 -13
  225. package/app/components/settings/UserSecretsSection.vue +4 -3
  226. package/app/components/settings/WorkspaceMetadataSettings.vue +6 -5
  227. package/app/components/settings/WorkspaceSettingsPanel.vue +72 -58
  228. package/app/components/skills/ReviewSkillQueue.vue +8 -7
  229. package/app/components/skills/SkillLibraryManager.vue +2 -2
  230. package/app/components/slack/SlackPanel.vue +8 -7
  231. package/app/components/spec/ServiceSpecWindow.vue +15 -16
  232. package/app/components/tasks/BugHuntModal.vue +1 -1
  233. package/app/components/tasks/ContextIssuePicker.vue +4 -6
  234. package/app/components/tasks/TaskContextIssues.vue +1 -1
  235. package/app/components/tasks/TaskImportModal.vue +3 -2
  236. package/app/components/tasks/TaskSourceConnectModal.vue +5 -5
  237. package/app/components/testing/TestReportWindow.vue +54 -53
  238. package/app/components/tutorial/TutorialNudge.vue +3 -2
  239. package/app/components/tutorial/TutorialOverlay.vue +3 -2
  240. package/app/components/vcs/GitLabConnect.vue +1 -1
  241. package/app/components/visualConfirm/VisualConfirmationWindow.vue +23 -25
  242. package/app/utils/theme/builtins.ts +7 -1
  243. package/package.json +1 -1
@@ -25,6 +25,7 @@ import type {
25
25
  NotificationType,
26
26
  } from '~/types/notifications'
27
27
  import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
28
+ import SectionLabel from '~/components/common/SectionLabel.vue'
28
29
 
29
30
  const ui = useUiStore()
30
31
  const notifications = useNotificationsStore()
@@ -174,11 +175,11 @@ function resetToDefaults() {
174
175
  </div>
175
176
 
176
177
  <template v-else>
177
- <div class="flex items-center gap-3 px-2 text-[10px] uppercase tracking-wide text-dimmed">
178
+ <SectionLabel class="flex items-center gap-3 px-2">
178
179
  <span class="flex-1">{{ t('notificationSettings.column.event') }}</span>
179
180
  <span class="w-16 text-center">{{ t('notificationSettings.column.inApp') }}</span>
180
181
  <span class="w-16 text-center">{{ t('notificationSettings.column.email') }}</span>
181
- </div>
182
+ </SectionLabel>
182
183
 
183
184
  <div class="max-h-[50vh] space-y-1 overflow-y-auto pr-1">
184
185
  <div
@@ -198,13 +199,13 @@ function resetToDefaults() {
198
199
  </div>
199
200
  </div>
200
201
 
201
- <p class="text-[11px] text-dimmed">
202
+ <p class="text-2xs text-dimmed">
202
203
  {{ t('notificationSettings.panel.inAppNote') }}
203
204
  </p>
204
- <p class="text-[11px] text-dimmed">
205
+ <p class="text-2xs text-dimmed">
205
206
  {{ t('notificationSettings.panel.emailNote') }}
206
207
  </p>
207
- <p class="text-[11px] text-dimmed">
208
+ <p class="text-2xs text-dimmed">
208
209
  {{ t('notificationSettings.panel.otherChannelsNote') }}
209
210
  <UButton
210
211
  v-if="slack.available"
@@ -24,7 +24,7 @@ function toneClass(option: (typeof props.options)[number], active: boolean): str
24
24
  </script>
25
25
 
26
26
  <template>
27
- <div class="flex rounded-lg border border-default p-0.5 text-[12px]">
27
+ <div class="flex rounded-lg border border-default p-0.5 text-xs">
28
28
  <button
29
29
  v-for="option in options"
30
30
  :key="option.value"
@@ -86,15 +86,15 @@ const earlierFailedToolCalls = computed(() =>
86
86
  <div class="flex items-start gap-3">
87
87
  <UIcon name="i-lucide-siren" class="mt-0.5 h-5 w-5 shrink-0 text-app-error-400" />
88
88
  <div class="min-w-0 flex-1">
89
- <h2 class="text-[13px] font-semibold text-app-error-200">
89
+ <h2 class="text-sm font-semibold text-app-error-200">
90
90
  {{ t('observability.failure.title') }}
91
91
  </h2>
92
92
 
93
93
  <!-- The run's own structured record. Absent on a run that is still going, or that
94
94
  failed without one; the evidence below stands on its own either way. -->
95
95
  <template v-if="evidence.failure">
96
- <p class="mt-1 text-[13px] text-default">{{ evidence.failure.message }}</p>
97
- <div class="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-[11px] text-dimmed">
96
+ <p class="mt-1 text-sm text-default">{{ evidence.failure.message }}</p>
97
+ <div class="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-2xs text-dimmed">
98
98
  <span>{{ t('observability.failure.kind', { kind: failureKindLabel }) }}</span>
99
99
  <span v-if="evidence.failure.stepIndex != null">
100
100
  {{ t('observability.failure.atStep', { index: evidence.failure.stepIndex + 1 }) }}
@@ -108,10 +108,10 @@ const earlierFailedToolCalls = computed(() =>
108
108
  <FailureDetail
109
109
  :detail="evidence.failure.detail"
110
110
  :message="evidence.failure.message"
111
- summary-class="text-[11px] text-dimmed hover:text-toned"
112
- pre-class="bg-app-950/60 text-[11px] text-muted"
111
+ summary-class="text-2xs text-dimmed hover:text-toned"
112
+ pre-class="bg-app-950/60 text-2xs text-muted"
113
113
  />
114
- <p v-if="evidence.failure.hint" class="mt-1.5 text-[12px] text-toned">
114
+ <p v-if="evidence.failure.hint" class="mt-1.5 text-xs text-toned">
115
115
  {{ evidence.failure.hint }}
116
116
  </p>
117
117
  </template>
@@ -133,7 +133,7 @@ const earlierFailedToolCalls = computed(() =>
133
133
  :style="{ color: agentMeta(evidence.lastErroredCall.agentKind).color }"
134
134
  />
135
135
  <div class="min-w-0 flex-1">
136
- <div class="flex flex-wrap items-baseline gap-x-2 text-[12px]">
136
+ <div class="flex flex-wrap items-baseline gap-x-2 text-xs">
137
137
  <span class="font-medium text-default">
138
138
  {{ t('observability.failure.lastErroredCall') }}
139
139
  </span>
@@ -145,13 +145,10 @@ const earlierFailedToolCalls = computed(() =>
145
145
  {{ evidence.lastErroredCall.httpStatus ?? t('observability.call.error') }}
146
146
  </UBadge>
147
147
  </div>
148
- <p
149
- v-if="evidence.lastErroredCall.errorMessage"
150
- class="mt-0.5 text-[12px] text-app-error-300"
151
- >
148
+ <p v-if="evidence.lastErroredCall.errorMessage" class="mt-0.5 text-xs text-app-error-300">
152
149
  {{ evidence.lastErroredCall.errorMessage }}
153
150
  </p>
154
- <p v-if="evidence.erroredCallCount > 1" class="mt-0.5 text-[11px] text-dimmed">
151
+ <p v-if="evidence.erroredCallCount > 1" class="mt-0.5 text-2xs text-dimmed">
155
152
  {{
156
153
  t(
157
154
  'observability.failure.moreErroredCalls',
@@ -173,7 +170,7 @@ const earlierFailedToolCalls = computed(() =>
173
170
  >
174
171
  <UIcon name="i-lucide-wrench" class="mt-0.5 h-4 w-4 shrink-0 text-app-error-400" />
175
172
  <div class="min-w-0 flex-1">
176
- <div class="flex flex-wrap items-baseline gap-x-2 text-[12px]">
173
+ <div class="flex flex-wrap items-baseline gap-x-2 text-xs">
177
174
  <span class="font-medium text-default">
178
175
  <!-- "One of the failing calls" when even the failures were bounded: the row is
179
176
  real either way, but calling it the LAST would be a claim about rows this
@@ -191,16 +188,16 @@ const earlierFailedToolCalls = computed(() =>
191
188
  </div>
192
189
  <pre
193
190
  v-if="failedToolResult"
194
- class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap text-[11px] leading-relaxed text-app-error-300"
191
+ class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap text-2xs leading-relaxed text-app-error-300"
195
192
  >{{ failedToolResult }}</pre>
196
- <p v-else class="mt-0.5 text-[11px] italic text-dimmed">
193
+ <p v-else class="mt-0.5 text-2xs italic text-dimmed">
197
194
  {{
198
195
  evidence.lastFailedToolCall.bodies === 'stored'
199
196
  ? t('observability.failure.toolReturnedNothing')
200
197
  : t('observability.failure.toolBodiesWithheld')
201
198
  }}
202
199
  </p>
203
- <p v-if="earlierFailedToolCalls" class="mt-0.5 text-[11px] text-dimmed">
200
+ <p v-if="earlierFailedToolCalls" class="mt-0.5 text-2xs text-dimmed">
204
201
  {{
205
202
  t(
206
203
  'observability.failure.moreFailedToolCalls',
@@ -220,7 +217,7 @@ const earlierFailedToolCalls = computed(() =>
220
217
  come back from being reported as one that came back clean. -->
221
218
  <div
222
219
  v-else-if="emptyReason"
223
- class="flex flex-wrap items-center justify-between gap-2 rounded-lg border border-dashed px-3 py-2 text-[12px]"
220
+ class="flex flex-wrap items-center justify-between gap-2 rounded-lg border border-dashed px-3 py-2 text-xs"
224
221
  :class="
225
222
  emptyReason === 'sink-unreachable'
226
223
  ? 'border-app-warning-900/60 text-app-warning-300'
@@ -11,6 +11,7 @@ import {
11
11
  totalInputTokens,
12
12
  transportRatio,
13
13
  } from '~/utils/observability'
14
+ import SectionLabel from '~/components/common/SectionLabel.vue'
14
15
 
15
16
  // Compact, at-a-glance LLM rollup for one pipeline step: token usage, an
16
17
  // output-limit headroom bar (how close the step ran to truncation), a
@@ -57,7 +58,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
57
58
  <template>
58
59
  <div
59
60
  v-if="m.calls > 0"
60
- class="rounded-lg border border-default bg-default/40 p-2.5 text-[12px]"
61
+ class="rounded-lg border border-default bg-default/40 p-2.5 text-xs"
61
62
  :class="clickable ? 'cursor-pointer transition hover:border-muted hover:bg-default/70' : ''"
62
63
  :role="clickable ? 'button' : undefined"
63
64
  @click="clickable ? $emit('inspect') : undefined"
@@ -88,13 +89,13 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
88
89
  >
89
90
  {{ onSubscription ? `~${cost}` : cost }}
90
91
  </span>
91
- <span
92
+ <SectionLabel
92
93
  v-if="onSubscription"
93
- class="text-[10px] uppercase tracking-wide text-dimmed"
94
+ as="span"
94
95
  :title="t('observability.metricsBar.subscriptionCostHint')"
95
96
  >
96
97
  {{ t('observability.metricsBar.subscription') }}
97
- </span>
98
+ </SectionLabel>
98
99
  </template>
99
100
  <div class="ms-auto flex items-center gap-1">
100
101
  <UBadge v-if="m.errors > 0" color="error" variant="subtle" size="sm">
@@ -112,7 +113,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
112
113
  </div>
113
114
 
114
115
  <!-- input breakdown: the headline's three classes, priced an order of magnitude apart -->
115
- <div v-if="hasCache" class="mt-1.5 flex items-center gap-1.5 text-[11px] tabular-nums">
116
+ <div v-if="hasCache" class="mt-1.5 flex items-center gap-1.5 text-2xs tabular-nums">
116
117
  <span class="text-muted" :title="t('observability.metricsBar.freshHint')">
117
118
  {{ t('observability.metricsBar.fresh', { tokens: formatTokens(m.promptTokens) }) }}
118
119
  </span>
@@ -136,7 +137,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
136
137
 
137
138
  <!-- output-limit headroom -->
138
139
  <div v-if="headroom !== null" class="mt-2">
139
- <div class="flex items-center justify-between text-[11px]">
140
+ <div class="flex items-center justify-between text-2xs">
140
141
  <span class="text-dimmed">{{ t('observability.metricsBar.outputLimit') }}</span>
141
142
  <span class="tabular-nums" :class="headroomTone">
142
143
  {{ formatTokens(m.peakCompletionTokens) }} /
@@ -156,7 +157,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
156
157
  :style="{ width: `${Math.max(2, pct(headroom))}%` }"
157
158
  />
158
159
  </div>
159
- <p v-if="m.truncatedCalls > 0" class="mt-1 text-[11px] text-app-error-400">
160
+ <p v-if="m.truncatedCalls > 0" class="mt-1 text-2xs text-app-error-400">
160
161
  {{
161
162
  t(
162
163
  'observability.metricsBar.truncatedCalls',
@@ -169,7 +170,7 @@ const headroomTone = computed(() => headroomColor(headroom.value, m.value.trunca
169
170
 
170
171
  <!-- transport overhead vs model execution -->
171
172
  <div v-if="transport !== null" class="mt-2">
172
- <div class="flex items-center justify-between text-[11px]">
173
+ <div class="flex items-center justify-between text-2xs">
173
174
  <span class="text-dimmed">{{ t('observability.metricsBar.transportVsExecution') }}</span>
174
175
  <span class="tabular-nums text-muted">
175
176
  {{ formatMs(m.overheadMs) }} / {{ formatMs(m.upstreamMs) }}
@@ -2,6 +2,7 @@
2
2
  import { computed } from 'vue'
3
3
  import type { StepMetrics } from '~/types/execution'
4
4
  import StepMetricsBar from '~/components/observability/StepMetricsBar.vue'
5
+ import SectionLabel from '~/components/common/SectionLabel.vue'
5
6
 
6
7
  // The shared "Model activity" block: the LLM observability rollup (StepMetricsBar) under
7
8
  // a labelled header with a "View all calls →" link into the full per-call panel. Used by
@@ -31,12 +32,12 @@ function openObservability() {
31
32
  <template>
32
33
  <div v-if="instanceId || hasCalls">
33
34
  <div class="mb-1 flex items-center justify-between">
34
- <span class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
35
+ <SectionLabel as="span">
35
36
  {{ t('observability.modelActivity') }}
36
- </span>
37
+ </SectionLabel>
37
38
  <button
38
39
  v-if="instanceId"
39
- class="text-[11px] text-app-info-400 hover:text-app-info-300"
40
+ class="text-2xs text-app-info-400 hover:text-app-info-300"
40
41
  @click="openObservability"
41
42
  >
42
43
  {{ t('observability.viewAllCalls') }}
@@ -5,6 +5,7 @@ import type { ToolOutcomeFilter } from '~/utils/observability'
5
5
  import { filterToolCallsByOutcome, formatMs } from '~/utils/observability'
6
6
  import { agentKindMeta } from '~/utils/catalog'
7
7
  import OutcomeFilterChips from '~/components/observability/OutcomeFilterChips.vue'
8
+ import SectionLabel from '~/components/common/SectionLabel.vue'
8
9
 
9
10
  // The tool-call TRAJECTORY drill-down: what the run's agents DID, oldest first, in the order
10
11
  // they did it. The sibling of the model-call list, and the one that holds the failures no LLM
@@ -142,10 +143,10 @@ function prettyArgs(raw: string): string {
142
143
  <div class="space-y-4">
143
144
  <div class="flex flex-wrap items-center justify-between gap-2">
144
145
  <div>
145
- <h2 class="text-[11px] uppercase tracking-wide text-dimmed">
146
+ <SectionLabel as="h2">
146
147
  {{ t('observability.toolCalls.title') }}
147
- </h2>
148
- <p class="text-[11px] text-app-600">{{ t('observability.toolCalls.subtitle') }}</p>
148
+ </SectionLabel>
149
+ <p class="text-2xs text-app-600">{{ t('observability.toolCalls.subtitle') }}</p>
149
150
  </div>
150
151
  <OutcomeFilterChips v-model="filter" :options="filterOptions" />
151
152
  </div>
@@ -198,7 +199,7 @@ function prettyArgs(raw: string): string {
198
199
  implies has to explain itself here. -->
199
200
  <p
200
201
  v-if="boundedNotice"
201
- class="rounded-lg border border-dashed border-app-warning-900/50 px-3 py-2 text-[11px] text-app-warning-300/90"
202
+ class="rounded-lg border border-dashed border-app-warning-900/50 px-3 py-2 text-2xs text-app-warning-300/90"
202
203
  >
203
204
  {{ boundedNotice }}
204
205
  </p>
@@ -225,8 +226,8 @@ function prettyArgs(raw: string): string {
225
226
  :style="{ color: agentMeta(call.agentKind).color }"
226
227
  :title="agentMeta(call.agentKind).label"
227
228
  />
228
- <span class="font-mono text-[13px] text-default">{{ call.tool }}</span>
229
- <div class="ms-auto flex items-center gap-2.5 text-[11px] tabular-nums text-muted">
229
+ <span class="font-mono text-sm text-default">{{ call.tool }}</span>
230
+ <div class="ms-auto flex items-center gap-2.5 text-2xs tabular-nums text-muted">
230
231
  <span :title="t('observability.toolCalls.durationHint')">
231
232
  {{ formatMs(Math.max(0, call.endedAt - call.startedAt)) }}
232
233
  </span>
@@ -238,20 +239,18 @@ function prettyArgs(raw: string): string {
238
239
  </button>
239
240
 
240
241
  <div v-if="expanded[call.id]" class="border-t border-default px-4 py-3 space-y-3">
241
- <div class="flex flex-wrap gap-x-5 gap-y-1 text-[11px] text-dimmed">
242
+ <div class="flex flex-wrap gap-x-5 gap-y-1 text-2xs text-dimmed">
242
243
  <span>{{ t('observability.toolCalls.dispatch', { jobId: call.jobId }) }}</span>
243
244
  <span>{{ t('observability.toolCalls.seq', { seq: call.seq }) }}</span>
244
245
  </div>
245
246
  <!-- `withheld` is not an empty body: nothing was captured, so an empty `args` here
246
247
  must not read as a tool that took none. -->
247
- <p v-if="call.bodies !== 'stored'" class="text-[12px] italic text-dimmed">
248
+ <p v-if="call.bodies !== 'stored'" class="text-xs italic text-dimmed">
248
249
  {{ t('observability.toolCalls.bodiesWithheld') }}
249
250
  </p>
250
251
  <template v-else>
251
252
  <div>
252
- <div
253
- class="mb-1 flex items-center gap-2 text-[11px] uppercase tracking-wide text-dimmed"
254
- >
253
+ <SectionLabel class="mb-1 flex items-center gap-2">
255
254
  <span>{{ t('observability.toolCalls.arguments') }}</span>
256
255
  <span
257
256
  v-if="call.argsDropped > 0"
@@ -259,15 +258,13 @@ function prettyArgs(raw: string): string {
259
258
  >
260
259
  {{ t('observability.toolCalls.dropped', { chars: call.argsDropped }) }}
261
260
  </span>
262
- </div>
261
+ </SectionLabel>
263
262
  <pre
264
- class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-toned"
263
+ class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-toned"
265
264
  >{{ call.args ? prettyArgs(call.args) : '—' }}</pre>
266
265
  </div>
267
266
  <div>
268
- <div
269
- class="mb-1 flex items-center gap-2 text-[11px] uppercase tracking-wide text-dimmed"
270
- >
267
+ <SectionLabel class="mb-1 flex items-center gap-2">
271
268
  <span>{{ t('observability.toolCalls.result') }}</span>
272
269
  <span
273
270
  v-if="call.resultDropped > 0"
@@ -275,9 +272,9 @@ function prettyArgs(raw: string): string {
275
272
  >
276
273
  {{ t('observability.toolCalls.dropped', { chars: call.resultDropped }) }}
277
274
  </span>
278
- </div>
275
+ </SectionLabel>
279
276
  <pre
280
- class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed"
277
+ class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed"
281
278
  :class="call.ok ? 'text-toned' : 'text-app-error-300'"
282
279
  >{{ call.result || '—' }}</pre>
283
280
  </div>
@@ -45,6 +45,7 @@ import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
45
45
  import MarkdownProse from '~/components/common/MarkdownProse.vue'
46
46
  import EmptyState from '~/components/common/EmptyState.vue'
47
47
  import type { BadgeColor } from '~/utils/badge'
48
+ import SectionLabel from '~/components/common/SectionLabel.vue'
48
49
 
49
50
  const board = useBoardStore()
50
51
  const documents = useDocumentsStore()
@@ -458,16 +459,16 @@ function openTestReport() {
458
459
 
459
460
  <!-- What was asked, in the requester's own words. -->
460
461
  <section class="mb-5">
461
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
462
+ <SectionLabel as="h3" class="mb-1.5">
462
463
  {{ t('outcome.ask.title') }}
463
- </h3>
464
+ </SectionLabel>
464
465
  <MarkdownProse
465
466
  v-if="outcome.ask"
466
467
  :text="outcome.ask"
467
- class="text-[13px] leading-relaxed text-toned"
468
+ class="text-sm leading-relaxed text-toned"
468
469
  data-testid="outcome-ask"
469
470
  />
470
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
471
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
471
472
  {{ t('outcome.ask.none') }}
472
473
  </p>
473
474
  </section>
@@ -477,9 +478,9 @@ function openTestReport() {
477
478
  agents actually read, and every section below is a statement about work done against
478
479
  it. A design that moved mid-run is the reading that changes all of them. -->
479
480
  <section class="mb-5" data-testid="outcome-sources">
480
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
481
+ <SectionLabel as="h3" class="mb-1.5">
481
482
  {{ t('outcome.sources.title') }}
482
- </h3>
483
+ </SectionLabel>
483
484
  <div v-if="outcome.sources.status === 'reported'" class="space-y-1">
484
485
  <div
485
486
  v-for="source in sourceRows"
@@ -495,7 +496,7 @@ function openTestReport() {
495
496
  <UIcon :name="source.icon" class="h-3.5 w-3.5 shrink-0 text-primary" />
496
497
  <span class="truncate">{{ source.title }}</span>
497
498
  </DocumentOriginLink>
498
- <p class="mt-0.5 text-[11px] text-dimmed" data-testid="outcome-source-revision">
499
+ <p class="mt-0.5 text-2xs text-dimmed" data-testid="outcome-source-revision">
499
500
  {{ source.revision }}
500
501
  </p>
501
502
  <!-- Stated separately from the revision above: the last revision alone says the run
@@ -503,23 +504,23 @@ function openTestReport() {
503
504
  changed under it. -->
504
505
  <p
505
506
  v-if="source.movedDuringRun"
506
- class="mt-0.5 text-[11px] text-app-warning-300"
507
+ class="mt-0.5 text-2xs text-app-warning-300"
507
508
  data-testid="outcome-source-moved"
508
509
  >
509
510
  {{ t('outcome.sources.moved') }}
510
511
  </p>
511
512
  </div>
512
513
  </div>
513
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
514
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
514
515
  {{ t(SOURCES_GAP_KEYS[outcome.sources.gap]) }}
515
516
  </p>
516
517
  </section>
517
518
 
518
519
  <!-- Requirement coverage: which required behaviours were checked, and what was seen. -->
519
520
  <section class="mb-5" data-testid="outcome-requirements">
520
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
521
+ <SectionLabel as="h3" class="mb-1.5">
521
522
  {{ t('outcome.requirements.title') }}
522
- </h3>
523
+ </SectionLabel>
523
524
  <template v-if="outcome.requirements.status === 'reported'">
524
525
  <div class="mb-2 flex flex-wrap items-center gap-1.5">
525
526
  <UBadge color="success" variant="subtle" size="sm">
@@ -550,7 +551,7 @@ function openTestReport() {
550
551
  and do not cover rather than letting them read as the whole picture. -->
551
552
  <p
552
553
  v-if="specNote"
553
- class="mb-2 text-[11px] leading-relaxed text-app-warning-300/90"
554
+ class="mb-2 text-2xs leading-relaxed text-app-warning-300/90"
554
555
  data-testid="outcome-spec-note"
555
556
  >
556
557
  {{ specNote }}
@@ -560,7 +561,7 @@ function openTestReport() {
560
561
  deciding which of the two numbers to distrust. -->
561
562
  <p
562
563
  v-if="unmatchedVerdicts > 0"
563
- class="mb-2 text-[11px] leading-relaxed text-app-warning-300/90"
564
+ class="mb-2 text-2xs leading-relaxed text-app-warning-300/90"
564
565
  data-testid="outcome-unmatched-verdicts"
565
566
  >
566
567
  {{ t('outcome.requirements.unmatchedVerdicts', { count: unmatchedVerdicts }) }}
@@ -578,7 +579,7 @@ function openTestReport() {
578
579
  />
579
580
  <div class="min-w-0">
580
581
  <div class="flex flex-wrap items-center gap-1.5">
581
- <span class="text-[13px] text-default">{{ req.title ?? req.id }}</span>
582
+ <span class="text-sm text-default">{{ req.title ?? req.id }}</span>
582
583
  <UBadge
583
584
  v-if="req.regression"
584
585
  color="error"
@@ -588,18 +589,18 @@ function openTestReport() {
588
589
  >
589
590
  {{ t('outcome.requirements.regressionTag') }}
590
591
  </UBadge>
591
- <span class="text-[10px] uppercase tracking-wide text-dimmed">
592
+ <SectionLabel as="span">
592
593
  {{ t(VERDICT_META[req.verdict].key) }}
593
- </span>
594
+ </SectionLabel>
594
595
  </div>
595
- <p v-if="req.detail" class="mt-0.5 text-[12px] leading-relaxed text-muted">
596
+ <p v-if="req.detail" class="mt-0.5 text-xs leading-relaxed text-muted">
596
597
  {{ req.detail }}
597
598
  </p>
598
599
  </div>
599
600
  </li>
600
601
  </ul>
601
602
  </template>
602
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
603
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
603
604
  {{ t(REQUIREMENTS_GAP_KEYS[outcome.requirements.gap]) }}
604
605
  </p>
605
606
  </section>
@@ -607,9 +608,9 @@ function openTestReport() {
607
608
  <!-- How it was tested: the tester's own verdict and prose, attributed as its account. -->
608
609
  <section class="mb-5" data-testid="outcome-tests">
609
610
  <div class="mb-1.5 flex flex-wrap items-center gap-2">
610
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
611
+ <SectionLabel as="h3">
611
612
  {{ t('outcome.tests.title') }}
612
- </h3>
613
+ </SectionLabel>
613
614
  <UBadge
614
615
  v-if="outcome.tests.status === 'reported'"
615
616
  :color="TESTS_VERDICT_COLOR[outcome.tests.verdict]"
@@ -642,15 +643,15 @@ function openTestReport() {
642
643
  <template v-if="outcome.tests.status === 'reported'">
643
644
  <p
644
645
  v-if="outcome.tests.abortReason"
645
- class="mb-2 rounded-md border border-app-error-900/70 bg-app-error-500/10 p-2 text-[13px] leading-relaxed text-app-error-200"
646
+ class="mb-2 rounded-md border border-app-error-900/70 bg-app-error-500/10 p-2 text-sm leading-relaxed text-app-error-200"
646
647
  data-testid="outcome-tests-abort"
647
648
  >
648
649
  {{ t('outcome.tests.abort', { reason: outcome.tests.abortReason }) }}
649
650
  </p>
650
- <p v-if="outcome.tests.summary" class="text-[13px] leading-relaxed text-toned">
651
+ <p v-if="outcome.tests.summary" class="text-sm leading-relaxed text-toned">
651
652
  {{ t('outcome.tests.summary', { summary: outcome.tests.summary }) }}
652
653
  </p>
653
- <p class="mt-1.5 text-[12px] text-muted">
654
+ <p class="mt-1.5 text-xs text-muted">
654
655
  {{
655
656
  t('outcome.tests.counts', {
656
657
  passed: outcome.tests.passed,
@@ -663,7 +664,7 @@ function openTestReport() {
663
664
  <li
664
665
  v-for="(concern, i) in outcome.tests.concerns"
665
666
  :key="i"
666
- class="flex items-start gap-2 text-[12px] text-toned"
667
+ class="flex items-start gap-2 text-xs text-toned"
667
668
  data-testid="outcome-concern"
668
669
  >
669
670
  <UBadge :color="SEVERITY_COLOR[concern.severity]" variant="subtle" size="sm">
@@ -673,18 +674,18 @@ function openTestReport() {
673
674
  </li>
674
675
  </ul>
675
676
  </template>
676
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
677
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
677
678
  {{ t(TESTS_GAP_KEYS[outcome.tests.gap]) }}
678
679
  </p>
679
680
  </section>
680
681
 
681
682
  <!-- What it looks like: the captured views, and whether a human was asked about them. -->
682
683
  <section class="mb-5" data-testid="outcome-visuals">
683
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
684
+ <SectionLabel as="h3" class="mb-1.5">
684
685
  {{ t('outcome.visuals.title') }}
685
- </h3>
686
+ </SectionLabel>
686
687
  <template v-if="outcome.visuals.status === 'reported'">
687
- <p class="mb-2 text-[12px] leading-relaxed text-muted">
688
+ <p class="mb-2 text-xs leading-relaxed text-muted">
688
689
  {{
689
690
  outcome.visuals.source === 'visual_confirm'
690
691
  ? t('outcome.visuals.source.visual_confirm')
@@ -718,7 +719,7 @@ function openTestReport() {
718
719
  />
719
720
  </div>
720
721
  <span
721
- class="flex items-center gap-1 truncate px-1.5 py-1 text-[11px] text-toned"
722
+ class="flex items-center gap-1 truncate px-1.5 py-1 text-2xs text-toned"
722
723
  :title="view.view"
723
724
  >
724
725
  <UIcon
@@ -733,12 +734,12 @@ function openTestReport() {
733
734
  </div>
734
735
  </template>
735
736
  <template v-else>
736
- <p class="text-[13px] italic leading-relaxed text-dimmed">
737
+ <p class="text-sm italic leading-relaxed text-dimmed">
737
738
  {{ t(VISUALS_GAP_KEYS[outcome.visuals.gap]) }}
738
739
  </p>
739
740
  <p
740
741
  v-if="outcome.visuals.detail"
741
- class="mt-1 text-[12px] leading-relaxed text-dimmed"
742
+ class="mt-1 text-xs leading-relaxed text-dimmed"
742
743
  data-testid="outcome-visuals-detail"
743
744
  >
744
745
  {{ outcome.visuals.detail }}
@@ -750,9 +751,9 @@ function openTestReport() {
750
751
  not read diffs starts from. Beside the captured views on purpose: the shots are what
751
752
  this run saw, this is the thing itself. -->
752
753
  <section class="mb-5" data-testid="outcome-environments">
753
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
754
+ <SectionLabel as="h3" class="mb-1.5">
754
755
  {{ t('outcome.environments.title') }}
755
- </h3>
756
+ </SectionLabel>
756
757
  <template v-if="outcome.environments.status === 'reported'">
757
758
  <div
758
759
  v-for="row in environmentRows"
@@ -765,10 +766,10 @@ function openTestReport() {
765
766
  <UBadge :color="ENVIRONMENT_STATE_COLOR[row.state]" variant="subtle" size="sm">
766
767
  {{ t(ENVIRONMENT_STATE_KEYS[row.state]) }}
767
768
  </UBadge>
768
- <span v-if="row.service" class="truncate text-[12px] text-toned">
769
+ <span v-if="row.service" class="truncate text-xs text-toned">
769
770
  {{ row.service }}
770
771
  </span>
771
- <span class="text-[11px] text-dimmed">
772
+ <span class="text-2xs text-dimmed">
772
773
  {{ t(ENVIRONMENT_ORIGIN_KEYS[row.origin]) }}
773
774
  </span>
774
775
  </div>
@@ -789,15 +790,15 @@ function openTestReport() {
789
790
  </UButton>
790
791
  <p
791
792
  v-else-if="row.url"
792
- class="mt-1.5 break-all text-[12px] text-dimmed"
793
+ class="mt-1.5 break-all text-xs text-dimmed"
793
794
  data-testid="outcome-environment-url"
794
795
  >
795
796
  {{ row.url }}
796
797
  </p>
797
- <p v-if="row.retained" class="mt-1 text-[11px] text-muted">
798
+ <p v-if="row.retained" class="mt-1 text-2xs text-muted">
798
799
  {{ t('outcome.environments.retained') }}
799
800
  </p>
800
- <p v-if="row.expiresAt" class="mt-1 text-[11px] text-dimmed">
801
+ <p v-if="row.expiresAt" class="mt-1 text-2xs text-dimmed">
801
802
  {{
802
803
  row.lapsed
803
804
  ? t('outcome.environments.expired', { date: d(new Date(row.expiresAt), 'long') })
@@ -810,7 +811,7 @@ function openTestReport() {
810
811
  otherwise holds "quota exceeded" reports a fault the environment does not have. -->
811
812
  <p
812
813
  v-if="row.detail"
813
- class="mt-1 break-words text-[12px] leading-relaxed text-dimmed"
814
+ class="mt-1 break-words text-xs leading-relaxed text-dimmed"
814
815
  data-testid="outcome-environment-detail"
815
816
  :data-detail-kind="row.detailKind"
816
817
  >
@@ -822,16 +823,16 @@ function openTestReport() {
822
823
  </p>
823
824
  </div>
824
825
  </template>
825
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
826
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
826
827
  {{ t(ENVIRONMENTS_GAP_KEYS[outcome.environments.gap]) }}
827
828
  </p>
828
829
  </section>
829
830
 
830
831
  <!-- The machine checks, listed only where one actually recorded a verdict. -->
831
832
  <section v-if="checkRows.length" data-testid="outcome-checks">
832
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
833
+ <SectionLabel as="h3" class="mb-1.5">
833
834
  {{ t('outcome.checks.title') }}
834
- </h3>
835
+ </SectionLabel>
835
836
  <div class="flex flex-wrap items-center gap-1.5">
836
837
  <UBadge
837
838
  v-for="check in checkRows"