@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
@@ -17,6 +17,7 @@ import { BINARY_OUTPUT_STATE_KEYS, binaryOutputView } from '~/utils/binaryOutput
17
17
  import { binaryCandidateView } from '~/utils/binaryCandidates'
18
18
  import CopyButton from '~/components/common/CopyButton.vue'
19
19
  import StoredAssetView from '~/components/binaryOutput/StoredAssetView.vue'
20
+ import SectionLabel from '~/components/common/SectionLabel.vue'
20
21
 
21
22
  // Two callers, one renderer — the same split `StepEffortReport` makes: the generic step-detail
22
23
  // panel drops it in as a `card` (its own heading + border, among the other detail sections),
@@ -59,20 +60,17 @@ const state = computed(() => {
59
60
  "
60
61
  data-testid="binary-output-report"
61
62
  >
62
- <div
63
- v-if="variant === 'card'"
64
- class="flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted"
65
- >
63
+ <SectionLabel v-if="variant === 'card'" class="flex items-center gap-1.5">
66
64
  <UIcon name="i-lucide-image" class="h-3.5 w-3.5" />
67
65
  <span>{{ t('binaryOutput.heading') }}</span>
68
- </div>
66
+ </SectionLabel>
69
67
 
70
68
  <!-- The CANDIDATE decision, when this step compared before delivering. It sits ABOVE the
71
69
  delivery outcome because it happened first, and because "which of four was this" is the
72
70
  question the artifacts below cannot answer. An AUTOMATIC keep says so: nobody looked. -->
73
71
  <p
74
72
  v-if="candidates && candidates.state.candidates.length > 0"
75
- class="text-[12px] leading-relaxed text-toned"
73
+ class="text-xs leading-relaxed text-toned"
76
74
  data-testid="binary-output-candidate-decision"
77
75
  >
78
76
  {{
@@ -92,7 +90,7 @@ const state = computed(() => {
92
90
  <!-- What happened, in one sentence, before any list. Four of the five states have no list
93
91
  at all, and the fifth still needs its qualifications read alongside it. -->
94
92
  <p
95
- class="flex items-start gap-2 text-[12px] leading-relaxed"
93
+ class="flex items-start gap-2 text-xs leading-relaxed"
96
94
  :class="state.tone"
97
95
  data-testid="binary-output-state"
98
96
  :data-state="view.state"
@@ -106,7 +104,7 @@ const state = computed(() => {
106
104
  so — it is a real state (a trait-carrying kind dispatched under an overriding kind
107
105
  records a declaration against a step that never held one), and rendering a blank
108
106
  would read as a missing value rather than an absent comparison. -->
109
- <dl class="grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-[11px]">
107
+ <dl class="grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-2xs">
110
108
  <dt class="text-dimmed">{{ t('binaryOutput.target') }}</dt>
111
109
  <dd
112
110
  v-if="view.target"
@@ -158,10 +156,8 @@ const state = computed(() => {
158
156
  :label="row.entity ?? row.description"
159
157
  class="mb-2 pe-8"
160
158
  />
161
- <code class="block break-all pe-8 font-mono text-[11px] text-default">{{
162
- row.location
163
- }}</code>
164
- <div class="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[10px] text-dimmed">
159
+ <code class="block break-all pe-8 font-mono text-2xs text-default">{{ row.location }}</code>
160
+ <div class="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-3xs text-dimmed">
165
161
  <span class="font-mono">{{ row.service }}</span>
166
162
  <!-- The join the report cannot make on its own, and the question a human opens this
167
163
  for: did it go where the step pointed it? -->
@@ -225,7 +221,7 @@ const state = computed(() => {
225
221
  {{ t('binaryOutput.missizedBadge') }}
226
222
  </UBadge>
227
223
  </div>
228
- <p v-if="row.description" class="mt-1 text-[11px] leading-relaxed text-muted">
224
+ <p v-if="row.description" class="mt-1 text-2xs leading-relaxed text-muted">
229
225
  {{ row.description }}
230
226
  </p>
231
227
  </li>
@@ -234,7 +230,7 @@ const state = computed(() => {
234
230
  <!-- Every qualification the report counted, each naming its own number. Never folded into
235
231
  one "some entries were dropped": the fix for an unknown service id is not the fix for
236
232
  a malformed entry, and neither is the fix for a list that stops short of the tail. -->
237
- <ul class="space-y-1 text-[11px] text-app-warning-400">
233
+ <ul class="space-y-1 text-2xs text-app-warning-400">
238
234
  <!-- The step's OWN target went missing from the catalog, and an id the AGENT invented,
239
235
  are two different failures with two different fixes (re-register it, versus correct
240
236
  the declaration). `binaryOutputView` returns them as DISJOINT fields precisely so
@@ -80,7 +80,7 @@ const filename = computed(() => {
80
80
  v-if="isImage && url"
81
81
  :src="url"
82
82
  :alt="label ?? assetId"
83
- class="w-full rounded object-contain"
83
+ class="w-full rounded-sm object-contain"
84
84
  :class="previewClass"
85
85
  data-testid="stored-asset-preview"
86
86
  />
@@ -89,7 +89,7 @@ const filename = computed(() => {
89
89
  frame. -->
90
90
  <p
91
91
  v-else-if="!isImage && url"
92
- class="flex items-center gap-1.5 rounded bg-elevated/60 px-2 py-1.5 text-[11px] text-toned"
92
+ class="flex items-center gap-1.5 rounded-sm bg-elevated/60 px-2 py-1.5 text-2xs text-toned"
93
93
  data-testid="stored-asset-file"
94
94
  >
95
95
  <UIcon name="i-lucide-file" class="h-3.5 w-3.5 shrink-0" />
@@ -97,7 +97,7 @@ const filename = computed(() => {
97
97
  </p>
98
98
  <p
99
99
  v-else-if="status === 'error'"
100
- class="flex items-center gap-1.5 text-[11px] text-app-warning-300"
100
+ class="flex items-center gap-1.5 text-2xs text-app-warning-300"
101
101
  data-testid="stored-asset-error"
102
102
  >
103
103
  <span>{{ t('binaryOutput.asset.loadFailed') }}</span>
@@ -105,29 +105,31 @@ const filename = computed(() => {
105
105
  {{ t('binaryOutput.asset.retry') }}
106
106
  </UButton>
107
107
  </p>
108
- <p v-else class="text-[11px] text-dimmed" data-testid="stored-asset-loading">
108
+ <p v-else class="text-2xs text-dimmed" data-testid="stored-asset-loading">
109
109
  {{ t('binaryOutput.asset.loading') }}
110
110
  </p>
111
111
 
112
112
  <!-- The two things a person does with a delivered asset. Both hang off the object URL, so
113
113
  they appear only once the bytes are in hand. -->
114
- <div v-if="url" class="flex items-center gap-3 text-[11px]">
115
- <a
116
- :href="url"
114
+ <div v-if="url" class="flex items-center gap-3 text-2xs">
115
+ <ULink
116
+ raw
117
+ :to="url"
117
118
  target="_blank"
118
119
  rel="noopener"
119
120
  class="text-app-info-300 hover:underline"
120
121
  data-testid="stored-asset-open"
121
122
  @click.stop
122
- >{{ t('binaryOutput.asset.open') }}</a
123
+ >{{ t('binaryOutput.asset.open') }}</ULink
123
124
  >
124
- <a
125
- :href="url"
125
+ <ULink
126
+ raw
127
+ :to="url"
126
128
  :download="filename"
127
129
  class="text-app-info-300 hover:underline"
128
130
  data-testid="stored-asset-download"
129
131
  @click.stop
130
- >{{ t('binaryOutput.asset.download') }}</a
132
+ >{{ t('binaryOutput.asset.download') }}</ULink
131
133
  >
132
134
  </div>
133
135
  </div>
@@ -46,6 +46,7 @@ import {
46
46
  import { descriptorFieldDefaults } from '@cat-factory/contracts'
47
47
  import { pipelineAllowedForManualStart } from '~/utils/pipeline'
48
48
  import { buildTaskTypePickerRows } from '~/utils/taskTypePicker'
49
+ import SectionLabel from '~/components/common/SectionLabel.vue'
49
50
 
50
51
  const ui = useUiStore()
51
52
  // Interface tier. In BASIC mode this form asks for the task itself (type, title,
@@ -141,6 +142,11 @@ const timeboxHours = ref<number | undefined>(undefined)
141
142
  // default — an expedition exists to cover ground nobody thought to look at, so narrowing it is
142
143
  // the deliberate act) plus an optional focus folded into every angle's prompt.
143
144
  const fishingPhaseIds = ref<string[]>([])
145
+ function toggleFishingPhase(id: string, checked: boolean) {
146
+ fishingPhaseIds.value = checked
147
+ ? [...fishingPhaseIds.value, id]
148
+ : fishingPhaseIds.value.filter((x) => x !== id)
149
+ }
144
150
  const fishingFocus = ref('')
145
151
  /** Held as a string because the input is a text field; parsed at submit, blank ⇒ the default. */
146
152
  const fishingMaxPasses = ref('')
@@ -938,13 +944,14 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
938
944
  data-testid="task-type-row"
939
945
  :data-task-type-row="row.id"
940
946
  >
941
- <p
947
+ <SectionLabel
942
948
  v-if="row.caption"
943
- class="mb-1 px-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed"
949
+ as="p"
950
+ class="mb-1 px-1"
944
951
  data-testid="task-type-category"
945
952
  >
946
953
  {{ row.caption }}
947
- </p>
954
+ </SectionLabel>
948
955
  <div class="flex flex-wrap gap-1">
949
956
  <UButton
950
957
  v-for="ty in row.choices"
@@ -981,7 +988,7 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
981
988
  </UFormField>
982
989
 
983
990
  <!-- Recurring tasks are configured as a schedule on the service frame. -->
984
- <div v-if="isRecurring" class="rounded-lg border border-default p-3 text-[11px] text-muted">
991
+ <div v-if="isRecurring" class="rounded-lg border border-default p-3 text-2xs text-muted">
985
992
  <template v-if="recurringFrameId">
986
993
  {{ t('board.addTask.recurringWithFrame') }}
987
994
  </template>
@@ -1023,7 +1030,7 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
1023
1030
  :ui="{ base: 'cursor-default text-toned' }"
1024
1031
  />
1025
1032
  </UFormField>
1026
- <p v-if="resolvingIssueBodies" class="text-[11px] text-dimmed">
1033
+ <p v-if="resolvingIssueBodies" class="text-2xs text-dimmed">
1027
1034
  {{ t('board.addTask.loadingIssue') }}
1028
1035
  </p>
1029
1036
 
@@ -1054,7 +1061,7 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
1054
1061
  <span class="text-sm text-default">{{ t('board.addTask.technical') }}</span>
1055
1062
  </template>
1056
1063
  <template #description>
1057
- <span class="text-[11px] text-dimmed">
1064
+ <span class="text-2xs text-dimmed">
1058
1065
  {{ t('board.addTask.technicalHint') }}
1059
1066
  </span>
1060
1067
  </template>
@@ -1103,25 +1110,21 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
1103
1110
  :description="t('board.addTask.bugFishingFields.angles.hint')"
1104
1111
  >
1105
1112
  <div class="grid gap-1.5 sm:grid-cols-2">
1106
- <label
1113
+ <!-- Each angle keeps its own test hook, so the boolean is derived from the id
1114
+ list rather than bound through a checkbox group. -->
1115
+ <UCheckbox
1107
1116
  v-for="phase in BUG_FISHING_PHASES"
1108
1117
  :key="phase.id"
1109
- class="flex items-start gap-2 rounded-md px-1.5 py-1 text-[12px] hover:bg-elevated/40"
1110
- >
1111
- <input
1112
- v-model="fishingPhaseIds"
1113
- type="checkbox"
1114
- :value="phase.id"
1115
- class="mt-0.5 accent-app-info-500"
1116
- :data-testid="`add-task-fishing-angle-${phase.id}`"
1117
- />
1118
- <span class="min-w-0">
1119
- <span class="block text-default">{{ phase.title }}</span>
1120
- <span class="block text-[11px] text-dimmed">{{ phase.goal }}</span>
1121
- </span>
1122
- </label>
1118
+ size="xs"
1119
+ :model-value="fishingPhaseIds.includes(phase.id)"
1120
+ :label="phase.title"
1121
+ :description="phase.goal"
1122
+ class="rounded-md px-1.5 py-1 hover:bg-elevated/40"
1123
+ :data-testid="`add-task-fishing-angle-${phase.id}`"
1124
+ @update:model-value="toggleFishingPhase(phase.id, $event === true)"
1125
+ />
1123
1126
  </div>
1124
- <p v-if="fishingPhaseIds.length === 0" class="mt-1.5 text-[11px] text-dimmed">
1127
+ <p v-if="fishingPhaseIds.length === 0" class="mt-1.5 text-2xs text-dimmed">
1125
1128
  {{ t('board.addTask.bugFishingFields.angles.allSelected') }}
1126
1129
  </p>
1127
1130
  </UFormField>
@@ -1385,11 +1388,11 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
1385
1388
  </div>
1386
1389
 
1387
1390
  <div v-if="configDescriptors.length" class="space-y-3">
1388
- <span class="text-[11px] font-semibold uppercase tracking-wide text-muted">
1391
+ <SectionLabel as="span">
1389
1392
  {{ t('board.addTask.agentConfiguration') }}
1390
- </span>
1393
+ </SectionLabel>
1391
1394
  <div v-for="d in configDescriptors" :key="d.id" class="space-y-1">
1392
- <div class="text-[11px] text-muted">{{ d.label }}</div>
1395
+ <div class="text-2xs text-muted">{{ d.label }}</div>
1393
1396
  <div v-if="d.type === 'select'" class="flex flex-wrap gap-1">
1394
1397
  <UButton
1395
1398
  v-for="opt in d.options"
@@ -1411,7 +1414,7 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
1411
1414
  :data-testid="`agent-config-${d.id}`"
1412
1415
  @update:model-value="(v: string | number) => setConfig(d.id, String(v))"
1413
1416
  />
1414
- <p class="text-[11px] leading-snug text-dimmed">{{ d.description }}</p>
1417
+ <p class="text-2xs leading-snug text-dimmed">{{ d.description }}</p>
1415
1418
  </div>
1416
1419
  </div>
1417
1420
 
@@ -1440,7 +1443,7 @@ function openReviewFrictionDialog(conflict: NonNullable<ReturnType<typeof parseC
1440
1443
  :issues-hint="t('board.addTask.noIssuesHint')"
1441
1444
  />
1442
1445
 
1443
- <p class="text-[11px] text-dimmed">
1446
+ <p class="text-2xs text-dimmed">
1444
1447
  {{ t('board.addTask.plannedHint') }}
1445
1448
  </p>
1446
1449
  </template>
@@ -138,7 +138,7 @@ async function retry() {
138
138
  data-testid="agent-failure-banner"
139
139
  :data-run-kind="run.kind"
140
140
  >
141
- <div class="flex items-center gap-1.5" :class="compact ? 'text-[11px]' : 'text-xs'">
141
+ <div class="flex items-center gap-1.5" :class="compact ? 'text-2xs' : 'text-xs'">
142
142
  <UIcon
143
143
  name="i-lucide-alert-triangle"
144
144
  class="shrink-0 text-app-error-400"
@@ -150,7 +150,7 @@ async function retry() {
150
150
  <p
151
151
  v-if="failure?.message"
152
152
  class="mt-1 leading-snug text-app-error-300/90"
153
- :class="compact ? 'line-clamp-2 text-[10px]' : 'text-[11px]'"
153
+ :class="compact ? 'line-clamp-2 text-3xs' : 'text-2xs'"
154
154
  :title="failure.message"
155
155
  >
156
156
  {{ failure.message }}
@@ -159,7 +159,7 @@ async function retry() {
159
159
  <p
160
160
  v-if="failure?.hint"
161
161
  class="mt-1 leading-snug text-app-error-400/70"
162
- :class="compact ? 'text-[10px]' : 'text-[11px]'"
162
+ :class="compact ? 'text-3xs' : 'text-2xs'"
163
163
  >
164
164
  {{ failure.hint }}
165
165
  </p>
@@ -168,7 +168,7 @@ async function retry() {
168
168
  name the concrete .env fix rather than only pointing at the (unhelpful-here) tab. -->
169
169
  <p
170
170
  v-if="showEnvironmentLocalHint && !compact"
171
- class="mt-1 text-[11px] leading-snug text-app-error-400/70"
171
+ class="mt-1 text-2xs leading-snug text-app-error-400/70"
172
172
  data-testid="agent-failure-environment-local-hint"
173
173
  >
174
174
  {{
@@ -192,15 +192,16 @@ async function retry() {
192
192
  v-if="!compact && failure"
193
193
  :detail="failure.detail"
194
194
  :message="failure.message"
195
- summary-class="text-[10px] text-app-error-400/60 hover:text-app-error-300"
196
- pre-class="bg-app-error-950/60 text-[10px] text-app-error-200/80"
195
+ summary-class="text-3xs text-app-error-400/60 hover:text-app-error-300"
196
+ pre-class="bg-app-error-950/60 text-3xs text-app-error-200/80"
197
197
  />
198
198
 
199
199
  <div class="mt-2 flex flex-wrap items-center gap-2">
200
- <button
201
- type="button"
200
+ <UButton
201
+ color="neutral"
202
+ variant="ghost"
202
203
  class="nodrag flex items-center gap-1 rounded-md bg-app-error-900/40 text-app-error-200 hover:bg-app-error-900/70 disabled:opacity-60"
203
- :class="compact ? 'px-2 py-0.5 text-[10px]' : 'px-2 py-1 text-[11px]'"
204
+ :class="compact ? 'px-2 py-0.5 text-3xs' : 'px-2 py-1 text-2xs'"
204
205
  :disabled="retrying || !access.canExecuteRuns.value"
205
206
  :title="access.canExecuteRuns.value ? undefined : t('access.noRunExecute')"
206
207
  data-testid="agent-failure-retry"
@@ -211,36 +212,38 @@ async function retry() {
211
212
  :class="[compact ? 'h-3 w-3' : 'h-3.5 w-3.5', { 'animate-spin': retrying }]"
212
213
  />
213
214
  {{ retrying ? t('board.failure.retrying') : compact ? t('common.retry') : retryLabel }}
214
- </button>
215
+ </UButton>
215
216
 
216
- <button
217
+ <UButton
218
+ color="neutral"
219
+ variant="ghost"
217
220
  v-if="run.kind === 'bootstrap'"
218
- type="button"
219
221
  class="nodrag flex items-center gap-1 rounded-md bg-app-error-900/20 text-app-error-300 hover:bg-app-error-900/50"
220
- :class="compact ? 'px-2 py-0.5 text-[10px]' : 'px-2 py-1 text-[11px]'"
222
+ :class="compact ? 'px-2 py-0.5 text-3xs' : 'px-2 py-1 text-2xs'"
221
223
  data-testid="agent-failure-inspect"
222
224
  @click.stop="inspectRun"
223
225
  >
224
226
  <UIcon name="i-lucide-activity" :class="compact ? 'h-3 w-3' : 'h-3.5 w-3.5'" />
225
227
  {{ t('observability.modelActivity') }}
226
- </button>
228
+ </UButton>
227
229
 
228
230
  <!-- Environment provisioning failures are almost always a deploy-backend / provider-config
229
231
  issue, so link straight to where it's set up rather than leaving the user to hunt. The
230
232
  destination + label follow the cause: a `deploy_runner_unwired` failure needs the runner
231
233
  pool (Agent containers tab), every other cause needs the environment provider (Test
232
234
  environments tab) — see `routesToRunnerPool`. -->
233
- <button
235
+ <UButton
236
+ color="neutral"
237
+ variant="ghost"
234
238
  v-if="isEnvironmentFailure"
235
- type="button"
236
239
  class="nodrag flex items-center gap-1 rounded-md bg-app-error-900/20 text-app-error-300 hover:bg-app-error-900/50"
237
- :class="compact ? 'px-2 py-0.5 text-[10px]' : 'px-2 py-1 text-[11px]'"
240
+ :class="compact ? 'px-2 py-0.5 text-3xs' : 'px-2 py-1 text-2xs'"
238
241
  data-testid="agent-failure-configure-environment"
239
242
  @click.stop="openFailureSetup"
240
243
  >
241
244
  <UIcon name="i-lucide-settings" :class="compact ? 'h-3 w-3' : 'h-3.5 w-3.5'" />
242
245
  {{ failureSetupLabel }}
243
- </button>
246
+ </UButton>
244
247
  </div>
245
248
  </div>
246
249
  </template>
@@ -13,18 +13,27 @@ const { t } = useI18n()
13
13
  </script>
14
14
 
15
15
  <template>
16
- <details
16
+ <UCollapsible
17
17
  v-if="failures.length"
18
18
  class="nodrag rounded-lg border border-muted/60 bg-default/40 px-3 py-2"
19
19
  data-testid="agent-failure-history"
20
20
  >
21
- <summary
22
- class="flex cursor-pointer items-center gap-1.5 text-[11px] text-muted hover:text-default"
23
- >
24
- <UIcon name="i-lucide-history" class="h-3.5 w-3.5 shrink-0" />
25
- {{ t('board.failure.history.previousErrors', { count: failures.length }, failures.length) }}
26
- </summary>
21
+ <template #default="{ open }">
22
+ <UButton
23
+ variant="link"
24
+ color="neutral"
25
+ size="xs"
26
+ icon="i-lucide-history"
27
+ :trailing-icon="open ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'"
28
+ :label="
29
+ t('board.failure.history.previousErrors', { count: failures.length }, failures.length)
30
+ "
31
+ :ui="{ base: 'w-full justify-start gap-1.5 p-0 text-2xs text-muted hover:text-default' }"
32
+ />
33
+ </template>
27
34
 
28
- <FailureHistoryList :failures="props.failures" class="mt-2" />
29
- </details>
35
+ <template #content>
36
+ <FailureHistoryList :failures="props.failures" class="mt-2" />
37
+ </template>
38
+ </UCollapsible>
30
39
  </template>
@@ -193,16 +193,17 @@ async function create() {
193
193
  <div v-if="presets.length > 1" class="space-y-1.5">
194
194
  <span class="text-xs font-medium text-toned">{{ t('initiative.create.preset') }}</span>
195
195
  <div class="grid gap-2" data-testid="initiative-preset-picker">
196
- <button
196
+ <UButton
197
+ color="neutral"
198
+ variant="ghost"
197
199
  v-for="p in presets"
198
200
  :key="p.id"
199
- type="button"
200
201
  :data-testid="`initiative-preset-option-${p.id}`"
201
202
  :aria-pressed="p.id === selectedPresetId"
202
203
  class="flex items-start gap-3 rounded-md border px-3 py-2 text-left transition"
203
204
  :class="
204
205
  p.id === selectedPresetId
205
- ? 'border-primary bg-primary/10'
206
+ ? 'border-primary bg-primary/10 hover:bg-primary/10 focus-visible:bg-primary/10 disabled:bg-primary/10'
206
207
  : 'border-muted hover:border-app-600'
207
208
  "
208
209
  @click="selectPreset(p.id)"
@@ -216,11 +217,11 @@ async function create() {
216
217
  <span class="block text-sm font-medium text-default">
217
218
  {{ p.presentation.label }}
218
219
  </span>
219
- <span class="block text-[11px] text-muted">
220
+ <span class="block text-2xs text-muted">
220
221
  {{ p.presentation.description }}
221
222
  </span>
222
223
  </span>
223
- </button>
224
+ </UButton>
224
225
  </div>
225
226
  </div>
226
227
 
@@ -264,7 +265,7 @@ async function create() {
264
265
  :issues-hint="t('initiative.create.contextIssuesHint')"
265
266
  />
266
267
 
267
- <p class="text-[11px] text-dimmed">
268
+ <p class="text-2xs text-dimmed">
268
269
  {{ t('initiative.create.hint') }}
269
270
  </p>
270
271
  </div>
@@ -18,18 +18,28 @@ const { t } = useI18n()
18
18
  </script>
19
19
 
20
20
  <template>
21
- <details v-if="detail && detail !== message" class="mt-1">
22
- <summary class="cursor-pointer" :class="summaryClass">
23
- {{ t('board.failure.showDetail') }}
24
- </summary>
21
+ <UCollapsible v-if="detail && detail !== message" class="mt-1">
22
+ <template #default="{ open }">
23
+ <UButton
24
+ variant="link"
25
+ color="neutral"
26
+ size="xs"
27
+ :icon="open ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'"
28
+ :label="t('board.failure.showDetail')"
29
+ :class="summaryClass"
30
+ :ui="{ base: 'w-full justify-start gap-1 p-0' }"
31
+ />
32
+ </template>
25
33
  <!-- The stack trace / extended detail: the first thing a user does with it is copy it, so
26
34
  offer a copy affordance floated over the scroll box (UX-39). -->
27
- <div class="relative mt-1">
28
- <CopyButton :text="detail" class="absolute end-1 top-1 z-10" />
29
- <pre
30
- class="max-h-32 overflow-auto whitespace-pre-wrap rounded p-1.5 pe-9"
31
- :class="preClass"
32
- >{{ detail }}</pre>
33
- </div>
34
- </details>
35
+ <template #content>
36
+ <div class="relative mt-1">
37
+ <CopyButton :text="detail" class="absolute end-1 top-1 z-10" />
38
+ <pre
39
+ class="max-h-32 overflow-auto whitespace-pre-wrap rounded-sm p-1.5 pe-9"
40
+ :class="preClass"
41
+ >{{ detail }}</pre>
42
+ </div>
43
+ </template>
44
+ </UCollapsible>
35
45
  </template>
@@ -23,24 +23,24 @@ const ordered = computed(() => [...props.failures].reverse())
23
23
  class="rounded-md border border-default/80 bg-app-950/50 px-2.5 py-2"
24
24
  data-testid="agent-failure-history-entry"
25
25
  >
26
- <div class="flex items-center gap-1.5 text-[10px] text-dimmed">
26
+ <div class="flex items-center gap-1.5 text-3xs text-dimmed">
27
27
  <UIcon name="i-lucide-alert-triangle" class="h-3 w-3 shrink-0 text-app-error-400/70" />
28
28
  <time>{{ d(new Date(failure.occurredAt), 'long') }}</time>
29
29
  </div>
30
30
 
31
- <p class="mt-1 text-[11px] leading-snug text-toned" :title="failure.message">
31
+ <p class="mt-1 text-2xs leading-snug text-toned" :title="failure.message">
32
32
  {{ failure.message }}
33
33
  </p>
34
34
 
35
- <p v-if="failure.hint" class="mt-1 text-[10px] leading-snug text-dimmed">
35
+ <p v-if="failure.hint" class="mt-1 text-3xs leading-snug text-dimmed">
36
36
  {{ failure.hint }}
37
37
  </p>
38
38
 
39
39
  <FailureDetail
40
40
  :detail="failure.detail"
41
41
  :message="failure.message"
42
- summary-class="text-[10px] text-dimmed hover:text-toned"
43
- pre-class="bg-app-950/80 text-[10px] text-muted"
42
+ summary-class="text-3xs text-dimmed hover:text-toned"
43
+ pre-class="bg-app-950/80 text-3xs text-muted"
44
44
  />
45
45
  </li>
46
46
  </ol>
@@ -12,6 +12,7 @@ import { BUILTIN_TASK_SOURCE_KINDS } from '@cat-factory/contracts'
12
12
  import { apiErrorReason } from '~/composables/api/errors'
13
13
  import { pipelineAllowedForSchedule } from '~/utils/pipeline'
14
14
  import { appliesIntakePredicate } from '~/utils/intakePredicates'
15
+ import SectionLabel from '~/components/common/SectionLabel.vue'
15
16
 
16
17
  const ui = useUiStore()
17
18
  const board = useBoardStore()
@@ -453,7 +454,7 @@ async function add() {
453
454
  <USwitch v-model="onDemand" :disabled="onDemandLocked" size="sm" class="mt-0.5" />
454
455
  <div class="space-y-0.5">
455
456
  <p class="text-xs font-medium text-default">{{ t('board.recurring.onDemand') }}</p>
456
- <p class="text-[11px] text-dimmed">
457
+ <p class="text-2xs text-dimmed">
457
458
  {{
458
459
  onDemandLocked
459
460
  ? t('board.recurring.onDemandLockedHint')
@@ -466,10 +467,10 @@ async function add() {
466
467
  <RecurringRecurrenceEditor v-if="!onDemand" v-model="recurrence" />
467
468
 
468
469
  <div v-if="filesTicket" class="space-y-3 rounded-lg border border-default p-3">
469
- <p class="text-[11px] font-semibold uppercase tracking-wide text-muted">
470
+ <SectionLabel as="p">
470
471
  {{ t('board.recurring.issueTracker') }}
471
- </p>
472
- <p class="text-[11px] text-dimmed">
472
+ </SectionLabel>
473
+ <p class="text-2xs text-dimmed">
473
474
  {{ t('board.recurring.issueTrackerHint') }}
474
475
  </p>
475
476
  <div class="flex gap-1">
@@ -541,22 +542,22 @@ async function add() {
541
542
  <p class="text-xs font-medium text-default">
542
543
  {{ t('board.recurring.trackerTrigger') }}
543
544
  </p>
544
- <p class="text-[11px] text-dimmed">
545
+ <p class="text-2xs text-dimmed">
545
546
  {{ t('board.recurring.trackerTriggerHint') }}
546
547
  </p>
547
548
  </div>
548
549
  </div>
549
550
 
550
551
  <div v-if="showIntake" class="space-y-3 rounded-lg border border-default p-3">
551
- <p class="text-[11px] font-semibold uppercase tracking-wide text-muted">
552
+ <SectionLabel as="p">
552
553
  {{ t('board.recurring.intake') }}
553
- </p>
554
- <p class="text-[11px] text-dimmed">
554
+ </SectionLabel>
555
+ <p class="text-2xs text-dimmed">
555
556
  {{ t('board.recurring.intakeHint') }}
556
557
  </p>
557
558
  <!-- Two different remedies: connect something, versus connect something ELSE. A source
558
559
  that is connected but cannot run a scheduled search is not an absent connection. -->
559
- <p v-if="intakeSources.length === 0" class="text-[11px] text-app-warning-500">
560
+ <p v-if="intakeSources.length === 0" class="text-2xs text-app-warning-500">
560
561
  {{
561
562
  tasks.anyOffered
562
563
  ? t('board.recurring.intakeNoIntakeSources')
@@ -626,7 +627,7 @@ async function add() {
626
627
  </UFormField>
627
628
 
628
629
  <template v-if="intakeSource">
629
- <p class="text-[11px] text-dimmed">
630
+ <p class="text-2xs text-dimmed">
630
631
  {{
631
632
  intakeDispatch === 'per-ticket'
632
633
  ? t('board.recurring.intakeDispatchPerTicketHint')
@@ -677,7 +678,7 @@ async function add() {
677
678
  </template>
678
679
  </div>
679
680
 
680
- <p class="text-[11px] text-dimmed">
681
+ <p class="text-2xs text-dimmed">
681
682
  {{ t('board.recurring.footerHint') }}
682
683
  </p>
683
684
  </div>