@cat-factory/app 0.307.1 → 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 (255) 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 +2 -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/composables/usePipelineErrorToast.ts +2 -0
  243. package/app/utils/catalog.ts +8 -0
  244. package/app/utils/theme/builtins.ts +7 -1
  245. package/i18n/locales/de.json +6 -3
  246. package/i18n/locales/en.json +6 -3
  247. package/i18n/locales/es.json +6 -3
  248. package/i18n/locales/fr.json +6 -3
  249. package/i18n/locales/he.json +6 -3
  250. package/i18n/locales/it.json +6 -3
  251. package/i18n/locales/ja.json +6 -3
  252. package/i18n/locales/pl.json +6 -3
  253. package/i18n/locales/tr.json +6 -3
  254. package/i18n/locales/uk.json +6 -3
  255. package/package.json +2 -2
@@ -15,6 +15,7 @@ import type {
15
15
  type HumanTestRoundOutcome = NonNullable<HumanTestRound['outcome']>
16
16
  import StepRunMeta from '~/components/panels/StepRunMeta.vue'
17
17
  import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
18
+ import SectionLabel from '~/components/common/SectionLabel.vue'
18
19
 
19
20
  const board = useBoardStore()
20
21
  const execution = useExecutionStore()
@@ -168,11 +169,11 @@ const canDestroy = computed(
168
169
  <template v-else>
169
170
  <!-- Environment -->
170
171
  <section class="rounded-lg border border-default bg-default/60 p-4">
171
- <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
172
+ <SectionLabel as="h3" class="mb-2">
172
173
  {{ t('humanTest.environment.heading') }}
173
- </h3>
174
+ </SectionLabel>
174
175
  <div v-if="env" class="space-y-2">
175
- <div class="flex items-center gap-2 text-[13px]">
176
+ <div class="flex items-center gap-2 text-sm">
176
177
  <UIcon
177
178
  name="i-lucide-circle-dot"
178
179
  class="h-3.5 w-3.5"
@@ -187,22 +188,22 @@ const canDestroy = computed(
187
188
  :href="env.url"
188
189
  target="_blank"
189
190
  rel="noopener"
190
- class="inline-flex items-center gap-1.5 break-all text-[13px] text-app-info-300 hover:underline"
191
+ class="inline-flex items-center gap-1.5 break-all text-sm text-app-info-300 hover:underline"
191
192
  >
192
193
  <UIcon name="i-lucide-external-link" class="h-3.5 w-3.5 shrink-0" />
193
194
  {{ env.url }}
194
195
  </a>
195
- <p v-else class="text-[12px] italic text-dimmed">
196
+ <p v-else class="text-xs italic text-dimmed">
196
197
  {{ t('humanTest.environment.noUrl') }}
197
198
  </p>
198
- <p v-if="env.expiresAt" class="text-[11px] text-dimmed">
199
+ <p v-if="env.expiresAt" class="text-2xs text-dimmed">
199
200
  {{ t('humanTest.environment.expires', { date: d(new Date(env.expiresAt), 'long') }) }}
200
201
  </p>
201
202
  </div>
202
- <p v-else class="text-[12px] text-app-warning-300/90">
203
+ <p v-else class="text-xs text-app-warning-300/90">
203
204
  {{ ht.degradedReason ?? t('humanTest.environment.none') }}
204
205
  </p>
205
- <p v-if="env && ht.degradedReason" class="mt-2 text-[12px] text-app-warning-300/90">
206
+ <p v-if="env && ht.degradedReason" class="mt-2 text-xs text-app-warning-300/90">
206
207
  {{ ht.degradedReason }}
207
208
  </p>
208
209
 
@@ -249,7 +250,7 @@ const canDestroy = computed(
249
250
  <!-- Working state -->
250
251
  <p
251
252
  v-if="working"
252
- class="flex items-center gap-2 rounded-lg border border-default bg-app-950/40 px-3 py-2 text-[12px] text-toned"
253
+ class="flex items-center gap-2 rounded-lg border border-default bg-app-950/40 px-3 py-2 text-xs text-toned"
253
254
  >
254
255
  <UIcon name="i-lucide-loader" class="h-3.5 w-3.5 animate-spin text-app-warning-300" />
255
256
  {{ phase ? t(PHASE_LABEL[phase]) : '' }}
@@ -258,11 +259,11 @@ const canDestroy = computed(
258
259
  <!-- Findings / fix -->
259
260
  <section v-if="awaitingHuman" class="rounded-lg border border-default bg-default/60 p-4">
260
261
  <div class="flex items-center justify-between">
261
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
262
+ <SectionLabel as="h3">
262
263
  {{ t('humanTest.fix.heading') }}
263
- </h3>
264
+ </SectionLabel>
264
265
  <button
265
- class="text-[12px] text-muted hover:text-default"
266
+ class="text-xs text-muted hover:text-default"
266
267
  @click="showFindings = !showFindings"
267
268
  >
268
269
  {{ showFindings ? t('humanTest.fix.cancel') : t('humanTest.fix.requestFix') }}
@@ -273,7 +274,7 @@ const canDestroy = computed(
273
274
  v-model="findings"
274
275
  rows="4"
275
276
  :placeholder="t('humanTest.fix.placeholder')"
276
- class="w-full rounded-md border border-muted bg-app-950 px-3 py-2 text-[13px] text-default placeholder:text-app-600 focus:border-app-warning-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-app-warning-500/60"
277
+ class="w-full rounded-md border border-muted bg-app-950 px-3 py-2 text-sm text-default placeholder:text-app-600 focus:border-app-warning-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-app-warning-500/60"
277
278
  />
278
279
  <UButton
279
280
  size="sm"
@@ -294,11 +295,11 @@ const canDestroy = computed(
294
295
  v-if="ht.rounds && ht.rounds.length"
295
296
  class="rounded-lg border border-default bg-default/60 p-4"
296
297
  >
297
- <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
298
+ <SectionLabel as="h3" class="mb-2">
298
299
  {{ t('humanTest.history.heading', { count: ht.attempts }, ht.attempts) }}
299
- </h3>
300
+ </SectionLabel>
300
301
  <ol class="space-y-2">
301
- <li v-for="(r, i) in ht.rounds" :key="i" class="flex items-start gap-2 text-[12px]">
302
+ <li v-for="(r, i) in ht.rounds" :key="i" class="flex items-start gap-2 text-xs">
302
303
  <UIcon
303
304
  :name="r.kind === 'fix' ? 'i-lucide-wrench' : 'i-lucide-git-merge'"
304
305
  class="mt-0.5 h-3.5 w-3.5 shrink-0 text-muted"
@@ -310,7 +311,7 @@ const canDestroy = computed(
310
311
  : t('humanTest.history.pulledMain')
311
312
  }}</span>
312
313
  <span
313
- class="ms-1.5 rounded px-1 text-[10px] uppercase"
314
+ class="ms-1.5 rounded-sm px-1 text-3xs uppercase"
314
315
  :class="
315
316
  r.outcome === 'completed'
316
317
  ? 'bg-app-success-500/15 text-app-success-300'
@@ -45,13 +45,13 @@ const { t } = useI18n()
45
45
  <header class="flex items-start gap-2.5">
46
46
  <UIcon name="i-lucide-clipboard-check" class="mt-0.5 h-4 w-4 shrink-0 text-app-warning-300" />
47
47
  <div class="min-w-0 flex-1">
48
- <h3 class="text-[13px] font-semibold text-app-warning-200">
48
+ <h3 class="text-sm font-semibold text-app-warning-200">
49
49
  {{ t('initiative.planReview.title') }}
50
50
  </h3>
51
- <p class="mt-0.5 text-[12px] leading-relaxed text-app-warning-100/80">
51
+ <p class="mt-0.5 text-xs leading-relaxed text-app-warning-100/80">
52
52
  {{ t('initiative.planReview.body') }}
53
53
  </p>
54
- <p class="mt-2 text-[12px] leading-relaxed text-app-warning-100/70">
54
+ <p class="mt-2 text-xs leading-relaxed text-app-warning-100/70">
55
55
  {{ t('initiative.planReview.noDocument') }}
56
56
  <template v-if="hasSections">
57
57
  {{ t('initiative.planReview.noDocumentSections') }}
@@ -30,6 +30,7 @@ import type { StepApproval } from '~/types/execution'
30
30
  import { useStepProse } from '~/composables/useStepProse'
31
31
  import { useProseComments } from '~/composables/useProseComments'
32
32
  import InitiativePlanDecision from '~/components/initiative/InitiativePlanDecision.vue'
33
+ import SectionLabel from '~/components/common/SectionLabel.vue'
33
34
 
34
35
  const props = defineProps<{
35
36
  /** The parked gate under review. */
@@ -150,12 +151,9 @@ async function copyPlan() {
150
151
  class="hidden w-52 shrink-0 flex-col border-e border-default bg-default/60 lg:flex"
151
152
  >
152
153
  <div class="flex items-center gap-0.5 border-b border-default px-3 py-2">
153
- <span
154
- v-if="outline.hasToc"
155
- class="min-w-0 flex-1 truncate text-[11px] font-semibold uppercase tracking-wide text-dimmed"
156
- >
154
+ <SectionLabel v-if="outline.hasToc" as="span" class="min-w-0 flex-1 truncate">
157
155
  {{ t('panels.stepDetail.contents') }}
158
- </span>
156
+ </SectionLabel>
159
157
  <span v-else class="flex-1" />
160
158
  <!-- Collapse-all tracks the outline: with no headings the only section is the untitled
161
159
  preamble, which renders no toggle of its own, so collapsing it would hide the whole
@@ -190,7 +188,7 @@ async function copyPlan() {
190
188
  <button
191
189
  v-for="s in tocSections"
192
190
  :key="s.id"
193
- class="block w-full truncate rounded-md px-2 py-1 text-start text-[12px] transition"
191
+ class="block w-full truncate rounded-md px-2 py-1 text-start text-xs transition"
194
192
  :class="
195
193
  activeId === s.id
196
194
  ? 'bg-app-warning-500/15 font-medium text-app-warning-100'
@@ -221,9 +219,9 @@ async function copyPlan() {
221
219
  :aria-expanded="runDetailsOpen"
222
220
  @click="runDetailsOpen = !runDetailsOpen"
223
221
  >
224
- <span class="flex-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
222
+ <SectionLabel as="span" class="flex-1">
225
223
  {{ t('panels.stepDetail.details') }}
226
- </span>
224
+ </SectionLabel>
227
225
  <UIcon
228
226
  :name="runDetailsOpen ? 'i-lucide-chevron-down' : 'i-lucide-chevron-up'"
229
227
  class="h-3.5 w-3.5 shrink-0 text-dimmed"
@@ -251,7 +249,7 @@ async function copyPlan() {
251
249
  `5xl` shell), so a cap was dead markup and the comment here said so. On a window that now
252
250
  spans the viewport it is the only thing between the plan and 200-character lines, and it
253
251
  is the step reader's own measure (`AgentStepDetail`, `mx-auto max-w-3xl` over the same
254
- 13px `.reader-prose`) rather than a second opinion about how wide prose should be. The
252
+ `text-sm` `.reader-prose`) rather than a second opinion about how wide prose should be. The
255
253
  leftover width is the document's margins; the LAYOUT is what the extra space bought —
256
254
  outline and rail no longer competing with the plan for one 5xl card. -->
257
255
  <div class="mx-auto w-full max-w-3xl">
@@ -264,7 +262,7 @@ async function copyPlan() {
264
262
  >
265
263
  <button
266
264
  v-if="s.depth > 0"
267
- class="group flex w-full items-center gap-1.5 rounded py-0.5 text-start transition hover:text-highlighted"
265
+ class="group flex w-full items-center gap-1.5 rounded-sm py-0.5 text-start transition hover:text-highlighted"
268
266
  :aria-expanded="!collapsed[s.id]"
269
267
  @click="toggle(s.id)"
270
268
  >
@@ -275,7 +273,7 @@ async function copyPlan() {
275
273
  />
276
274
  <span
277
275
  class="font-semibold text-app-100"
278
- :class="s.depth <= 1 ? 'text-base' : s.depth === 2 ? 'text-sm' : 'text-[13px]'"
276
+ :class="s.depth <= 1 ? 'text-base' : s.depth === 2 ? 'text-sm' : 'text-xs'"
279
277
  v-html="s.titleHtml"
280
278
  />
281
279
  </button>
@@ -285,7 +283,7 @@ async function copyPlan() {
285
283
  <!-- eslint-disable-next-line vue/no-v-html -->
286
284
  <div
287
285
  v-show="!collapsed[s.id]"
288
- class="reader-prose mt-0.5 text-[13px] leading-relaxed text-toned"
286
+ class="reader-prose mt-0.5 text-sm leading-relaxed text-toned"
289
287
  :class="[s.depth > 0 ? 'ps-5' : '', canExecute ? 'review-mode' : '']"
290
288
  @click="onProseClick"
291
289
  v-html="s.bodyHtml"
@@ -305,12 +303,12 @@ async function copyPlan() {
305
303
  <!-- A HEADING, not a styled div: this rail is what the window is now for, so the surface
306
304
  that asks the human for a decision has to be reachable as one. -->
307
305
  <h3
308
- class="flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-app-warning-400"
306
+ class="flex items-center gap-1.5 text-2xs font-semibold uppercase tracking-wide text-app-warning-400"
309
307
  >
310
308
  <UIcon name="i-lucide-clipboard-check" class="h-3.5 w-3.5 shrink-0" />
311
309
  {{ t('initiative.planReview.title') }}
312
310
  </h3>
313
- <p class="mt-1 text-[12px] leading-relaxed text-muted">
311
+ <p class="mt-1 text-xs leading-relaxed text-muted">
314
312
  {{ t('initiative.planReview.body') }}
315
313
  </p>
316
314
  </div>
@@ -322,11 +320,11 @@ async function copyPlan() {
322
320
  data-testid="initiative-plan-composer"
323
321
  class="rounded-lg border border-primary/40 bg-primary/5 p-2.5"
324
322
  >
325
- <div class="mb-1 text-[10px] uppercase tracking-wide text-primary">
323
+ <div class="mb-1 text-3xs uppercase tracking-wide text-primary">
326
324
  {{ t('panels.stepDetail.commentingOn') }}
327
325
  </div>
328
326
  <pre
329
- class="mb-2 max-h-20 overflow-auto whitespace-pre-wrap rounded bg-app-950/60 p-1.5 text-[11px] text-toned"
327
+ class="mb-2 max-h-20 overflow-auto whitespace-pre-wrap rounded-sm bg-app-950/60 p-1.5 text-2xs text-toned"
330
328
  >{{ draftTarget.quotedSource }}</pre>
331
329
  <UTextarea
332
330
  v-model="draftBody"
@@ -361,9 +359,9 @@ async function copyPlan() {
361
359
  class="rounded-lg border border-default bg-default/50 p-2.5"
362
360
  >
363
361
  <div class="mb-1 flex items-start justify-between gap-2">
364
- <div class="text-[10px] uppercase tracking-wide text-dimmed">
362
+ <SectionLabel>
365
363
  {{ t('panels.stepDetail.commentN', { number: idx + 1 }) }}
366
- </div>
364
+ </SectionLabel>
367
365
  <button
368
366
  class="text-dimmed transition hover:text-app-error-400"
369
367
  :title="t('panels.stepDetail.removeComment')"
@@ -373,16 +371,16 @@ async function copyPlan() {
373
371
  </button>
374
372
  </div>
375
373
  <pre
376
- class="mb-1 max-h-16 overflow-auto whitespace-pre-wrap rounded bg-app-950/50 p-1.5 text-[10px] text-muted"
374
+ class="mb-1 max-h-16 overflow-auto whitespace-pre-wrap rounded-sm bg-app-950/50 p-1.5 text-3xs text-muted"
377
375
  >{{ c.quotedSource }}</pre>
378
- <p class="text-[12px] text-default">{{ c.body }}</p>
376
+ <p class="text-xs text-default">{{ c.body }}</p>
379
377
  </div>
380
378
 
381
379
  <!-- Only worth saying where clicking a block does something (the RBAC to act on it) and
382
380
  where nothing has been said yet. -->
383
381
  <p
384
382
  v-if="canExecute && !draftTarget && !planComments.length"
385
- class="text-[11px] leading-relaxed text-muted"
383
+ class="text-2xs leading-relaxed text-muted"
386
384
  >
387
385
  {{ t('initiative.planReview.commentHint') }}
388
386
  </p>
@@ -221,7 +221,7 @@ async function onDiscard() {
221
221
  </div>
222
222
 
223
223
  <template v-else>
224
- <p class="mb-4 text-[13px] leading-relaxed text-toned">
224
+ <p class="mb-4 text-sm leading-relaxed text-toned">
225
225
  {{ t('initiative.planning.intro') }}
226
226
  </p>
227
227
 
@@ -259,7 +259,7 @@ async function onDiscard() {
259
259
  converged, which means the planner already has what it needs). -->
260
260
  <div
261
261
  v-else-if="phase === 'idle' && questions.length === 0"
262
- class="rounded-lg border border-default bg-app-950/40 p-4 text-center text-[13px] text-muted"
262
+ class="rounded-lg border border-default bg-app-950/40 p-4 text-center text-sm text-muted"
263
263
  data-testid="initiative-planning-idle"
264
264
  >
265
265
  {{ t('initiative.planning.idle') }}
@@ -268,7 +268,7 @@ async function onDiscard() {
268
268
  <!-- Converged / no pending questions -->
269
269
  <div
270
270
  v-else-if="phase === 'converged' || questions.length === 0"
271
- class="rounded-lg border border-default bg-app-950/40 p-4 text-center text-[13px] text-muted"
271
+ class="rounded-lg border border-default bg-app-950/40 p-4 text-center text-sm text-muted"
272
272
  data-testid="initiative-planning-converged"
273
273
  >
274
274
  {{ t('initiative.planning.converged') }}
@@ -301,7 +301,7 @@ async function onDiscard() {
301
301
  flush could only drop. -->
302
302
  <p
303
303
  v-if="!addressable(q)"
304
- class="mt-1 text-[11px] text-app-warning-300"
304
+ class="mt-1 text-2xs text-app-warning-300"
305
305
  data-testid="initiative-planning-unanswerable"
306
306
  >
307
307
  {{ t('initiative.planning.unanswerable') }}
@@ -360,7 +360,7 @@ async function onDiscard() {
360
360
  v-if="phase === 'awaiting' && questions.length > 0"
361
361
  class="ms-auto flex items-center gap-2"
362
362
  >
363
- <p class="text-[11px] text-dimmed">
363
+ <p class="text-2xs text-dimmed">
364
364
  <span
365
365
  v-if="unanswered > 0"
366
366
  class="text-app-warning-400/90"
@@ -29,6 +29,7 @@ import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
29
29
  import StepRunMeta from '~/components/panels/StepRunMeta.vue'
30
30
  import InitiativePlanReview from '~/components/initiative/InitiativePlanReview.vue'
31
31
  import InitiativePlanNotice from '~/components/initiative/InitiativePlanNotice.vue'
32
+ import SectionLabel from '~/components/common/SectionLabel.vue'
32
33
 
33
34
  const board = useBoardStore()
34
35
  const initiatives = useInitiativesStore()
@@ -313,7 +314,7 @@ const { requestClose } = useUnsavedGuard({
313
314
  :style="{ width: `${progressPct}%` }"
314
315
  />
315
316
  </div>
316
- <span class="text-[11px] tabular-nums text-muted">
317
+ <span class="text-2xs tabular-nums text-muted">
317
318
  {{ t('initiative.card.progress', { done: progress.settled, total: progress.total }) }}
318
319
  </span>
319
320
  </div>
@@ -385,15 +386,15 @@ const { requestClose } = useUnsavedGuard({
385
386
  class="mt-0.5 h-4 w-4 shrink-0 text-app-warning-300"
386
387
  />
387
388
  <div class="min-w-0 flex-1">
388
- <h3 class="text-[13px] font-semibold text-app-warning-200">
389
+ <h3 class="text-sm font-semibold text-app-warning-200">
389
390
  {{ t('initiative.checkpoint.pausedTitle') }}
390
391
  </h3>
391
- <p class="mt-0.5 text-[12px] leading-relaxed text-app-warning-100/80">
392
+ <p class="mt-0.5 text-xs leading-relaxed text-app-warning-100/80">
392
393
  {{ t('initiative.checkpoint.pausedBody', { phase: checkpointPhase!.title }) }}
393
394
  </p>
394
395
  <div class="mt-2.5 flex flex-wrap gap-2">
395
396
  <button
396
- class="rounded bg-primary/90 px-2.5 py-1 text-[11px] font-medium text-inverted hover:bg-primary disabled:opacity-50"
397
+ class="rounded-sm bg-primary/90 px-2.5 py-1 text-2xs font-medium text-inverted hover:bg-primary disabled:opacity-50"
397
398
  :disabled="initiatives.controlling"
398
399
  data-testid="initiative-checkpoint-resume"
399
400
  @click="checkpointControl('resume')"
@@ -401,7 +402,7 @@ const { requestClose } = useUnsavedGuard({
401
402
  {{ t('initiative.inspector.resume') }}
402
403
  </button>
403
404
  <button
404
- class="rounded border border-app-error-500/50 px-2.5 py-1 text-[11px] font-medium text-app-error-300 hover:bg-app-error-500/10 disabled:opacity-50"
405
+ class="rounded-sm border border-app-error-500/50 px-2.5 py-1 text-2xs font-medium text-app-error-300 hover:bg-app-error-500/10 disabled:opacity-50"
405
406
  :disabled="initiatives.controlling"
406
407
  data-testid="initiative-checkpoint-cancel"
407
408
  @click="checkpointControl('cancel')"
@@ -418,34 +419,34 @@ const { requestClose } = useUnsavedGuard({
418
419
  structure that reads better at the full span, but these are paragraphs and bullets
419
420
  of agent-written text that would otherwise run the width of the display. -->
420
421
  <section v-if="initiative.goal" class="mb-4">
421
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
422
+ <SectionLabel as="h3" class="mb-1">
422
423
  {{ t('initiative.tracker.goal') }}
423
- </h3>
424
- <p class="max-w-3xl whitespace-pre-wrap text-[13px] leading-relaxed text-toned">
424
+ </SectionLabel>
425
+ <p class="max-w-3xl whitespace-pre-wrap text-sm leading-relaxed text-toned">
425
426
  {{ initiative.goal }}
426
427
  </p>
427
428
  </section>
428
429
  <section v-if="initiative.constraints?.length" class="mb-4">
429
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
430
+ <SectionLabel as="h3" class="mb-1">
430
431
  {{ t('initiative.tracker.constraints') }}
431
- </h3>
432
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
432
+ </SectionLabel>
433
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
433
434
  <li v-for="(c, i) in initiative.constraints" :key="i">{{ c }}</li>
434
435
  </ul>
435
436
  </section>
436
437
  <section v-if="initiative.nonGoals?.length" class="mb-4">
437
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
438
+ <SectionLabel as="h3" class="mb-1">
438
439
  {{ t('initiative.tracker.nonGoals') }}
439
- </h3>
440
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
440
+ </SectionLabel>
441
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
441
442
  <li v-for="(g, i) in initiative.nonGoals" :key="i">{{ g }}</li>
442
443
  </ul>
443
444
  </section>
444
445
  <section v-if="initiative.analysisSummary" class="mb-4">
445
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
446
+ <SectionLabel as="h3" class="mb-1">
446
447
  {{ t('initiative.tracker.analysis') }}
447
- </h3>
448
- <p class="max-w-3xl whitespace-pre-wrap text-[13px] leading-relaxed text-toned">
448
+ </SectionLabel>
449
+ <p class="max-w-3xl whitespace-pre-wrap text-sm leading-relaxed text-toned">
449
450
  {{ initiative.analysisSummary }}
450
451
  </p>
451
452
  </section>
@@ -453,7 +454,7 @@ const { requestClose } = useUnsavedGuard({
453
454
  <!-- Awaiting planning -->
454
455
  <div
455
456
  v-if="phases.length === 0"
456
- class="mb-4 rounded-lg border border-dashed border-muted p-4 text-center text-[12px] text-muted"
457
+ class="mb-4 rounded-lg border border-dashed border-muted p-4 text-center text-xs text-muted"
457
458
  >
458
459
  {{ t('initiative.tracker.noPlan') }}
459
460
  </div>
@@ -488,9 +489,9 @@ const { requestClose } = useUnsavedGuard({
488
489
  }}
489
490
  </UBadge>
490
491
  </h3>
491
- <p v-if="phase.goal" class="mb-2 text-[12px] text-muted">{{ phase.goal }}</p>
492
+ <p v-if="phase.goal" class="mb-2 text-xs text-muted">{{ phase.goal }}</p>
492
493
  <div class="overflow-x-auto rounded-lg border border-default">
493
- <table class="w-full text-[12px]">
494
+ <table class="w-full text-xs">
494
495
  <thead>
495
496
  <tr class="border-b border-default text-left text-dimmed">
496
497
  <th class="px-3 py-2 font-medium">{{ t('initiative.tracker.colItem') }}</th>
@@ -506,7 +507,7 @@ const { requestClose } = useUnsavedGuard({
506
507
  >
507
508
  <td class="px-3 py-2 align-top">
508
509
  <div class="font-medium text-default">{{ item.title }}</div>
509
- <div v-if="item.dependsOn?.length" class="mt-0.5 text-[10px] text-dimmed">
510
+ <div v-if="item.dependsOn?.length" class="mt-0.5 text-3xs text-dimmed">
510
511
  {{
511
512
  t('initiative.tracker.dependsOn', {
512
513
  items: item.dependsOn.join(', '),
@@ -515,7 +516,7 @@ const { requestClose } = useUnsavedGuard({
515
516
  </div>
516
517
  <div
517
518
  v-if="item.note"
518
- class="mt-0.5 max-w-3xl text-[10px] text-app-warning-300/80"
519
+ class="mt-0.5 max-w-3xl text-3xs text-app-warning-300/80"
519
520
  >
520
521
  {{ item.note }}
521
522
  </div>
@@ -525,7 +526,7 @@ const { requestClose } = useUnsavedGuard({
525
526
  >
526
527
  <button
527
528
  v-if="item.status === 'blocked'"
528
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated disabled:opacity-50"
529
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated disabled:opacity-50"
529
530
  :disabled="initiatives.curating"
530
531
  :data-testid="`initiative-item-retry-${item.id}`"
531
532
  @click="itemAction(item, 'retry')"
@@ -533,7 +534,7 @@ const { requestClose } = useUnsavedGuard({
533
534
  {{ t('initiative.curation.retry') }}
534
535
  </button>
535
536
  <button
536
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated disabled:opacity-50"
537
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated disabled:opacity-50"
537
538
  :disabled="initiatives.curating"
538
539
  :data-testid="`initiative-item-skip-${item.id}`"
539
540
  @click="itemAction(item, 'skip')"
@@ -572,19 +573,19 @@ const { requestClose } = useUnsavedGuard({
572
573
  <!-- Execution policy -->
573
574
  <section v-if="initiative.policy" class="mb-4">
574
575
  <div class="mb-1 flex items-center gap-2">
575
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
576
+ <SectionLabel as="h3">
576
577
  {{ t('initiative.tracker.policy') }}
577
- </h3>
578
+ </SectionLabel>
578
579
  <button
579
580
  v-if="editable && !editingPolicy"
580
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated"
581
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated"
581
582
  data-testid="initiative-policy-edit"
582
583
  @click="startEditPolicy"
583
584
  >
584
585
  {{ t('initiative.curation.edit') }}
585
586
  </button>
586
587
  </div>
587
- <ul v-if="!editingPolicy" class="text-[12px] text-toned">
588
+ <ul v-if="!editingPolicy" class="text-xs text-toned">
588
589
  <li>
589
590
  {{
590
591
  t('initiative.tracker.maxConcurrent', {
@@ -603,29 +604,29 @@ const { requestClose } = useUnsavedGuard({
603
604
  </ul>
604
605
  <!-- Edit form: the two scalar knobs; planner-authored rules are preserved. -->
605
606
  <div v-else class="flex flex-col gap-2 rounded-lg border border-default p-3">
606
- <label class="flex items-center gap-2 text-[12px] text-toned">
607
+ <label class="flex items-center gap-2 text-xs text-toned">
607
608
  <span class="w-40">{{ t('initiative.curation.maxConcurrentField') }}</span>
608
609
  <input
609
610
  v-model.number="policyForm.maxConcurrent"
610
611
  type="number"
611
612
  min="1"
612
613
  max="20"
613
- class="w-20 rounded border border-muted bg-app-950 px-2 py-1 text-default"
614
+ class="w-20 rounded-sm border border-muted bg-app-950 px-2 py-1 text-default"
614
615
  data-testid="initiative-policy-max-concurrent"
615
616
  />
616
617
  </label>
617
- <label class="flex items-center gap-2 text-[12px] text-toned">
618
+ <label class="flex items-center gap-2 text-xs text-toned">
618
619
  <span class="w-40">{{ t('initiative.curation.defaultPipelineField') }}</span>
619
620
  <input
620
621
  v-model="policyForm.defaultPipelineId"
621
622
  type="text"
622
- class="flex-1 rounded border border-muted bg-app-950 px-2 py-1 font-mono text-[11px] text-default"
623
+ class="flex-1 rounded-sm border border-muted bg-app-950 px-2 py-1 font-mono text-2xs text-default"
623
624
  data-testid="initiative-policy-default-pipeline"
624
625
  />
625
626
  </label>
626
627
  <div class="flex gap-2">
627
628
  <button
628
- class="rounded bg-primary/90 px-2 py-1 text-[11px] text-inverted hover:bg-primary disabled:opacity-50"
629
+ class="rounded-sm bg-primary/90 px-2 py-1 text-2xs text-inverted hover:bg-primary disabled:opacity-50"
629
630
  :disabled="initiatives.curating"
630
631
  data-testid="initiative-policy-save"
631
632
  @click="savePolicy"
@@ -633,7 +634,7 @@ const { requestClose } = useUnsavedGuard({
633
634
  {{ t('initiative.curation.save') }}
634
635
  </button>
635
636
  <button
636
- class="rounded border border-muted px-2 py-1 text-[11px] text-toned hover:bg-elevated"
637
+ class="rounded-sm border border-muted px-2 py-1 text-2xs text-toned hover:bg-elevated"
637
638
  @click="editingPolicy = false"
638
639
  >
639
640
  {{ t('initiative.curation.cancel') }}
@@ -644,10 +645,10 @@ const { requestClose } = useUnsavedGuard({
644
645
 
645
646
  <!-- Logs -->
646
647
  <section v-if="initiative.decisions?.length" class="mb-4">
647
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
648
+ <SectionLabel as="h3" class="mb-1">
648
649
  {{ t('initiative.tracker.decisions') }}
649
- </h3>
650
- <ul class="list-inside list-disc text-[13px] text-toned">
650
+ </SectionLabel>
651
+ <ul class="list-inside list-disc text-sm text-toned">
651
652
  <li v-for="d in initiative.decisions" :key="d.id">
652
653
  <span class="font-medium">{{ d.title }}</span>
653
654
  <span v-if="d.detail" class="text-muted"> — {{ d.detail }}</span>
@@ -655,10 +656,10 @@ const { requestClose } = useUnsavedGuard({
655
656
  </ul>
656
657
  </section>
657
658
  <section v-if="initiative.deviations?.length" class="mb-4">
658
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
659
+ <SectionLabel as="h3" class="mb-1">
659
660
  {{ t('initiative.tracker.deviations') }}
660
- </h3>
661
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
661
+ </SectionLabel>
662
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
662
663
  <li v-for="d in initiative.deviations" :key="d.id">
663
664
  <code v-if="d.itemId" class="text-muted">{{ d.itemId }}</code>
664
665
  {{ d.description }}
@@ -667,10 +668,10 @@ const { requestClose } = useUnsavedGuard({
667
668
  </ul>
668
669
  </section>
669
670
  <section v-if="initiative.followUps?.length" class="mb-4">
670
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
671
+ <SectionLabel as="h3" class="mb-1">
671
672
  {{ t('initiative.tracker.followUps') }}
672
- </h3>
673
- <ul class="flex flex-col gap-2 text-[13px] text-toned">
673
+ </SectionLabel>
674
+ <ul class="flex flex-col gap-2 text-sm text-toned">
674
675
  <li
675
676
  v-for="f in initiative.followUps"
676
677
  :key="f.id"
@@ -693,11 +694,11 @@ const { requestClose } = useUnsavedGuard({
693
694
  <!-- Triage actions for an open follow-up (only while executing) -->
694
695
  <div v-if="editable && f.status === 'open'" class="mt-2">
695
696
  <div v-if="promotingId === f.id" class="flex flex-col gap-2">
696
- <label class="flex items-center gap-2 text-[12px]">
697
+ <label class="flex items-center gap-2 text-xs">
697
698
  <span class="text-muted">{{ t('initiative.curation.phaseField') }}</span>
698
699
  <select
699
700
  v-model="promoteForm.phaseId"
700
- class="flex-1 rounded border border-muted bg-app-950 px-2 py-1 text-default"
701
+ class="flex-1 rounded-sm border border-muted bg-app-950 px-2 py-1 text-default"
701
702
  data-testid="initiative-promote-phase"
702
703
  >
703
704
  <option v-for="p in phases" :key="p.id" :value="p.id">
@@ -708,13 +709,13 @@ const { requestClose } = useUnsavedGuard({
708
709
  <input
709
710
  v-model="promoteForm.title"
710
711
  type="text"
711
- class="rounded border border-muted bg-app-950 px-2 py-1 text-[12px] text-default"
712
+ class="rounded-sm border border-muted bg-app-950 px-2 py-1 text-xs text-default"
712
713
  :placeholder="t('initiative.curation.itemTitlePlaceholder')"
713
714
  data-testid="initiative-promote-title"
714
715
  />
715
716
  <div class="flex gap-2">
716
717
  <button
717
- class="rounded bg-primary/90 px-2 py-1 text-[11px] text-inverted hover:bg-primary disabled:opacity-50"
718
+ class="rounded-sm bg-primary/90 px-2 py-1 text-2xs text-inverted hover:bg-primary disabled:opacity-50"
718
719
  :disabled="initiatives.curating || !promoteForm.phaseId"
719
720
  data-testid="initiative-promote-submit"
720
721
  @click="submitPromote(f)"
@@ -722,7 +723,7 @@ const { requestClose } = useUnsavedGuard({
722
723
  {{ t('initiative.curation.promoteConfirm') }}
723
724
  </button>
724
725
  <button
725
- class="rounded border border-muted px-2 py-1 text-[11px] text-toned hover:bg-elevated"
726
+ class="rounded-sm border border-muted px-2 py-1 text-2xs text-toned hover:bg-elevated"
726
727
  @click="promotingId = null"
727
728
  >
728
729
  {{ t('initiative.curation.cancel') }}
@@ -731,14 +732,14 @@ const { requestClose } = useUnsavedGuard({
731
732
  </div>
732
733
  <div v-else class="flex gap-1.5">
733
734
  <button
734
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated"
735
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated"
735
736
  data-testid="initiative-followup-promote"
736
737
  @click="startPromote(f)"
737
738
  >
738
739
  {{ t('initiative.curation.promote') }}
739
740
  </button>
740
741
  <button
741
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated disabled:opacity-50"
742
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated disabled:opacity-50"
742
743
  :disabled="initiatives.curating"
743
744
  data-testid="initiative-followup-dismiss"
744
745
  @click="dismissFollowUp(f)"
@@ -751,10 +752,10 @@ const { requestClose } = useUnsavedGuard({
751
752
  </ul>
752
753
  </section>
753
754
  <section v-if="initiative.caveats?.length" class="mb-4">
754
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
755
+ <SectionLabel as="h3" class="mb-1">
755
756
  {{ t('initiative.tracker.caveats') }}
756
- </h3>
757
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
757
+ </SectionLabel>
758
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
758
759
  <li v-for="(c, i) in initiative.caveats" :key="i">{{ c }}</li>
759
760
  </ul>
760
761
  </section>