@stacksjs/defaults 0.75.329 → 0.75.334

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 (70) hide show
  1. package/ai/skills/stacks-native/CATALOG.md +6 -6
  2. package/ide/vscode/package.json +1 -1
  3. package/package.json +4 -4
  4. package/resources/components/Dashboard/Auth/ForgotPassword.stx +1 -1
  5. package/resources/components/Dashboard/Ci/CiDashboard.stx +7 -7
  6. package/resources/components/Dashboard/Ci/CiRunHistoryDrawer.stx +3 -3
  7. package/resources/components/Dashboard/Commerce/CommerceCategoriesTable.stx +1 -1
  8. package/resources/components/Dashboard/Commerce/CommerceCategoryDetailsDialog.stx +5 -5
  9. package/resources/components/Dashboard/Commerce/CommerceCategoryDialog.stx +2 -2
  10. package/resources/components/Dashboard/Commerce/CommerceCategoryHierarchy.stx +2 -2
  11. package/resources/components/Dashboard/Commerce/CommerceCouponDetailsDialog.stx +9 -9
  12. package/resources/components/Dashboard/Commerce/CommerceCouponDialog.stx +1 -1
  13. package/resources/components/Dashboard/Commerce/CommerceCustomerDetailsDialog.stx +5 -5
  14. package/resources/components/Dashboard/Commerce/CommerceCustomerDialog.stx +2 -2
  15. package/resources/components/Dashboard/Commerce/CommerceCustomersTable.stx +1 -1
  16. package/resources/components/Dashboard/Commerce/CommerceGiftCardBreakdown.stx +1 -1
  17. package/resources/components/Dashboard/Commerce/CommerceGiftCardDetailsDialog.stx +11 -11
  18. package/resources/components/Dashboard/Commerce/CommerceOrderDetailsDialog.stx +13 -13
  19. package/resources/components/Dashboard/Commerce/CommercePaymentsBreakdown.stx +2 -2
  20. package/resources/components/Dashboard/Commerce/CommercePosCart.stx +1 -1
  21. package/resources/components/Dashboard/Commerce/CommercePosCatalog.stx +1 -1
  22. package/resources/components/Dashboard/Commerce/CommercePosReceiptDialog.stx +1 -1
  23. package/resources/components/Dashboard/Commerce/CommerceProductDetailDashboard.stx +8 -8
  24. package/resources/components/Dashboard/Commerce/CommerceProductDialog.stx +1 -1
  25. package/resources/components/Dashboard/Commerce/CommerceProductsTable.stx +2 -2
  26. package/resources/components/Dashboard/Commerce/CommerceReviewsTable.stx +1 -1
  27. package/resources/components/Dashboard/Commerce/CommerceVariantsTable.stx +1 -1
  28. package/resources/components/Dashboard/Commerce/Delivery/DeliveryOverviewDashboard.stx +1 -1
  29. package/resources/components/Dashboard/Commerce/Delivery/DigitalDeliveryDialog.stx +2 -2
  30. package/resources/components/Dashboard/Commerce/PaymentDetailsDialog.stx +3 -3
  31. package/resources/components/Dashboard/Commerce/PrintDeviceDetailsDialog.stx +6 -6
  32. package/resources/components/Dashboard/Commerce/PrintLogBreakdown.stx +1 -1
  33. package/resources/components/Dashboard/Commerce/PrintLogDetailsDialog.stx +2 -2
  34. package/resources/components/Dashboard/Commerce/PrintLogsTable.stx +3 -3
  35. package/resources/components/Dashboard/Content/CommentsDashboard.stx +1 -1
  36. package/resources/components/Dashboard/Content/FileStoragePanel.stx +6 -6
  37. package/resources/components/Dashboard/Content/FileUploadDialog.stx +1 -1
  38. package/resources/components/Dashboard/Content/PostEditorDialog.stx +2 -2
  39. package/resources/components/Dashboard/Content/PostsDashboard.stx +1 -1
  40. package/resources/components/Dashboard/Content/SeoEditorDialog.stx +1 -1
  41. package/resources/components/Dashboard/Deployments/DeploymentPreviewDialog.stx +1 -1
  42. package/resources/components/Dashboard/Feedback/FeedbackForm.stx +4 -4
  43. package/resources/components/Dashboard/FileViewer/MediaCard.stx +1 -1
  44. package/resources/components/Dashboard/FileViewer/MediaInfoPanel.stx +4 -4
  45. package/resources/components/Dashboard/GlobalSearch.stx +4 -4
  46. package/resources/components/Dashboard/Infrastructure/CloudDashboard.stx +1 -1
  47. package/resources/components/Dashboard/Infrastructure/DnsDashboard.stx +2 -2
  48. package/resources/components/Dashboard/Infrastructure/LogsDashboard.stx +2 -2
  49. package/resources/components/Dashboard/Infrastructure/MailboxesDashboard.stx +3 -3
  50. package/resources/components/Dashboard/Infrastructure/ServerlessDashboard.stx +1 -1
  51. package/resources/components/Dashboard/Infrastructure/ServersDashboard.stx +5 -5
  52. package/resources/components/Dashboard/Kanban/KanbanBoardDashboard.stx +1 -1
  53. package/resources/components/Dashboard/Kanban/KanbanBoardsDashboard.stx +2 -2
  54. package/resources/components/Dashboard/Kanban/KanbanCardDialog.stx +8 -8
  55. package/resources/components/Dashboard/Marketing/AbandonedCartsDashboard.stx +5 -5
  56. package/resources/components/Dashboard/Marketing/CampaignsDashboard.stx +5 -5
  57. package/resources/components/Dashboard/Marketing/MarketingListsDashboard.stx +4 -4
  58. package/resources/components/Dashboard/Marketing/SocialPostsDashboard.stx +4 -4
  59. package/resources/components/Dashboard/Models/ModelsOverview.stx +1 -1
  60. package/resources/components/Dashboard/Navbar.stx +2 -2
  61. package/resources/components/Dashboard/Operations/AuditDashboard.stx +1 -1
  62. package/resources/components/Dashboard/Operations/OperationHistory.stx +1 -1
  63. package/resources/components/Dashboard/Operations/RecoveryJobList.stx +1 -1
  64. package/resources/components/Dashboard/Remote/RemoteConsole.stx +1 -1
  65. package/resources/components/Dashboard/Settings/SettingsDashboard.stx +1 -1
  66. package/resources/components/Dashboard/UI/Checkbox.stx +1 -1
  67. package/resources/components/Dashboard/UI/MetricCards.stx +1 -1
  68. package/resources/components/Dashboard/UI/Pagination.stx +1 -1
  69. package/resources/components/Dashboard/UI/Textarea.stx +2 -2
  70. package/resources/components/Dashboard/UI/Toggle.stx +1 -1
@@ -150,7 +150,7 @@ function errorMessages(): string[] {
150
150
  </ul>
151
151
  <div class="grid gap-4 grid-cols-1 sm:grid-cols-2">
152
152
  <label class="block sm:col-span-2"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Name</span><input x-model="name" type="text" maxlength="100" required class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
153
- <label class="block sm:col-span-2"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Slug</span><input x-model="slug" type="text" maxlength="255" required spellcheck="false" class="mt-1 px-3 py-2 w-full font-mono text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" @input="markSlugTouched" @blur="normalizeSlug" /><span class="block mt-1 text-gray-400 text-xs dark:text-neutral-500">The storefront address, /products/{{ slug() || 'slug' }}.</span></label>
153
+ <label class="block sm:col-span-2"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Slug</span><input x-model="slug" type="text" maxlength="255" required spellcheck="false" class="mt-1 px-3 py-2 w-full font-mono text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" @input="markSlugTouched" @blur="normalizeSlug" /><span class="block mt-1 text-gray-500 text-xs dark:text-neutral-500">The storefront address, /products/{{ slug() || 'slug' }}.</span></label>
154
154
  <label class="block sm:col-span-2"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Description</span><textarea x-model="description" rows="3" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700"></textarea></label>
155
155
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Price ({{ currency() }})</span><input x-model="price" type="number" min="0" :step="moneyInputStep(currency())" inputmode="decimal" required :aria-invalid="price() !== '' && priceError() !== ''" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /><span :if="price() !== '' && priceError()" class="block mt-1 text-red-600 text-xs dark:text-red-400">{{ priceError() }}</span></label>
156
156
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Inventory count</span><input x-model="inventoryCount" type="number" min="0" step="1" required class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
@@ -85,13 +85,13 @@ function handleRowAction(payload: { action: string, row: CommerceProductRecord }
85
85
  <div class="flex flex-none items-center justify-center h-9 w-9 font-semibold text-blue-700 text-xs dark:text-blue-300 bg-blue-50 dark:bg-blue-950/40 rounded-md" x-text="row.initials"></div>
86
86
  <div class="min-w-0">
87
87
  <p class="font-medium text-gray-900 text-sm dark:text-white" x-text="row.nameLabel"></p>
88
- <p class="mt-1 max-w-52 text-gray-400 text-xs truncate dark:text-neutral-500" x-text="row.descriptionLabel"></p>
88
+ <p class="mt-1 max-w-52 text-gray-500 text-xs truncate dark:text-neutral-500" x-text="row.descriptionLabel"></p>
89
89
  </div>
90
90
  </div>
91
91
  </template>
92
92
  <template :if="column.key === 'inventoryCount'">
93
93
  <p :class="'font-medium text-sm ' + (row.outOfStock ? 'text-red-600 dark:text-red-400' : 'text-gray-700 dark:text-neutral-200')" x-text="row.inventoryLabel"></p>
94
- <p class="mt-1 text-gray-400 text-xs dark:text-neutral-500" x-text="row.prepLabel"></p>
94
+ <p class="mt-1 text-gray-500 text-xs dark:text-neutral-500" x-text="row.prepLabel"></p>
95
95
  </template>
96
96
  </template>
97
97
  </Table>
@@ -111,7 +111,7 @@ function handleRowAction(payload: { action: string, row: ReviewRecord }): void {
111
111
  <div class="max-w-lg min-w-72">
112
112
  <p class="font-medium text-gray-900 text-sm dark:text-white" x-text="row.titleLabel"></p>
113
113
  <p class="mt-1 line-clamp-2 text-gray-500 text-sm dark:text-neutral-400" x-text="row.contentLabel"></p>
114
- <div class="flex flex-wrap gap-x-3 gap-y-1 items-center mt-2 text-gray-400 text-xs dark:text-neutral-500">
114
+ <div class="flex flex-wrap gap-x-3 gap-y-1 items-center mt-2 text-gray-500 text-xs dark:text-neutral-500">
115
115
  <span :aria-label="row.starsLabel" class="text-amber-500 text-sm" x-text="row.stars"></span>
116
116
  <span x-text="row.helpfulLabel"></span>
117
117
  <span x-text="row.unhelpfulLabel"></span>
@@ -74,7 +74,7 @@ function handleRowAction(payload: { action: string, row: ProductVariantRecord })
74
74
  <span class="px-2 py-0.5 text-blue-700 text-xs dark:text-blue-300 bg-blue-50 dark:bg-blue-950/40 rounded-full" x-text="option"></span>
75
75
  </template>
76
76
  <span :if="row.moreOptions" class="px-2 py-0.5 text-gray-600 text-xs dark:text-neutral-300 bg-gray-100 dark:bg-neutral-700 rounded-full" x-text="row.moreOptions"></span>
77
- <span :if="row.shownOptions.length === 0" class="text-gray-400 text-xs">No options</span>
77
+ <span :if="row.shownOptions.length === 0" class="text-gray-500 text-xs dark:text-gray-400">No options</span>
78
78
  </div>
79
79
  </template>
80
80
  </template>
@@ -182,7 +182,7 @@ onMount(() => {
182
182
  <span :class="'h-5 w-5 text-blue-600 dark:text-blue-400 ' + statIcon(item.label)"></span>
183
183
  </div>
184
184
  <p class="mt-2 font-semibold tabular-nums text-2xl text-gray-900 dark:text-white">{{ item.value }}</p>
185
- <p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ item.detail }}</p>
185
+ <p class="mt-1 text-gray-500 text-xs dark:text-neutral-500">{{ item.detail }}</p>
186
186
  </article>
187
187
  </template>
188
188
  </section>
@@ -93,8 +93,8 @@ function submit(): void {
93
93
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Method name</span><input x-model="name" type="text" required maxlength="255" autocomplete="off" placeholder="Secure download" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /></label>
94
94
  <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Description</span><textarea x-model="description" required rows="3" placeholder="Explain how customers receive and access files." class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700 resize-y"></textarea></label>
95
95
  <div class="grid gap-4 grid-cols-1 sm:grid-cols-2">
96
- <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Download limit</span><input x-model="downloadLimit" type="number" min="0" step="1" inputmode="numeric" placeholder="Unlimited" class="mt-1 px-3 py-2 w-full tabular-nums text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /><span class="block mt-1 text-gray-400 text-xs dark:text-neutral-500">Leave blank for unlimited downloads.</span></label>
97
- <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Expiry days</span><input x-model="expiryDays" type="number" required min="0" step="1" inputmode="numeric" class="mt-1 px-3 py-2 w-full tabular-nums text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /><span class="block mt-1 text-gray-400 text-xs dark:text-neutral-500">Use 0 for access without expiry.</span></label>
96
+ <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Download limit</span><input x-model="downloadLimit" type="number" min="0" step="1" inputmode="numeric" placeholder="Unlimited" class="mt-1 px-3 py-2 w-full tabular-nums text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /><span class="block mt-1 text-gray-500 text-xs dark:text-neutral-500">Leave blank for unlimited downloads.</span></label>
97
+ <label class="block"><span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Expiry days</span><input x-model="expiryDays" type="number" required min="0" step="1" inputmode="numeric" class="mt-1 px-3 py-2 w-full tabular-nums text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700" /><span class="block mt-1 text-gray-500 text-xs dark:text-neutral-500">Use 0 for access without expiry.</span></label>
98
98
  </div>
99
99
  <div class="grid gap-3 grid-cols-1 sm:grid-cols-2">
100
100
  <label class="flex gap-3 items-start p-3 border border-gray-200 rounded-lg dark:border-neutral-700"><input x-model="requiresLogin" type="checkbox" class="mt-0.5 h-4 w-4 text-blue-600 bg-white dark:bg-neutral-900 border-gray-300 rounded dark:border-neutral-600" /><span><strong class="block text-gray-900 text-sm dark:text-white">Require login</strong><span class="block mt-0.5 text-gray-500 text-xs dark:text-neutral-400">Only authenticated customers can download.</span></span></label>
@@ -48,10 +48,10 @@ function refundable(): boolean {
48
48
  </template>
49
49
  <dl class="grid gap-x-6 gap-y-4 sm:grid-cols-2">
50
50
  <template :for="item in detailRows()" :key="item.label">
51
- <div><dt class="text-gray-400 text-xs dark:text-neutral-500">{{ item.label }}</dt><dd class="mt-1 break-all text-gray-800 text-sm dark:text-neutral-100">{{ item.value }}</dd></div>
51
+ <div><dt class="text-gray-500 text-xs dark:text-neutral-500">{{ item.label }}</dt><dd class="mt-1 break-all text-gray-800 text-sm dark:text-neutral-100">{{ item.value }}</dd></div>
52
52
  </template>
53
- <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Method</dt><dd class="mt-1 capitalize text-gray-800 text-sm dark:text-neutral-100">{{ label(record()?.method || '') }}</dd></div>
54
- <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Refund recorded</dt><dd class="mt-1 text-gray-800 text-sm dark:text-neutral-100">{{ record()?.refundAmount ? money(record()?.refundAmount || 0, record()?.currency || 'USD') : record()?.status === 'refunded' && !record()?.refundRecorded ? 'Amount missing' : money(0, record()?.currency || 'USD') }}</dd></div>
53
+ <div><dt class="text-gray-500 text-xs dark:text-neutral-500">Method</dt><dd class="mt-1 capitalize text-gray-800 text-sm dark:text-neutral-100">{{ label(record()?.method || '') }}</dd></div>
54
+ <div><dt class="text-gray-500 text-xs dark:text-neutral-500">Refund recorded</dt><dd class="mt-1 text-gray-800 text-sm dark:text-neutral-100">{{ record()?.refundAmount ? money(record()?.refundAmount || 0, record()?.currency || 'USD') : record()?.status === 'refunded' && !record()?.refundRecorded ? 'Amount missing' : money(0, record()?.currency || 'USD') }}</dd></div>
55
55
  </dl>
56
56
 
57
57
  <div :if="record()?.notes" class="mt-5 p-3 text-gray-600 text-sm dark:text-neutral-300 bg-gray-50 dark:bg-neutral-900/60 rounded-lg">{{ record()?.notes }}</div>
@@ -49,12 +49,12 @@ function deleteRecord(): void {
49
49
  <span class="px-2 py-1 capitalize font-semibold text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ label(record()?.status || '') }}</span>
50
50
  </template>
51
51
  <dl class="grid gap-4 grid-cols-2">
52
- <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Location</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ record()?.location || 'Not recorded' }}</dd></div>
53
- <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Terminal</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ record()?.terminal || 'Not recorded' }}</dd></div>
54
- <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Recorded prints</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ (record()?.printCount || 0).toLocaleString() }}</dd></div>
55
- <div><dt class="text-gray-400 text-xs dark:text-neutral-500">Record ID</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ record()?.id || 'Not recorded' }}</dd></div>
56
- <div class="col-span-2"><dt class="text-gray-400 text-xs dark:text-neutral-500">Last heartbeat</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ formatDate(record()?.lastPing || 0) }}</dd></div>
57
- <div class="col-span-2"><dt class="text-gray-400 text-xs dark:text-neutral-500">Created</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ formatDate(record()?.createdAt || '') }}</dd></div>
52
+ <div><dt class="text-gray-500 text-xs dark:text-neutral-500">Location</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ record()?.location || 'Not recorded' }}</dd></div>
53
+ <div><dt class="text-gray-500 text-xs dark:text-neutral-500">Terminal</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ record()?.terminal || 'Not recorded' }}</dd></div>
54
+ <div><dt class="text-gray-500 text-xs dark:text-neutral-500">Recorded prints</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ (record()?.printCount || 0).toLocaleString() }}</dd></div>
55
+ <div><dt class="text-gray-500 text-xs dark:text-neutral-500">Record ID</dt><dd class="mt-1 font-mono text-gray-900 text-sm dark:text-white">{{ record()?.id || 'Not recorded' }}</dd></div>
56
+ <div class="col-span-2"><dt class="text-gray-500 text-xs dark:text-neutral-500">Last heartbeat</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ formatDate(record()?.lastPing || 0) }}</dd></div>
57
+ <div class="col-span-2"><dt class="text-gray-500 text-xs dark:text-neutral-500">Created</dt><dd class="mt-1 text-gray-900 text-sm dark:text-white">{{ formatDate(record()?.createdAt || '') }}</dd></div>
58
58
  </dl>
59
59
  <template #footer>
60
60
  <div class="flex gap-2 justify-between w-full">
@@ -67,7 +67,7 @@ function hourlyRows(): CountRow[] {
67
67
  </article>
68
68
 
69
69
  <article class="p-4 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
70
- <div class="flex items-start justify-between"><h2 class="font-semibold text-gray-900 text-sm dark:text-white">Prints by hour</h2><span class="text-gray-400 text-xs dark:text-neutral-500">Local time</span></div>
70
+ <div class="flex items-start justify-between"><h2 class="font-semibold text-gray-900 text-sm dark:text-white">Prints by hour</h2><span class="text-gray-500 text-xs dark:text-neutral-500">Local time</span></div>
71
71
  <div class="mt-4 space-y-3">
72
72
  <template :for="item in hourlyRows()" :key="item.key">
73
73
  <div class="grid gap-3 grid-cols-[4rem_1fr_auto] items-center"><span class="text-gray-500 text-xs dark:text-neutral-400">{{ item.key }}</span><div class="h-1.5 bg-gray-100 dark:bg-neutral-700 rounded-full"><div :style="'width:' + item.percentage + '%'" class="h-1.5 bg-violet-500 rounded-full"></div></div><span class="text-gray-500 text-xs dark:text-neutral-400">{{ item.count }}</span></div>
@@ -39,7 +39,7 @@ function details(): Array<{ label: string, value: string }> {
39
39
  <template #header-trailing>
40
40
  <span class="px-2 py-1 capitalize font-medium text-gray-700 text-xs dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 rounded-full">{{ record()?.status }}</span>
41
41
  </template>
42
- <dl class="grid gap-x-6 gap-y-4 sm:grid-cols-2"><template :for="item in details()" :key="item.label"><div><dt class="text-gray-400 text-xs dark:text-neutral-500">{{ item.label }}</dt><dd class="mt-1 break-all text-gray-800 text-sm dark:text-neutral-100">{{ item.value }}</dd></div></template></dl>
43
- <div :if="record()?.metadata && record()?.metadata !== '{}'" class="mt-5"><p class="text-gray-400 text-xs dark:text-neutral-500">Metadata</p><pre class="overflow-x-auto mt-1 p-3 text-gray-700 text-xs whitespace-pre-wrap dark:text-neutral-200 bg-gray-50 dark:bg-neutral-900/60 rounded-lg">{{ record()?.metadata }}</pre></div>
42
+ <dl class="grid gap-x-6 gap-y-4 sm:grid-cols-2"><template :for="item in details()" :key="item.label"><div><dt class="text-gray-500 text-xs dark:text-neutral-500">{{ item.label }}</dt><dd class="mt-1 break-all text-gray-800 text-sm dark:text-neutral-100">{{ item.value }}</dd></div></template></dl>
43
+ <div :if="record()?.metadata && record()?.metadata !== '{}'" class="mt-5"><p class="text-gray-500 text-xs dark:text-neutral-500">Metadata</p><pre class="overflow-x-auto mt-1 p-3 text-gray-700 text-xs whitespace-pre-wrap dark:text-neutral-200 bg-gray-50 dark:bg-neutral-900/60 rounded-lg">{{ record()?.metadata }}</pre></div>
44
44
  <template #footer><Button variant="secondary" @click="emit('close')">Close</Button></template>
45
45
  </Modal>
@@ -31,10 +31,10 @@ function statusClass(status: string): string {
31
31
  <tbody class="divide-gray-200 divide-y dark:divide-neutral-700">
32
32
  <template :for="record in records()" :key="record.id">
33
33
  <tr>
34
- <td class="px-4 py-4"><p class="font-medium text-gray-900 text-sm dark:text-white">{{ record.document || 'Untitled print job' }}</p><p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">Log #{{ record.id }}</p></td>
35
- <td class="px-4 py-4"><p class="text-gray-700 text-sm dark:text-neutral-200">{{ record.printer || 'Unknown printer' }}</p><p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ record.printDeviceId ? 'Device #' + record.printDeviceId : 'No linked device' }}</p></td>
34
+ <td class="px-4 py-4"><p class="font-medium text-gray-900 text-sm dark:text-white">{{ record.document || 'Untitled print job' }}</p><p class="mt-1 text-gray-500 text-xs dark:text-neutral-500">Log #{{ record.id }}</p></td>
35
+ <td class="px-4 py-4"><p class="text-gray-700 text-sm dark:text-neutral-200">{{ record.printer || 'Unknown printer' }}</p><p class="mt-1 text-gray-500 text-xs dark:text-neutral-500">{{ record.printDeviceId ? 'Device #' + record.printDeviceId : 'No linked device' }}</p></td>
36
36
  <td class="px-4 py-4"><span :class="'inline-flex px-2 py-1 font-medium text-xs capitalize rounded-full ' + statusClass(record.status)">{{ record.status || 'unknown' }}</span></td>
37
- <td class="px-4 py-4"><p class="text-gray-700 text-sm dark:text-neutral-200">{{ record.pages }} pages</p><p class="mt-1 text-gray-400 text-xs dark:text-neutral-500">{{ record.sizeKb }} KB · {{ record.durationSeconds }}s</p></td>
37
+ <td class="px-4 py-4"><p class="text-gray-700 text-sm dark:text-neutral-200">{{ record.pages }} pages</p><p class="mt-1 text-gray-500 text-xs dark:text-neutral-500">{{ record.sizeKb }} KB · {{ record.durationSeconds }}s</p></td>
38
38
  <td class="px-4 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-400">{{ date(record.timestamp) }}</td>
39
39
  <td class="px-4 py-4"><div class="flex gap-1 justify-end"><Button variant="ghost" size="sm" iconOnly :ariaLabel="'View print log ' + record.id" @click="emit('view', record)"><span class="block h-4 w-4 text-blue-500 i-hugeicons-view"></span></Button><Button variant="ghost" size="sm" iconOnly :ariaLabel="'Delete print log ' + record.id" @click="emit('delete', record)"><span class="block h-4 w-4 text-red-500 i-hugeicons-waste"></span></Button></div></td>
40
40
  </tr>
@@ -183,7 +183,7 @@ onMount(() => {
183
183
  <div class="divide-gray-200 divide-y dark:divide-neutral-700">
184
184
  <div :if="loading()" class="px-4 py-14 text-center text-gray-500 text-sm dark:text-neutral-400"><span class="inline-block mr-2 h-4 w-4 animate-spin i-hugeicons-loading-03"></span>Loading comments</div>
185
185
  <div :else-if="visibleComments().length === 0" class="px-4 py-14 text-center"><span class="inline-block h-6 w-6 text-gray-400 i-hugeicons-comment-01"></span><p class="mt-2 font-medium text-gray-900 text-sm dark:text-white">No comments found</p><p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Adjust the search or status filter.</p></div>
186
- <template :else><template :for="comment in visibleComments()"><article class="p-4"><div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between"><div class="min-w-0"><div class="flex flex-wrap gap-2 items-center"><p class="font-semibold text-gray-900 text-sm dark:text-white">{{ comment.authorName || 'Anonymous' }}</p><span :class="statusClass(comment.status)">{{ comment.status }}</span><span class="text-gray-400 text-xs">{{ formatDate(comment.createdAt) }}</span></div><p class="mt-1 text-gray-500 text-xs dark:text-neutral-400">{{ comment.authorEmail }}<span :if="comment.postTitle"> on {{ comment.postTitle }}</span></p><p class="mt-3 max-w-4xl text-gray-700 text-sm whitespace-pre-wrap dark:text-neutral-200">{{ comment.content }}</p></div><div class="flex flex-shrink-0 flex-wrap gap-2"><Button :if="comment.status !== 'approved'" variant="success" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'approved')">Approve</Button><Button :if="comment.status !== 'pending'" variant="secondary" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'pending')">Restore</Button><Button :if="comment.status !== 'spam'" variant="warning" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'spam')">Spam</Button><Button :if="comment.status !== 'trash' && comment.source === 'comments'" variant="outline" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'trash')">Trash</Button><Button variant="ghost" size="sm" iconOnly :ariaLabel="'Permanently delete comment by ' + comment.authorName" :disabled="Boolean(updatingId())" @click="openDelete(comment)"><span class="block h-4 w-4 text-red-500 i-hugeicons-delete-02"></span></Button></div></div></article></template></template>
186
+ <template :else><template :for="comment in visibleComments()"><article class="p-4"><div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between"><div class="min-w-0"><div class="flex flex-wrap gap-2 items-center"><p class="font-semibold text-gray-900 text-sm dark:text-white">{{ comment.authorName || 'Anonymous' }}</p><span :class="statusClass(comment.status)">{{ comment.status }}</span><span class="text-gray-500 text-xs dark:text-gray-400">{{ formatDate(comment.createdAt) }}</span></div><p class="mt-1 text-gray-500 text-xs dark:text-neutral-400">{{ comment.authorEmail }}<span :if="comment.postTitle"> on {{ comment.postTitle }}</span></p><p class="mt-3 max-w-4xl text-gray-700 text-sm whitespace-pre-wrap dark:text-neutral-200">{{ comment.content }}</p></div><div class="flex flex-shrink-0 flex-wrap gap-2"><Button :if="comment.status !== 'approved'" variant="success" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'approved')">Approve</Button><Button :if="comment.status !== 'pending'" variant="secondary" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'pending')">Restore</Button><Button :if="comment.status !== 'spam'" variant="warning" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'spam')">Spam</Button><Button :if="comment.status !== 'trash' && comment.source === 'comments'" variant="outline" size="sm" :disabled="Boolean(updatingId())" @click="setStatus(comment, 'trash')">Trash</Button><Button variant="ghost" size="sm" iconOnly :ariaLabel="'Permanently delete comment by ' + comment.authorName" :disabled="Boolean(updatingId())" @click="openDelete(comment)"><span class="block h-4 w-4 text-red-500 i-hugeicons-delete-02"></span></Button></div></div></article></template></template>
187
187
  </div>
188
188
  </section>
189
189
  </div>
@@ -50,7 +50,7 @@ function navRowClass(active: boolean): string {
50
50
  <div class="flex flex-col h-full">
51
51
  <div class="p-4 border-b border-black/[0.06] dark:border-white/[0.08]">
52
52
  <label class="block">
53
- <span class="font-semibold text-[11px] text-stone-400 tracking-wider uppercase dark:text-neutral-500">Storage disk</span>
53
+ <span class="font-semibold text-[11px] text-stone-500 tracking-wider uppercase dark:text-neutral-500">Storage disk</span>
54
54
  <select x-model="disk" :disabled="busy()" class="mt-2 px-2.5 py-2 w-full text-sm text-stone-800 dark:text-white bg-white/80 dark:bg-neutral-800 border border-stone-200 rounded-lg dark:border-neutral-700 disabled:opacity-60" @change="emit('disk', $event.target.value)">
55
55
  <template :for="option in disks"><option :value="option.name">{{ option.name }}{{ option.public ? ' (public)' : '' }}</option></template>
56
56
  </select>
@@ -59,7 +59,7 @@ function navRowClass(active: boolean): string {
59
59
 
60
60
  <div class="p-4 border-b border-black/[0.06] dark:border-white/[0.08]">
61
61
  <div class="flex items-center justify-between">
62
- <p class="font-semibold text-[11px] text-stone-400 tracking-wider uppercase dark:text-neutral-500">Stored content</p>
62
+ <p class="font-semibold text-[11px] text-stone-500 tracking-wider uppercase dark:text-neutral-500">Stored content</p>
63
63
  <span class="font-mono text-[11px] text-stone-500 dark:text-neutral-400">{{ summary().contentSize }}</span>
64
64
  </div>
65
65
  <div class="grid gap-2 grid-cols-2 mt-3">
@@ -69,11 +69,11 @@ function navRowClass(active: boolean): string {
69
69
  </div>
70
70
 
71
71
  <div class="p-4 border-b border-black/[0.06] dark:border-white/[0.08]">
72
- <p class="font-semibold text-[11px] text-stone-400 tracking-wider uppercase dark:text-neutral-500">Content by type</p>
72
+ <p class="font-semibold text-[11px] text-stone-500 tracking-wider uppercase dark:text-neutral-500">Content by type</p>
73
73
  <div class="mt-3 space-y-3">
74
74
  <template :for="row in typeRows">
75
75
  <div>
76
- <div class="flex items-center justify-between text-[11px]"><span class="text-stone-600 dark:text-neutral-300">{{ row.label }}</span><span class="font-mono text-stone-400 dark:text-neutral-500">{{ row.size }}</span></div>
76
+ <div class="flex items-center justify-between text-[11px]"><span class="text-stone-600 dark:text-neutral-300">{{ row.label }}</span><span class="font-mono text-stone-500 dark:text-neutral-500">{{ row.size }}</span></div>
77
77
  <div class="overflow-hidden mt-1 h-1.5 bg-black/[0.06] dark:bg-white/[0.08] rounded-full"><div :class="'h-full rounded-full ' + row.color" :style="row.barStyle"></div></div>
78
78
  </div>
79
79
  </template>
@@ -81,7 +81,7 @@ function navRowClass(active: boolean): string {
81
81
  </div>
82
82
 
83
83
  <div :if="summary().capacityKnown" class="p-4 border-b border-black/[0.06] dark:border-white/[0.08]">
84
- <div class="flex items-center justify-between"><p class="font-semibold text-[11px] text-stone-400 tracking-wider uppercase dark:text-neutral-500">Volume capacity</p><span class="font-mono text-[11px] text-stone-500 dark:text-neutral-400">{{ summary().capacityPercent.toFixed(0) }}%</span></div>
84
+ <div class="flex items-center justify-between"><p class="font-semibold text-[11px] text-stone-500 tracking-wider uppercase dark:text-neutral-500">Volume capacity</p><span class="font-mono text-[11px] text-stone-500 dark:text-neutral-400">{{ summary().capacityPercent.toFixed(0) }}%</span></div>
85
85
  <div class="overflow-hidden mt-2 h-1.5 bg-black/[0.06] dark:bg-white/[0.08] rounded-full"><div class="h-full bg-blue-500 rounded-full" :style="'width: ' + summary().capacityPercent.toFixed(2) + '%'"></div></div>
86
86
  <p class="mt-2 text-[11px] text-stone-500 dark:text-neutral-400">{{ summary().available }} available of {{ summary().total }}</p>
87
87
  </div>
@@ -89,7 +89,7 @@ function navRowClass(active: boolean): string {
89
89
  <nav aria-label="Storage folders" class="overflow-y-auto flex-1 p-2">
90
90
  <button type="button" :class="navRowClass(currentPath() === '')" @click="emit('navigate', '')"><span class="h-[18px] w-[18px] text-blue-500 i-hugeicons-home-02"></span>Home</button>
91
91
  <template :for="folder in folders">
92
- <button type="button" :class="navRowClass(currentPath() === folder.path)" @click="emit('navigate', folder.path)"><span class="h-[18px] w-[18px] text-amber-500 i-hugeicons-folder-02"></span><span class="truncate">{{ folder.name }}</span><span class="ml-auto tabular-nums text-[11px] text-stone-400 dark:text-neutral-500">{{ folder.count }}</span></button>
92
+ <button type="button" :class="navRowClass(currentPath() === folder.path)" @click="emit('navigate', folder.path)"><span class="h-[18px] w-[18px] text-amber-500 i-hugeicons-folder-02"></span><span class="truncate">{{ folder.name }}</span><span class="ml-auto tabular-nums text-[11px] text-stone-500 dark:text-neutral-500">{{ folder.count }}</span></button>
93
93
  </template>
94
94
  </nav>
95
95
 
@@ -73,7 +73,7 @@ function submit(): void {
73
73
  </label>
74
74
  <ul :if="files().length" class="overflow-y-auto mt-4 space-y-1 max-h-32 text-sm">
75
75
  <template :for="file in files">
76
- <li class="flex gap-4 items-center justify-between px-3 py-2 bg-stone-50 dark:bg-neutral-900 rounded-lg"><span class="text-stone-700 truncate dark:text-neutral-200">{{ file.name }}</span><span class="flex-shrink-0 font-mono text-stone-400 text-xs dark:text-neutral-500">{{ formatFileSize(file.size) }}</span></li>
76
+ <li class="flex gap-4 items-center justify-between px-3 py-2 bg-stone-50 dark:bg-neutral-900 rounded-lg"><span class="text-stone-700 truncate dark:text-neutral-200">{{ file.name }}</span><span class="flex-shrink-0 font-mono text-stone-500 text-xs dark:text-neutral-500">{{ formatFileSize(file.size) }}</span></li>
77
77
  </template>
78
78
  </ul>
79
79
  </form>
@@ -136,12 +136,12 @@ function submit(): void {
136
136
  <label>
137
137
  <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Excerpt</span>
138
138
  <textarea x-model="excerpt" name="excerpt" rows="3" maxlength="500" placeholder="Optional, at least 10 characters when provided" class="mt-1 px-3 py-2 w-full text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700"></textarea>
139
- <span class="block mt-1 text-gray-400 text-xs">{{ excerpt().length }}/500</span>
139
+ <span class="block mt-1 text-gray-500 text-xs dark:text-gray-400">{{ excerpt().length }}/500</span>
140
140
  </label>
141
141
  <label>
142
142
  <span class="font-medium text-gray-700 text-sm dark:text-neutral-200">Content</span>
143
143
  <textarea x-model="content" name="content" required minlength="10" maxlength="100000" rows="10" class="mt-1 px-3 py-2 w-full font-mono text-gray-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-gray-300 rounded-md dark:border-neutral-700"></textarea>
144
- <span class="block mt-1 text-gray-400 text-xs">{{ content().length }}/100000</span>
144
+ <span class="block mt-1 text-gray-500 text-xs dark:text-gray-400">{{ content().length }}/100000</span>
145
145
  </label>
146
146
  <div class="grid gap-4 lg:grid-cols-2">
147
147
  <fieldset class="p-4 border border-gray-200 rounded-lg dark:border-neutral-700">
@@ -293,7 +293,7 @@ onMount(() => { void loadPosts() })
293
293
  <span :if="row.featured" x-tooltip="Featured" title="Featured" class="flex-shrink-0 h-4 w-4 text-amber-500 i-hugeicons-star"></span>
294
294
  </div>
295
295
  <p class="mt-1 text-gray-500 text-xs truncate dark:text-neutral-400" x-text="row.summaryLabel"></p>
296
- <p class="mt-1 text-gray-400 text-xs dark:text-neutral-500" x-text="row.authorLabel"></p>
296
+ <p class="mt-1 text-gray-500 text-xs dark:text-neutral-500" x-text="row.authorLabel"></p>
297
297
  </template>
298
298
  <template :else>
299
299
  <p class="text-gray-500 text-xs truncate dark:text-neutral-400"><span class="font-medium text-gray-700 dark:text-neutral-200">Categories:</span> <span x-text="row.categoriesLabel"></span></p>
@@ -70,7 +70,7 @@ function submit(): void {
70
70
  <div>
71
71
  <div class="flex items-center justify-between">
72
72
  <label for="seo-meta-description" class="block font-medium text-neutral-700 text-sm dark:text-neutral-300">Meta description</label>
73
- <span class="tabular-nums text-neutral-400 text-xs">{{ metaDescription().length }}/160</span>
73
+ <span class="tabular-nums text-neutral-500 text-xs dark:text-neutral-400">{{ metaDescription().length }}/160</span>
74
74
  </div>
75
75
  <textarea
76
76
  id="seo-meta-description"
@@ -81,7 +81,7 @@ function icon(operation: DeploymentPreviewOperation): string {
81
81
  </div>
82
82
  <div class="flex-1 min-w-0">
83
83
  <div class="flex gap-2 items-center">
84
- <span class="font-mono text-neutral-400 text-xs">{{ index + 1 }}</span>
84
+ <span class="font-mono text-neutral-500 text-xs dark:text-neutral-400">{{ index + 1 }}</span>
85
85
  <h5 class="font-semibold text-neutral-900 text-sm dark:text-white">{{ operation.label }}</h5>
86
86
  </div>
87
87
  <p class="mt-1 text-neutral-600 text-sm dark:text-neutral-300">{{ operation.detail }}</p>
@@ -221,7 +221,7 @@ function another() {
221
221
  </label>
222
222
 
223
223
  <label class="block mb-4">
224
- <span class="block mb-1.5 font-medium text-neutral-700 text-sm dark:text-neutral-200">Details <span class="font-normal text-neutral-400">(optional)</span></span>
224
+ <span class="block mb-1.5 font-medium text-neutral-700 text-sm dark:text-neutral-200">Details <span class="font-normal text-neutral-500 dark:text-neutral-400">(optional)</span></span>
225
225
  <textarea
226
226
  x-model="description"
227
227
  rows="6"
@@ -233,7 +233,7 @@ function another() {
233
233
  </label>
234
234
 
235
235
  <div class="mb-5">
236
- <span class="block mb-1.5 font-medium text-neutral-700 text-sm dark:text-neutral-200">Screenshot <span class="font-normal text-neutral-400">(optional)</span></span>
236
+ <span class="block mb-1.5 font-medium text-neutral-700 text-sm dark:text-neutral-200">Screenshot <span class="font-normal text-neutral-500 dark:text-neutral-400">(optional)</span></span>
237
237
 
238
238
  <div :if="screenshot()" class="flex gap-3 items-center p-3 bg-neutral-50 dark:bg-neutral-800/50 border border-neutral-200 rounded-lg dark:border-neutral-700">
239
239
  <img :src="preview()" alt="The screenshot you chose" class="object-cover h-14 w-14 bg-white dark:bg-neutral-900 border border-neutral-200 rounded dark:border-neutral-700" />
@@ -246,7 +246,7 @@ function another() {
246
246
  <label :else class="flex flex-col items-center justify-center px-4 py-6 text-center border border-dashed border-neutral-300 rounded-lg dark:border-neutral-600 hover:border-blue-400 dark:hover:border-blue-600 transition-colors cursor-pointer" @dragover.prevent @drop.prevent="drop($event)">
247
247
  <span class="h-6 w-6 text-neutral-400 i-hugeicons-image-upload"></span>
248
248
  <span class="mt-2 font-medium text-neutral-700 text-sm dark:text-neutral-200">Choose an image, drop it here, or paste it</span>
249
- <span class="mt-1 text-neutral-400 text-xs">PNG, JPEG, WebP or GIF, up to {{ megabytes(sizeLimit()) }}</span>
249
+ <span class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">PNG, JPEG, WebP or GIF, up to {{ megabytes(sizeLimit()) }}</span>
250
250
  <input
251
251
  ref="feedbackScreenshotInput"
252
252
  type="file"
@@ -269,7 +269,7 @@ function another() {
269
269
  </button>
270
270
  </form>
271
271
 
272
- <p class="mt-4 text-center text-neutral-400 text-xs dark:text-neutral-500">
272
+ <p class="mt-4 text-center text-neutral-500 text-xs dark:text-neutral-500">
273
273
  This link lets you send feedback. It does not sign you in, and it cannot read anything back.
274
274
  </p>
275
275
  </div>
@@ -97,6 +97,6 @@ const badgeClass = derived(() => kind() === 'video'
97
97
  </div>
98
98
  <div class="px-3 py-2.5">
99
99
  <p :title="currentItem().name" class="font-medium text-[13px] text-stone-800 truncate dark:text-white">{{ currentItem().name }}</p>
100
- <p class="mt-0.5 capitalize text-[11px] text-stone-400 dark:text-neutral-500">{{ currentItem().type === 'folder' ? 'Folder' : kind() }}</p>
100
+ <p class="mt-0.5 capitalize text-[11px] text-stone-500 dark:text-neutral-500">{{ currentItem().type === 'folder' ? 'Folder' : kind() }}</p>
101
101
  </div>
102
102
  </div>
@@ -90,10 +90,10 @@ const kindLabel = derived(() => currentItem().type === 'folder' ? 'Folder' : `${
90
90
  </div>
91
91
  <h4 class="mt-4 break-words font-semibold text-[15px] text-stone-800 dark:text-white">{{ currentItem().name }}</h4>
92
92
  <dl class="mt-4 space-y-3 text-[13px]">
93
- <div class="flex gap-4 items-start justify-between"><dt class="text-stone-400 dark:text-neutral-500">Type</dt><dd class="capitalize font-medium text-right text-stone-700 dark:text-neutral-200">{{ kindLabel() }}</dd></div>
94
- <div class="flex gap-4 items-start justify-between"><dt class="text-stone-400 dark:text-neutral-500">Size</dt><dd class="font-medium text-right text-stone-700 dark:text-neutral-200">{{ sizeLabel() }}</dd></div>
95
- <div class="flex gap-4 items-start justify-between"><dt class="text-stone-400 dark:text-neutral-500">Location</dt><dd class="break-all font-medium text-right text-stone-700 dark:text-neutral-200">{{ locationLabel() }}</dd></div>
96
- <div class="flex gap-4 items-start justify-between"><dt class="text-stone-400 dark:text-neutral-500">Modified</dt><dd class="font-medium text-right text-stone-700 dark:text-neutral-200">{{ formatWhen(currentItem().lastModified) }}</dd></div>
93
+ <div class="flex gap-4 items-start justify-between"><dt class="text-stone-500 dark:text-neutral-500">Type</dt><dd class="capitalize font-medium text-right text-stone-700 dark:text-neutral-200">{{ kindLabel() }}</dd></div>
94
+ <div class="flex gap-4 items-start justify-between"><dt class="text-stone-500 dark:text-neutral-500">Size</dt><dd class="font-medium text-right text-stone-700 dark:text-neutral-200">{{ sizeLabel() }}</dd></div>
95
+ <div class="flex gap-4 items-start justify-between"><dt class="text-stone-500 dark:text-neutral-500">Location</dt><dd class="break-all font-medium text-right text-stone-700 dark:text-neutral-200">{{ locationLabel() }}</dd></div>
96
+ <div class="flex gap-4 items-start justify-between"><dt class="text-stone-500 dark:text-neutral-500">Modified</dt><dd class="font-medium text-right text-stone-700 dark:text-neutral-200">{{ formatWhen(currentItem().lastModified) }}</dd></div>
97
97
  </dl>
98
98
  <span :if="currentItem().shared" class="inline-flex gap-1 items-center self-start mt-5 px-2 py-1 font-medium text-[11px] text-indigo-700 dark:text-indigo-300 bg-indigo-100 dark:bg-indigo-500/15 rounded-full"><span class="h-3 w-3 i-hugeicons-share-01"></span>Public disk</span>
99
99
  </div>
@@ -152,7 +152,7 @@ onDestroy(() => {
152
152
  @input="scheduleSearch($event.target.value)"
153
153
  />
154
154
  <span :if="isSearching()" class="shrink-0 h-5 w-5 text-blue-500 animate-spin i-hugeicons-loading-03"></span>
155
- <kbd :if="!isSearching()" class="shrink-0 px-1.5 py-0.5 font-medium text-[10px] text-neutral-400 bg-neutral-100 dark:bg-neutral-700 border border-neutral-200 rounded dark:border-neutral-600">
155
+ <kbd :if="!isSearching()" class="shrink-0 px-1.5 py-0.5 font-medium text-[10px] text-neutral-500 dark:text-neutral-400 bg-neutral-100 dark:bg-neutral-700 border border-neutral-200 rounded dark:border-neutral-600">
156
156
  ESC
157
157
  </kbd>
158
158
  </div>
@@ -170,7 +170,7 @@ onDestroy(() => {
170
170
  <template :if="!error() && Object.keys(results()).length > 0">
171
171
  <template :for="group in resultGroups()">
172
172
  <div class="pb-1 pt-3 px-3">
173
- <h3 class="px-1 font-semibold text-neutral-400 text-xs tracking-wider uppercase">
173
+ <h3 class="px-1 font-semibold text-neutral-500 text-xs tracking-wider uppercase dark:text-neutral-400">
174
174
  {{ group.type }}
175
175
  </h3>
176
176
  </div>
@@ -203,11 +203,11 @@ onDestroy(() => {
203
203
  </div>
204
204
 
205
205
  <div :if="!error() && !query().trim() && !isSearching()" class="px-4 py-8 text-center">
206
- <p class="text-neutral-400 text-sm">Search fields declared by each model's useSearch trait.</p>
206
+ <p class="text-neutral-500 text-sm dark:text-neutral-400">Search fields declared by each model's useSearch trait.</p>
207
207
  </div>
208
208
  </div>
209
209
 
210
- <div class="flex gap-4 items-center px-4 py-2.5 text-neutral-400 text-xs border-neutral-200 border-t dark:border-neutral-700">
210
+ <div class="flex gap-4 items-center px-4 py-2.5 text-neutral-500 text-xs dark:text-neutral-400 border-neutral-200 border-t dark:border-neutral-700">
211
211
  <span class="flex gap-1 items-center">
212
212
  <kbd class="px-1 py-0.5 text-[10px] bg-neutral-100 dark:bg-neutral-700 border border-neutral-200 rounded dark:border-neutral-600">↑↓</kbd>
213
213
  Navigate
@@ -243,7 +243,7 @@ onMount(() => {
243
243
  </div>
244
244
  </section>
245
245
 
246
- <footer :if="snapshot()?.generatedAt" class="text-neutral-400 text-right text-xs dark:text-neutral-500">Snapshot {{ formatDate(snapshot()?.generatedAt || null) }}</footer>
246
+ <footer :if="snapshot()?.generatedAt" class="text-neutral-500 text-right text-xs dark:text-neutral-500">Snapshot {{ formatDate(snapshot()?.generatedAt || null) }}</footer>
247
247
 
248
248
  <CloudDetailsDialog :open="Boolean(selectedResource())" :item="selectedResource()" @close="closeResource" />
249
249
  </div>
@@ -254,7 +254,7 @@ onMount(() => {
254
254
  <section class="overflow-hidden bg-white dark:bg-neutral-900 border border-neutral-200 rounded-xl dark:border-neutral-700">
255
255
  <header class="flex items-center justify-between px-5 py-4 border-b border-neutral-200 dark:border-neutral-700">
256
256
  <div><h2 class="font-semibold text-neutral-900 dark:text-white">Nameservers</h2><p class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">Configured delegation targets.</p></div>
257
- <span class="font-mono text-neutral-400 text-xs">{{ nameservers().length }}</span>
257
+ <span class="font-mono text-neutral-500 text-xs dark:text-neutral-400">{{ nameservers().length }}</span>
258
258
  </header>
259
259
  <div :if="nameservers().length > 0" class="grid gap-3 sm:grid-cols-2 p-5">
260
260
  <div :for="nameserver in nameservers()" class="flex gap-3 items-center p-3 bg-neutral-50 dark:bg-neutral-800 rounded-lg">
@@ -263,7 +263,7 @@ onMount(() => {
263
263
  </div>
264
264
  </div>
265
265
  <p :if="nameservers().length === 0" class="p-5 text-neutral-500 text-sm dark:text-neutral-400">No nameservers configured.</p>
266
- <p :if="generatedAt()" class="px-5 py-3 text-neutral-400 text-xs dark:text-neutral-500 bg-neutral-50 dark:bg-neutral-800/50 border-neutral-100 border-t dark:border-neutral-800">Snapshot {{ formatDate(generatedAt()) }}</p>
266
+ <p :if="generatedAt()" class="px-5 py-3 text-neutral-500 text-xs dark:text-neutral-500 bg-neutral-50 dark:bg-neutral-800/50 border-neutral-100 border-t dark:border-neutral-800">Snapshot {{ formatDate(generatedAt()) }}</p>
267
267
  </section>
268
268
 
269
269
  <DnsRecordDialog :open="Boolean(selectedRecord())" :record="selectedRecord()" @close="closeRecord" />
@@ -266,7 +266,7 @@ onDestroy(() => {
266
266
  <div class="p-5 bg-white dark:bg-neutral-900 border border-neutral-200 rounded-xl dark:border-neutral-700">
267
267
  <div class="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
268
268
  <div><h2 class="font-semibold text-neutral-900 dark:text-white">Query logs</h2><p class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">Search message, project, file, and stack trace.</p></div>
269
- <p :if="generatedAt()" class="text-neutral-400 text-xs dark:text-neutral-500">Snapshot {{ formatDate(generatedAt()) }}</p>
269
+ <p :if="generatedAt()" class="text-neutral-500 text-xs dark:text-neutral-500">Snapshot {{ formatDate(generatedAt()) }}</p>
270
270
  </div>
271
271
  <div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3 mt-5">
272
272
  <label class="block relative sm:col-span-2 xl:col-span-1">
@@ -296,7 +296,7 @@ onDestroy(() => {
296
296
  <td class="px-5 py-4 text-neutral-500 whitespace-nowrap dark:text-neutral-400">{{ formatDate(record.timestamp) }}</td>
297
297
  <td class="px-5 py-4"><LogLevelBadge :type="record.type" /></td>
298
298
  <td class="px-5 py-4 font-mono text-neutral-700 text-xs dark:text-neutral-300">{{ record.source || 'Not recorded' }}</td>
299
- <td class="px-5 py-4 max-w-md"><p class="font-medium text-neutral-900 dark:text-white">{{ record.message }}</p><p :if="record.file" class="mt-1 font-mono text-neutral-400 text-xs truncate dark:text-neutral-500">{{ record.file }}</p></td>
299
+ <td class="px-5 py-4 max-w-md"><p class="font-medium text-neutral-900 dark:text-white">{{ record.message }}</p><p :if="record.file" class="mt-1 font-mono text-neutral-500 text-xs truncate dark:text-neutral-500">{{ record.file }}</p></td>
300
300
  <td class="px-5 py-4 text-neutral-600 whitespace-nowrap dark:text-neutral-300">{{ record.project || 'Not recorded' }}</td>
301
301
  <td class="px-5 py-4 text-right"><Button variant="ghost" iconOnly :ariaLabel="'Inspect log ' + record.id" @click="openLog(record)"><span class="block h-5 w-5 i-hugeicons-view"></span></Button></td>
302
302
  </tr>
@@ -217,7 +217,7 @@ onMount(() => {
217
217
 
218
218
  <section class="grid gap-4 grid-cols-1 xl:grid-cols-2">
219
219
  <div class="overflow-hidden bg-white dark:bg-neutral-900 border border-neutral-200 rounded-xl dark:border-neutral-700">
220
- <header class="flex items-center justify-between px-5 py-4 border-b border-neutral-200 dark:border-neutral-700"><div><h2 class="font-semibold text-neutral-900 dark:text-white">Forwarding</h2><p class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">Configured address copies.</p></div><span class="font-mono text-neutral-400 text-xs">{{ forwards().length }}</span></header>
220
+ <header class="flex items-center justify-between px-5 py-4 border-b border-neutral-200 dark:border-neutral-700"><div><h2 class="font-semibold text-neutral-900 dark:text-white">Forwarding</h2><p class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">Configured address copies.</p></div><span class="font-mono text-neutral-500 text-xs dark:text-neutral-400">{{ forwards().length }}</span></header>
221
221
  <div :if="forwards().length > 0" class="divide-neutral-100 divide-y dark:divide-neutral-800">
222
222
  <div :for="forward in forwards()" class="px-5 py-4">
223
223
  <p class="font-medium font-mono text-neutral-900 text-sm dark:text-white">{{ forward.source }}</p>
@@ -228,12 +228,12 @@ onMount(() => {
228
228
  </div>
229
229
 
230
230
  <div class="overflow-hidden bg-white dark:bg-neutral-900 border border-neutral-200 rounded-xl dark:border-neutral-700">
231
- <header class="flex items-center justify-between px-5 py-4 border-b border-neutral-200 dark:border-neutral-700"><div><h2 class="font-semibold text-neutral-900 dark:text-white">Retention</h2><p class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">Configured mail storage policy.</p></div><span class="font-mono text-neutral-400 text-xs">{{ server().storage.length }}</span></header>
231
+ <header class="flex items-center justify-between px-5 py-4 border-b border-neutral-200 dark:border-neutral-700"><div><h2 class="font-semibold text-neutral-900 dark:text-white">Retention</h2><p class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">Configured mail storage policy.</p></div><span class="font-mono text-neutral-500 text-xs dark:text-neutral-400">{{ server().storage.length }}</span></header>
232
232
  <dl :if="server().storage.length > 0" class="grid gap-4 sm:grid-cols-2 p-5 text-sm">
233
233
  <div :for="item in server().storage"><dt class="capitalize text-neutral-500 dark:text-neutral-400">{{ storageLabel(item) }}</dt><dd class="mt-1 font-medium text-neutral-900 dark:text-white">{{ item.value }}</dd></div>
234
234
  </dl>
235
235
  <p :if="server().storage.length === 0" class="p-5 text-neutral-500 text-sm dark:text-neutral-400">No storage policy configured.</p>
236
- <p :if="generatedAt()" class="px-5 py-3 text-neutral-400 text-xs dark:text-neutral-500 bg-neutral-50 dark:bg-neutral-800/50 border-neutral-100 border-t dark:border-neutral-800">Snapshot {{ formatDate(generatedAt()) }}</p>
236
+ <p :if="generatedAt()" class="px-5 py-3 text-neutral-500 text-xs dark:text-neutral-500 bg-neutral-50 dark:bg-neutral-800/50 border-neutral-100 border-t dark:border-neutral-800">Snapshot {{ formatDate(generatedAt()) }}</p>
237
237
  </div>
238
238
  </section>
239
239
 
@@ -240,7 +240,7 @@ onMount(() => {
240
240
  </div>
241
241
  </section>
242
242
 
243
- <footer :if="generatedAt()" class="text-neutral-400 text-right text-xs dark:text-neutral-500">Snapshot {{ formatDate(generatedAt()) }}</footer>
243
+ <footer :if="generatedAt()" class="text-neutral-500 text-right text-xs dark:text-neutral-500">Snapshot {{ formatDate(generatedAt()) }}</footer>
244
244
 
245
245
  <CloudDetailsDialog :open="Boolean(selectedResource())" :item="selectedResource()" @close="closeResource" />
246
246
  </div>
@@ -268,7 +268,7 @@ onMount(() => {
268
268
  <h2 class="font-semibold text-neutral-900 dark:text-white">Configured request path</h2>
269
269
  <p class="mt-1 text-neutral-500 text-xs dark:text-neutral-400">A structural view of declared routing, with no inferred health data.</p>
270
270
  </div>
271
- <p class="text-neutral-400 text-xs dark:text-neutral-500">Source: config/cloud.ts</p>
271
+ <p class="text-neutral-500 text-xs dark:text-neutral-500">Source: config/cloud.ts</p>
272
272
  </div>
273
273
  <div class="grid gap-3 grid-cols-1 md:grid-cols-[1fr_auto_1fr_auto_1fr] mt-5">
274
274
  <div class="flex gap-3 items-center p-4 bg-rose-50 dark:bg-rose-950/25 border border-rose-100 rounded-xl dark:border-rose-900/50">
@@ -312,7 +312,7 @@ onMount(() => {
312
312
  <div class="overflow-hidden bg-white dark:bg-neutral-900 border border-neutral-200 rounded-xl dark:border-neutral-700">
313
313
  <div class="flex items-center justify-between px-5 py-4 border-b border-neutral-200 dark:border-neutral-700">
314
314
  <div><h3 class="font-semibold text-neutral-900 text-sm dark:text-white">Definitions</h3><p class="mt-0.5 text-neutral-500 text-xs dark:text-neutral-400">Desired compute configuration</p></div>
315
- <span class="font-mono text-neutral-400 text-xs">{{ filteredServers().length }}</span>
315
+ <span class="font-mono text-neutral-500 text-xs dark:text-neutral-400">{{ filteredServers().length }}</span>
316
316
  </div>
317
317
  <div class="divide-neutral-100 divide-y dark:divide-neutral-800">
318
318
  <button :for="server in filteredServers()" type="button" class="flex gap-4 items-center px-5 py-4 w-full text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/70" @click="inspectServer(server)">
@@ -327,7 +327,7 @@ onMount(() => {
327
327
  <div class="overflow-hidden bg-white dark:bg-neutral-900 border border-neutral-200 rounded-xl dark:border-neutral-700">
328
328
  <div class="flex items-center justify-between px-5 py-4 border-b border-neutral-200 dark:border-neutral-700">
329
329
  <div><h3 class="font-semibold text-neutral-900 text-sm dark:text-white">Deployments</h3><p class="mt-0.5 text-neutral-500 text-xs dark:text-neutral-400">Persisted provider state</p></div>
330
- <span class="font-mono text-neutral-400 text-xs">{{ filteredDeployments().length }}</span>
330
+ <span class="font-mono text-neutral-500 text-xs dark:text-neutral-400">{{ filteredDeployments().length }}</span>
331
331
  </div>
332
332
  <div class="divide-neutral-100 divide-y dark:divide-neutral-800">
333
333
  <button :for="deployment in filteredDeployments()" type="button" class="flex gap-4 items-center px-5 py-4 w-full text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/70" @click="inspectDeployment(deployment)">
@@ -352,7 +352,7 @@ onMount(() => {
352
352
  <article :for="event in events()" class="flex gap-3 px-5 py-4">
353
353
  <span :class="'mt-0.5 h-5 w-5 shrink-0 ' + eventIcon(event)"></span>
354
354
  <div class="flex-1 min-w-0"><p class="font-medium text-neutral-900 text-sm dark:text-white">{{ event.service }}</p><p class="mt-1 text-neutral-500 text-sm dark:text-neutral-400">{{ event.message }}</p></div>
355
- <time class="shrink-0 text-neutral-400 text-xs dark:text-neutral-500">{{ formatDate(event.timestamp) }}</time>
355
+ <time class="shrink-0 text-neutral-500 text-xs dark:text-neutral-500">{{ formatDate(event.timestamp) }}</time>
356
356
  </article>
357
357
  </div>
358
358
  </div>
@@ -366,7 +366,7 @@ onMount(() => {
366
366
  </div>
367
367
  <p :if="environments().length === 0" class="text-neutral-500 text-sm dark:text-neutral-400">No environments configured.</p>
368
368
  </div>
369
- <p :if="generatedAt()" class="mt-5 pt-4 text-neutral-400 text-xs dark:text-neutral-500 border-neutral-100 border-t dark:border-neutral-800">Snapshot {{ formatDate(generatedAt()) }}</p>
369
+ <p :if="generatedAt()" class="mt-5 pt-4 text-neutral-500 text-xs dark:text-neutral-500 border-neutral-100 border-t dark:border-neutral-800">Snapshot {{ formatDate(generatedAt()) }}</p>
370
370
  </div>
371
371
  </section>
372
372
 
@@ -376,7 +376,7 @@
376
376
  <div>
377
377
  <h1 class="font-semibold text-2xl text-zinc-900 dark:text-zinc-100" :text="board.name"></h1>
378
378
  <p :if="board.description" class="mt-1 text-sm text-zinc-500" :text="board.description"></p>
379
- <p class="mt-2 text-xs text-zinc-400">
379
+ <p class="mt-2 text-xs text-zinc-500 dark:text-zinc-400">
380
380
  <span :text="columns.length + ' columns'"></span>
381
381
  <span> · </span>
382
382
  <span :text="totalCards() + ' cards'"></span>
@@ -200,7 +200,7 @@
200
200
  class="mt-1 line-clamp-2 text-xs text-zinc-500"
201
201
  :text="board.description"
202
202
  ></p>
203
- <p class="mt-3 text-xs text-zinc-400" :text="cardCountText(board.cardCount)"></p>
203
+ <p class="mt-3 text-xs text-zinc-500 dark:text-zinc-400" :text="cardCountText(board.cardCount)"></p>
204
204
  </div>
205
205
  </StxLink>
206
206
  <span class="absolute right-3 top-4 opacity-0 focus-within:opacity-100 group-hover:opacity-100 transition-opacity">
@@ -232,7 +232,7 @@
232
232
  </div>
233
233
 
234
234
  <div>
235
- <label for="kanban-board-description" class="block mb-1 font-medium text-xs text-zinc-700 dark:text-zinc-300">Description <span class="text-zinc-400">(optional)</span></label>
235
+ <label for="kanban-board-description" class="block mb-1 font-medium text-xs text-zinc-700 dark:text-zinc-300">Description <span class="text-zinc-500 dark:text-zinc-400">(optional)</span></label>
236
236
  <textarea
237
237
  id="kanban-board-description"
238
238
  x-model="draftDescription"