domma-cms 0.44.0 → 0.45.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 (254) hide show
  1. package/CLAUDE.md +53 -53
  2. package/README.md +27 -27
  3. package/admin/css/admin.css +1 -1
  4. package/admin/dist/domma/domma-tools.css +3 -3
  5. package/admin/dist/domma/domma-tools.min.js +3 -3
  6. package/admin/index.html +2 -2
  7. package/admin/js/app.js +1 -1
  8. package/admin/js/lib/card-builder.js +2 -2
  9. package/admin/js/lib/crud-tutorial.js +1 -1
  10. package/admin/js/lib/effect-defs.js +1 -1
  11. package/admin/js/lib/effects-builder.js +1 -1
  12. package/admin/js/lib/image-editor.js +1 -1
  13. package/admin/js/lib/markdown-toolbar.js +2 -2
  14. package/admin/js/lib/project-context.js +1 -1
  15. package/admin/js/lib/project-quick-create.js +1 -1
  16. package/admin/js/lib/scribe-composer.js +1 -1
  17. package/admin/js/lib/server-restart.js +1 -1
  18. package/admin/js/lib/shortcode-context-menu.js +2 -2
  19. package/admin/js/lib/simple-editor.js +1 -1
  20. package/admin/js/lib/themes.js +1 -1
  21. package/admin/js/lib/timeline-builder.js +1 -1
  22. package/admin/js/templates/action-editor.html +8 -8
  23. package/admin/js/templates/api-endpoint-editor.html +7 -7
  24. package/admin/js/templates/api-endpoints.html +1 -1
  25. package/admin/js/templates/api-reference.html +1 -1
  26. package/admin/js/templates/block-editor.html +6 -6
  27. package/admin/js/templates/collection-editor.html +1 -1
  28. package/admin/js/templates/component-editor.html +2 -2
  29. package/admin/js/templates/dashboard/cache.html +3 -3
  30. package/admin/js/templates/dashboard/journeys.html +3 -3
  31. package/admin/js/templates/dashboard/kpi-strip.html +3 -3
  32. package/admin/js/templates/dashboard/top-pages.html +1 -1
  33. package/admin/js/templates/dashboard/traffic-chart.html +1 -1
  34. package/admin/js/templates/docs/api-actions.html +1 -1
  35. package/admin/js/templates/docs/api-collections.html +4 -4
  36. package/admin/js/templates/docs/api-pages.html +2 -2
  37. package/admin/js/templates/docs/api-plugins.html +1 -1
  38. package/admin/js/templates/docs/api-settings.html +2 -2
  39. package/admin/js/templates/docs/api-users.html +1 -1
  40. package/admin/js/templates/docs/components-howto.html +4 -4
  41. package/admin/js/templates/docs/components-reference.html +21 -21
  42. package/admin/js/templates/docs/components-rules.html +14 -14
  43. package/admin/js/templates/docs/components-walkthrough.html +13 -13
  44. package/admin/js/templates/docs/tutorial-crud.html +49 -49
  45. package/admin/js/templates/docs/tutorial-forms.html +4 -4
  46. package/admin/js/templates/docs/tutorial-plugin.html +10 -10
  47. package/admin/js/templates/docs/usage-actions.html +6 -6
  48. package/admin/js/templates/docs/usage-cta-shortcode.html +9 -9
  49. package/admin/js/templates/docs/usage-dconfig.html +4 -4
  50. package/admin/js/templates/docs/usage-navigation.html +1 -1
  51. package/admin/js/templates/docs/usage-pages.html +1 -1
  52. package/admin/js/templates/docs/usage-shortcodes.html +24 -24
  53. package/admin/js/templates/docs/usage-users-roles.html +3 -3
  54. package/admin/js/templates/docs/usage-views.html +4 -4
  55. package/admin/js/templates/documentation.html +1 -1
  56. package/admin/js/templates/effects.html +752 -752
  57. package/admin/js/templates/form-editor.html +5 -5
  58. package/admin/js/templates/forms.html +17 -17
  59. package/admin/js/templates/login.html +5 -5
  60. package/admin/js/templates/menu-editor.html +10 -10
  61. package/admin/js/templates/my-profile.html +17 -17
  62. package/admin/js/templates/navigation.html +11 -11
  63. package/admin/js/templates/notifications.html +1 -1
  64. package/admin/js/templates/page-editor.html +4 -4
  65. package/admin/js/templates/pro-docs.html +14 -14
  66. package/admin/js/templates/role-editor.html +70 -70
  67. package/admin/js/templates/roles.html +10 -10
  68. package/admin/js/templates/settings.html +10 -10
  69. package/admin/js/templates/tutorials.html +3 -3
  70. package/admin/js/templates/view-editor.html +15 -15
  71. package/admin/js/views/action-editor.js +1 -1
  72. package/admin/js/views/actions-list.js +1 -1
  73. package/admin/js/views/api-endpoint-editor.js +2 -2
  74. package/admin/js/views/api-endpoints.js +2 -2
  75. package/admin/js/views/api-tokens.js +3 -3
  76. package/admin/js/views/blocks.js +2 -2
  77. package/admin/js/views/collection-editor.js +1 -1
  78. package/admin/js/views/collection-entries.js +1 -1
  79. package/admin/js/views/collections.js +1 -1
  80. package/admin/js/views/component-editor.js +1 -1
  81. package/admin/js/views/components.js +4 -4
  82. package/admin/js/views/dashboard/widgets/cache.js +1 -1
  83. package/admin/js/views/dashboard/widgets/journeys.js +1 -1
  84. package/admin/js/views/dashboard/widgets/kpi-strip.js +1 -1
  85. package/admin/js/views/form-editor.js +7 -7
  86. package/admin/js/views/form-submissions.js +1 -1
  87. package/admin/js/views/forms.js +1 -1
  88. package/admin/js/views/layouts.js +1 -1
  89. package/admin/js/views/login.js +2 -2
  90. package/admin/js/views/menu-editor.js +3 -3
  91. package/admin/js/views/menu-locations.js +1 -1
  92. package/admin/js/views/menus.js +3 -3
  93. package/admin/js/views/navigation.js +8 -8
  94. package/admin/js/views/page-editor.js +40 -40
  95. package/admin/js/views/pages.js +3 -3
  96. package/admin/js/views/plugin-code.js +2 -2
  97. package/admin/js/views/plugins.js +1 -1
  98. package/admin/js/views/project-settings.js +1 -1
  99. package/admin/js/views/projects.js +1 -1
  100. package/admin/js/views/roles.js +1 -1
  101. package/admin/js/views/user-editor.js +1 -1
  102. package/admin/js/views/users.js +3 -3
  103. package/admin/js/views/view-editor.js +1 -1
  104. package/admin/js/views/view-preview.js +1 -1
  105. package/admin/js/views/views-list.js +1 -1
  106. package/bin/cli.js +8 -8
  107. package/bin/lib/config-merge.js +44 -44
  108. package/bin/update.js +16 -16
  109. package/config/plugins.json +1 -1
  110. package/package.json +2 -2
  111. package/plugins/_template/admin/views/index.js +1 -1
  112. package/plugins/_template/config.js +1 -1
  113. package/plugins/_template/plugin.js +1 -1
  114. package/plugins/analytics/admin/templates/analytics.html +3 -3
  115. package/plugins/analytics/admin/views/analytics.js +1 -1
  116. package/plugins/analytics/config.js +1 -1
  117. package/plugins/analytics/plugin.js +4 -4
  118. package/plugins/analytics/plugin.json +1 -1
  119. package/plugins/analytics/public/inject-body.html +2 -2
  120. package/plugins/analytics/public/inject-head.html +1 -1
  121. package/plugins/blog/admin/templates/blog.html +4 -4
  122. package/plugins/blog/admin/views/blog.js +3 -3
  123. package/plugins/blog/admin/views/categories.js +2 -2
  124. package/plugins/blog/admin/views/comments.js +4 -4
  125. package/plugins/blog/admin/views/post-editor.js +1 -1
  126. package/plugins/blog/plugin.js +2 -2
  127. package/plugins/blog/plugin.json +4 -4
  128. package/plugins/contacts/admin/views/contacts.js +8 -8
  129. package/plugins/contacts/plugin.js +4 -4
  130. package/plugins/contacts/plugin.json +1 -1
  131. package/plugins/invoice/admin/templates/editor.html +6 -6
  132. package/plugins/invoice/admin/templates/index.html +4 -4
  133. package/plugins/invoice/admin/views/editor.js +3 -3
  134. package/plugins/invoice/admin/views/index.js +4 -4
  135. package/plugins/invoice/admin/views/issuers.js +1 -1
  136. package/plugins/invoice/admin/views/party-view.js +3 -3
  137. package/plugins/invoice/admin/views/receivers.js +1 -1
  138. package/plugins/invoice/config.js +1 -1
  139. package/plugins/invoice/plugin.js +1 -1
  140. package/plugins/invoice/plugin.json +4 -4
  141. package/plugins/notes/admin/views/notes.js +4 -4
  142. package/plugins/notes/plugin.js +1 -1
  143. package/plugins/notes/plugin.json +1 -1
  144. package/plugins/site-search/admin/templates/site-search.html +3 -3
  145. package/plugins/site-search/admin/views/site-search.js +1 -1
  146. package/plugins/site-search/config.js +1 -1
  147. package/plugins/site-search/plugin.js +4 -4
  148. package/plugins/site-search/plugin.json +1 -1
  149. package/plugins/surveys/admin/templates/results.html +1 -1
  150. package/plugins/surveys/admin/templates/survey-editor.html +4 -4
  151. package/plugins/surveys/admin/views/audience.js +6 -6
  152. package/plugins/surveys/admin/views/results.js +3 -3
  153. package/plugins/surveys/admin/views/survey-editor.js +1 -1
  154. package/plugins/surveys/admin/views/surveys.js +2 -2
  155. package/plugins/surveys/plugin.js +1 -1
  156. package/plugins/surveys/plugin.json +4 -4
  157. package/plugins/theme-switcher/admin/views/theme-switcher.js +1 -1
  158. package/plugins/theme-switcher/plugin.json +3 -3
  159. package/plugins/theme-switcher/public/inject-body.html +28 -28
  160. package/plugins/theme-switcher/public/inject-head.html +1 -1
  161. package/plugins/todo/plugin.js +1 -1
  162. package/public/css/forms.css +1 -1
  163. package/public/js/collection-browser.js +1 -1
  164. package/public/js/collection-context.js +1 -1
  165. package/public/js/form-logic-engine.js +1 -1
  166. package/public/js/forms.js +2 -1
  167. package/public/js/site.js +1 -1
  168. package/scripts/build.js +14 -14
  169. package/scripts/create-plugin.js +2 -2
  170. package/scripts/fresh.js +2 -2
  171. package/scripts/gen-instance-secret.js +1 -1
  172. package/scripts/pro.js +12 -12
  173. package/scripts/reset.js +2 -2
  174. package/scripts/setup.js +15 -15
  175. package/scripts/users.js +5 -5
  176. package/scripts/verify-assets.mjs +6 -6
  177. package/server/config.js +1 -1
  178. package/server/middleware/auth.js +253 -253
  179. package/server/middleware/managerAuth.js +3 -3
  180. package/server/routes/api/actions.js +4 -4
  181. package/server/routes/api/api-endpoints.js +7 -7
  182. package/server/routes/api/api-tokens.js +5 -5
  183. package/server/routes/api/auth.js +309 -309
  184. package/server/routes/api/blocks.js +3 -3
  185. package/server/routes/api/collections.js +18 -18
  186. package/server/routes/api/dashboard.js +5 -5
  187. package/server/routes/api/effects.js +2 -2
  188. package/server/routes/api/endpoints-public.js +5 -5
  189. package/server/routes/api/forms.js +47 -47
  190. package/server/routes/api/menu-locations.js +3 -3
  191. package/server/routes/api/menus.js +7 -7
  192. package/server/routes/api/navigation.js +42 -42
  193. package/server/routes/api/notifications.js +2 -2
  194. package/server/routes/api/pages.js +14 -2
  195. package/server/routes/api/plugin-marketplace.js +3 -3
  196. package/server/routes/api/plugins.js +6 -6
  197. package/server/routes/api/projects.js +9 -9
  198. package/server/routes/api/scaffold.js +7 -7
  199. package/server/routes/api/settings.js +6 -6
  200. package/server/routes/api/sidebar.js +1 -1
  201. package/server/routes/api/users.js +5 -5
  202. package/server/routes/api/versions.js +1 -1
  203. package/server/routes/api/views.js +1 -1
  204. package/server/routes/docs-public.js +3 -3
  205. package/server/routes/public.js +14 -14
  206. package/server/server.js +34 -16
  207. package/server/services/actions.js +19 -19
  208. package/server/services/adapters/FileAdapter.js +2 -2
  209. package/server/services/adapters/MongoAdapter.js +5 -5
  210. package/server/services/apiEndpoints.js +15 -15
  211. package/server/services/apiTokens.js +7 -7
  212. package/server/services/blocks.js +13 -13
  213. package/server/services/cache/drivers/MemoryDriver.js +3 -3
  214. package/server/services/cache/drivers/NoneDriver.js +1 -1
  215. package/server/services/cache/index.js +5 -5
  216. package/server/services/collections.js +14 -14
  217. package/server/services/components.js +9 -9
  218. package/server/services/connectionManager.js +4 -4
  219. package/server/services/content.js +25 -2
  220. package/server/services/docs.js +14 -14
  221. package/server/services/email.js +167 -167
  222. package/server/services/filterEngine.js +6 -6
  223. package/server/services/forms.js +18 -10
  224. package/server/services/health.js +1 -1
  225. package/server/services/hooks.js +7 -7
  226. package/server/services/images.js +4 -4
  227. package/server/services/managerClient.js +1 -1
  228. package/server/services/markdown.js +79 -79
  229. package/server/services/menuRender.js +5 -5
  230. package/server/services/menus-migration.js +3 -3
  231. package/server/services/menus.js +31 -31
  232. package/server/services/permissionRegistry.js +1 -1
  233. package/server/services/pluginFiles.js +5 -5
  234. package/server/services/pluginInstaller.js +17 -17
  235. package/server/services/pluginScaffold.js +1 -1
  236. package/server/services/plugins.js +17 -17
  237. package/server/services/presetCollections.js +2 -2
  238. package/server/services/projects.js +35 -26
  239. package/server/services/recipes/contact-list.json +1 -1
  240. package/server/services/recipes/onboarding.json +8 -8
  241. package/server/services/references.js +8 -8
  242. package/server/services/renderer.js +9 -9
  243. package/server/services/roles.js +9 -9
  244. package/server/services/rowAccess.js +10 -10
  245. package/server/services/scaffolder.js +30 -30
  246. package/server/services/sidebar-migration.js +10 -10
  247. package/server/services/sitemap.js +1 -1
  248. package/server/services/userProfiles.js +199 -199
  249. package/server/services/userRoles.js +7 -7
  250. package/server/services/users.js +302 -302
  251. package/server/services/versions.js +3 -3
  252. package/server/services/viewPipeline.js +6 -6
  253. package/server/services/views.js +11 -11
  254. package/server/templates/page.html +5 -5
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Invoice plugin — editor view. Create or edit a single invoice.
2
+ * Invoice plugin - editor view. Create or edit a single invoice.
3
3
  */
4
4
  function escapeHtml(s) {
5
5
  return String(s ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
@@ -77,7 +77,7 @@ export const editorView = {
77
77
  while (el.firstChild) el.removeChild(el.firstChild);
78
78
  const placeholder = document.createElement('option');
79
79
  placeholder.value = '';
80
- placeholder.textContent = '— select —';
80
+ placeholder.textContent = '- select -';
81
81
  el.appendChild(placeholder);
82
82
  for (const item of list) {
83
83
  const opt = document.createElement('option');
@@ -151,7 +151,7 @@ export const editorView = {
151
151
  const totalCell = document.createElement('td');
152
152
  totalCell.style.cssText = 'text-align:right;font-variant-numeric:tabular-nums;';
153
153
  totalCell.id = `line-total-${idx}`;
154
- totalCell.textContent = '—';
154
+ totalCell.textContent = '-';
155
155
 
156
156
  const removeBtn = document.createElement('button');
157
157
  removeBtn.type = 'button';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Invoice plugin — list view.
2
+ * Invoice plugin - list view.
3
3
  */
4
4
  function escapeHtml(s) {
5
5
  return String(s ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
@@ -25,7 +25,7 @@ export const indexView = {
25
25
 
26
26
  function receiverName(id) {
27
27
  const r = receivers.find((x) => x.id === id);
28
- if (!r) return '—';
28
+ if (!r) return '-';
29
29
  return r.company || r.name || id;
30
30
  }
31
31
 
@@ -50,13 +50,13 @@ export const indexView = {
50
50
  columns: [
51
51
  {
52
52
  key: 'number', title: 'Number', sortable: true,
53
- render: (v, row) => `<a href="#/plugins/invoice/edit/${escapeHtml(row.id)}" style="font-weight:600;">${escapeHtml(v || '—')}</a>`
53
+ render: (v, row) => `<a href="#/plugins/invoice/edit/${escapeHtml(row.id)}" style="font-weight:600;">${escapeHtml(v || '-')}</a>`
54
54
  },
55
55
  { key: 'receiverId', title: 'Billed To', sortable: false,
56
56
  render: (v) => escapeHtml(receiverName(v))
57
57
  },
58
58
  { key: 'issueDate', title: 'Issue Date', sortable: true,
59
- render: (v) => v ? escapeHtml(D(v).format('DD MMM YYYY')) : '—'
59
+ render: (v) => v ? escapeHtml(D(v).format('DD MMM YYYY')) : '-'
60
60
  },
61
61
  { key: 'totals', title: 'Total', sortable: false,
62
62
  render: (totals, row) => `<span style="font-variant-numeric:tabular-nums;">${escapeHtml(fmt(totals?.total ?? 0, row.currency))}</span>`
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Invoice plugin — issuers CRUD view.
2
+ * Invoice plugin - issuers CRUD view.
3
3
  */
4
4
  import {mountPartyView} from './party-view.js?v=1';
5
5
 
@@ -25,11 +25,11 @@ export async function mountPartyView($container, config) {
25
25
  }
26
26
  ];
27
27
  if (config.fields.some((f) => f.key === 'company')) {
28
- cols.push({ key: 'company', title: 'Company', sortable: true, render: (v) => escapeHtml(v || '—') });
28
+ cols.push({ key: 'company', title: 'Company', sortable: true, render: (v) => escapeHtml(v || '-') });
29
29
  }
30
30
  cols.push(
31
- { key: 'email', title: 'Email', sortable: true, render: (v) => v ? `<a href="mailto:${escapeHtml(v)}">${escapeHtml(v)}</a>` : '—' },
32
- { key: 'vatNumber', title: 'VAT', sortable: false, render: (v) => v ? `<code>${escapeHtml(v)}</code>` : '—' },
31
+ { key: 'email', title: 'Email', sortable: true, render: (v) => v ? `<a href="mailto:${escapeHtml(v)}">${escapeHtml(v)}</a>` : '-' },
32
+ { key: 'vatNumber', title: 'VAT', sortable: false, render: (v) => v ? `<code>${escapeHtml(v)}</code>` : '-' },
33
33
  { key: 'id', title: 'Actions', sortable: false,
34
34
  render: (id) => `<div style="display:flex;gap:.4rem;">
35
35
  <button class="btn btn-sm btn-outline party-edit" data-id="${escapeHtml(id)}"><span data-icon="edit" data-icon-size="14"></span></button>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Invoice plugin — receivers CRUD view.
2
+ * Invoice plugin - receivers CRUD view.
3
3
  */
4
4
  import {mountPartyView} from './party-view.js?v=1';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Invoice Plugin — Default Configuration
2
+ * Invoice Plugin - Default Configuration
3
3
  *
4
4
  * numberPrefix used in generated invoice numbers (e.g. INV-2026-0001)
5
5
  * numberPadding minimum digits for the sequential portion
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Invoice Plugin — Server
2
+ * Invoice Plugin - Server
3
3
  *
4
4
  * Endpoints (mounted at /api/plugins/invoice):
5
5
  * GET /issuers admin list issuers
@@ -65,19 +65,19 @@
65
65
  ],
66
66
  "views": {
67
67
  "plugin-invoice-list": {
68
- "entry": "invoice/admin/views/index.js?v=a7963ce7",
68
+ "entry": "invoice/admin/views/index.js?v=9c70ea80",
69
69
  "exportName": "indexView"
70
70
  },
71
71
  "plugin-invoice-editor": {
72
- "entry": "invoice/admin/views/editor.js?v=897f0259",
72
+ "entry": "invoice/admin/views/editor.js?v=e5e153c1",
73
73
  "exportName": "editorView"
74
74
  },
75
75
  "plugin-invoice-issuers": {
76
- "entry": "invoice/admin/views/issuers.js?v=ce720b84",
76
+ "entry": "invoice/admin/views/issuers.js?v=ac69a08a",
77
77
  "exportName": "issuersView"
78
78
  },
79
79
  "plugin-invoice-receivers": {
80
- "entry": "invoice/admin/views/receivers.js?v=c4b34b26",
80
+ "entry": "invoice/admin/views/receivers.js?v=f016e1ff",
81
81
  "exportName": "receiversView"
82
82
  }
83
83
  }
@@ -101,7 +101,7 @@ export const notesView = {
101
101
  const ellipsis = v && v.length > 100 ? '\u2026' : '';
102
102
  return preview
103
103
  ? `<span style="font-size:0.87rem;opacity:0.8;">${esc(preview)}${ellipsis}</span>`
104
- : '<span style="opacity:0.35;">\u2014</span>';
104
+ : '<span style="opacity:0.35;">-</span>';
105
105
  }
106
106
  },
107
107
  {
@@ -109,7 +109,7 @@ export const notesView = {
109
109
  title: 'Categories',
110
110
  sortable: false,
111
111
  render: (v) => {
112
- if (!Array.isArray(v) || v.length === 0) return '<span style="opacity:0.35;">\u2014</span>';
112
+ if (!Array.isArray(v) || v.length === 0) return '<span style="opacity:0.35;">-</span>';
113
113
  return v.map((c) =>
114
114
  `<span class="badge badge-outline notes-cat-tag" data-cat="${esc(c)}" `
115
115
  + `style="font-size:0.7rem;margin-right:2px;cursor:pointer;">${esc(c)}</span>`
@@ -122,7 +122,7 @@ export const notesView = {
122
122
  sortable: true,
123
123
  render: (v) => v
124
124
  ? `<span title="${esc(D(v).format('DD MMM YYYY HH:mm'))}">${esc(D(v).fromNow())}</span>`
125
- : '\u2014'
125
+ : '-'
126
126
  },
127
127
  {
128
128
  key: 'id',
@@ -160,7 +160,7 @@ export const notesView = {
160
160
  Domma.icons.scan(wrap);
161
161
  }
162
162
 
163
- // ---- Render category filter bar (DOM methods — no innerHTML with user data) ----
163
+ // ---- Render category filter bar (DOM methods - no innerHTML with user data) ----
164
164
  function renderCategoryFilter() {
165
165
  catFilterEl.textContent = '';
166
166
 
@@ -30,7 +30,7 @@ export default async function notesPlugin(fastify, options) {
30
30
  return items;
31
31
  }
32
32
 
33
- /** GET /api/plugins/notes/items — supports ?q= and ?category= */
33
+ /** GET /api/plugins/notes/items - supports ?q= and ?category= */
34
34
  fastify.get('/items', { preHandler: [authenticate] }, async (request, reply) => {
35
35
  const uid = userId(request);
36
36
  const { q, category } = request.query;
@@ -25,7 +25,7 @@
25
25
  ],
26
26
  "views": {
27
27
  "plugin-notes": {
28
- "entry": "notes/admin/views/notes.js?v=43194b9f",
28
+ "entry": "notes/admin/views/notes.js?v=1010cfca",
29
29
  "exportName": "notesView"
30
30
  }
31
31
  }
@@ -43,13 +43,13 @@
43
43
  <label class="form-label">Max results</label>
44
44
  <input id="field-max-results" type="number" class="form-input" min="1" max="50"
45
45
  placeholder="10">
46
- <span class="form-hint">Maximum number of results to return per search (1–50).</span>
46
+ <span class="form-hint">Maximum number of results to return per search (1-50).</span>
47
47
  </div>
48
48
  <div class="col-6">
49
49
  <label class="form-label">Minimum query length</label>
50
50
  <input id="field-min-query-length" type="number" class="form-input" min="1" max="5"
51
51
  placeholder="2">
52
- <span class="form-hint">Minimum characters required before searching (1–5).</span>
52
+ <span class="form-hint">Minimum characters required before searching (1-5).</span>
53
53
  </div>
54
54
  </div>
55
55
 
@@ -58,7 +58,7 @@
58
58
  <label class="form-label">Debounce delay (ms)</label>
59
59
  <input id="field-debounce-ms" type="number" class="form-input" min="100" max="1000"
60
60
  placeholder="300">
61
- <span class="form-hint">Delay after typing stops before search fires (100–1000ms).</span>
61
+ <span class="form-hint">Delay after typing stops before search fires (100-1000ms).</span>
62
62
  </div>
63
63
  </div>
64
64
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Site Search Plugin — Admin Settings View
2
+ * Site Search Plugin - Admin Settings View
3
3
  */
4
4
  import {apiRequest} from '/admin/js/api.js';
5
5
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Site Search Plugin — Default Configuration
2
+ * Site Search Plugin - Default Configuration
3
3
  */
4
4
  export default {
5
5
  placeholder: 'Search pages...',
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Site Search Plugin — Server
2
+ * Site Search Plugin - Server
3
3
  *
4
4
  * Endpoints (prefix: /api/plugins/site-search):
5
- * GET /search?q=term — public: full-text search across all published pages
6
- * GET /settings — public: return plugin settings (used by inject script)
7
- * PUT /settings — admin-auth: save user overrides
5
+ * GET /search?q=term - public: full-text search across all published pages
6
+ * GET /settings - public: return plugin settings (used by inject script)
7
+ * PUT /settings - admin-auth: save user overrides
8
8
  */
9
9
  import {listPages} from '../../server/services/content.js';
10
10
  import {getPluginSettings, savePluginState} from '../../server/services/plugins.js';
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "views": {
30
30
  "plugin-site-search": {
31
- "entry": "site-search/admin/views/site-search.js?v=ff425f47",
31
+ "entry": "site-search/admin/views/site-search.js?v=0c7dd970",
32
32
  "exportName": "siteSearchView"
33
33
  }
34
34
  }
@@ -1,7 +1,7 @@
1
1
  <div class="survey-results-plugin">
2
2
 
3
3
  <style>
4
- /* Layout only + real Domma theme tokens — surfaces use .card so the
4
+ /* Layout only + real Domma theme tokens - surfaces use .card so the
5
5
  active theme is always respected; no hardcoded colours. */
6
6
  .survey-results-plugin .sr-head { display:flex; align-items:flex-start; gap:1rem; flex-wrap:wrap; margin-bottom:1.25rem; }
7
7
  .survey-results-plugin .sr-head h2 { margin:0 0 0.25rem; }
@@ -1,7 +1,7 @@
1
1
  <div class="survey-editor-plugin">
2
2
 
3
3
  <style>
4
- /* Layout only — colours/borders come from Domma's themed .card and
4
+ /* Layout only - colours/borders come from Domma's themed .card and
5
5
  .form-input, so the active theme is always respected. */
6
6
  .survey-editor-plugin .se-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.25rem; }
7
7
  .survey-editor-plugin .se-span-2 { grid-column: 1 / -1; }
@@ -90,16 +90,16 @@
90
90
  <div class="card-body">
91
91
  <div class="se-grid">
92
92
  <div class="se-field se-span-2">
93
- <label for="f-intro">Intro (Markdown — shown above the form)</label>
93
+ <label for="f-intro">Intro (Markdown - shown above the form)</label>
94
94
  <textarea id="f-intro" name="intro" class="form-input" placeholder="## Welcome&#10;Thanks for taking a moment to help us improve."></textarea>
95
95
  </div>
96
96
  <div class="se-field se-span-2">
97
- <label for="f-footer">Footer (Markdown — shown below the form)</label>
97
+ <label for="f-footer">Footer (Markdown - shown below the form)</label>
98
98
  <textarea id="f-footer" name="footer" class="form-input" placeholder="Questions? Contact us at hello@example.com"></textarea>
99
99
  </div>
100
100
  <div class="se-field se-span-2">
101
101
  <label for="f-thankYou">Thank-you message (shown after submitting)</label>
102
- <textarea id="f-thankYou" name="thankYou" class="form-input" placeholder="Thank you — your response has been recorded."></textarea>
102
+ <textarea id="f-thankYou" name="thankYou" class="form-input" placeholder="Thank you - your response has been recorded."></textarea>
103
103
  </div>
104
104
  </div>
105
105
  </div>
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Surveys plugin — shared audience view.
2
+ * Surveys plugin - shared audience view.
3
3
  *
4
4
  * Manages survey contacts and audience groups, plus an import action that pulls
5
5
  * the audience from the Contacts plugin.
@@ -90,15 +90,15 @@ export const audienceView = {
90
90
  table = T.create($container.find('#audience-table').get(0), {
91
91
  data: contacts,
92
92
  columns: [
93
- {key: 'name', title: 'Name', sortable: true, render: (v) => esc(v) || '—'},
93
+ {key: 'name', title: 'Name', sortable: true, render: (v) => esc(v) || '-'},
94
94
  {
95
95
  key: 'email', title: 'Email', sortable: true,
96
- render: (v) => v ? `<a href="mailto:${esc(v)}">${esc(v)}</a>` : '—'
96
+ render: (v) => v ? `<a href="mailto:${esc(v)}">${esc(v)}</a>` : '-'
97
97
  },
98
98
  {
99
99
  key: 'groups', title: 'Groups', sortable: false,
100
100
  render: (v) => {
101
- if (!Array.isArray(v) || !v.length) return '—';
101
+ if (!Array.isArray(v) || !v.length) return '-';
102
102
  return v.map((g) => `<span class="badge badge-primary" style="margin-right:2px;">${esc(g)}</span>`).join('');
103
103
  }
104
104
  },
@@ -152,7 +152,7 @@ export const audienceView = {
152
152
  row.style.cssText = 'padding:0.4rem 0;border-bottom:1px solid var(--dm-border);';
153
153
  const badge = document.createElement('span');
154
154
  badge.className = 'badge badge-primary';
155
- badge.textContent = g.name; // textContent — safe
155
+ badge.textContent = g.name; // textContent - safe
156
156
  row.appendChild(badge);
157
157
  if (g.description) {
158
158
  const desc = document.createElement('div');
@@ -177,7 +177,7 @@ export const audienceView = {
177
177
 
178
178
  // Canonical F.create: (blueprintObject, defaultsObject, opts).renderTo(el).
179
179
  // Blueprint is keyed by field name; placeholder/hint live under
180
- // formConfig (proven shape — collection-entries.js). We supply our own
180
+ // formConfig (proven shape - collection-entries.js). We supply our own
181
181
  // buttons (below) and read values from the DOM on save, so the modal's
182
182
  // HTML sanitiser never strips an interactive submit button.
183
183
  F.create(
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Surveys plugin — results / statistics dashboard.
2
+ * Surveys plugin - results / statistics dashboard.
3
3
  *
4
4
  * Renders a response-rate summary, then per-question cards: distribution bars
5
5
  * for choice/rating fields and a tidy answer list for free-text fields. Authed
@@ -76,7 +76,7 @@ export const resultsView = {
76
76
 
77
77
  // ---- Header -------------------------------------------------------
78
78
  const titleEl = root.querySelector('#results-title');
79
- if (titleEl) titleEl.textContent = `Results — ${survey?.title || slug}`;
79
+ if (titleEl) titleEl.textContent = `Results - ${survey?.title || slug}`;
80
80
  const subEl = root.querySelector('#results-sub');
81
81
  if (subEl) {
82
82
  const statusBadge = survey?.status ? ` · ${survey.status}` : '';
@@ -103,7 +103,7 @@ export const resultsView = {
103
103
  let questionsHtml;
104
104
 
105
105
  if (!completed && !fields.some((f) => answerCount(f) > 0)) {
106
- questionsHtml = `<div class="card"><div class="card-body"><p class="sr-empty">No responses yet — once people complete the survey, their answers appear here.</p></div></div>`;
106
+ questionsHtml = `<div class="card"><div class="card-body"><p class="sr-empty">No responses yet - once people complete the survey, their answers appear here.</p></div></div>`;
107
107
  } else {
108
108
  questionsHtml = fields.map((f, idx) => {
109
109
  const n = answerCount(f);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Surveys plugin — campaign create/edit view.
2
+ * Surveys plugin - campaign create/edit view.
3
3
  *
4
4
  * The form is hand-built in the template as native inputs laid out in an
5
5
  * explicit CSS grid (guaranteed multi-column), so this view only populates the
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Surveys plugin — campaign list view.
2
+ * Surveys plugin - campaign list view.
3
3
  *
4
4
  * Lists survey campaigns in a Domma table with status/mode badges and
5
5
  * row actions that navigate to the editor and results views.
@@ -144,7 +144,7 @@ export const surveysView = {
144
144
  const audienceBtn = $container.find('#manage-audience').get(0);
145
145
  if (audienceBtn) audienceBtn.addEventListener('click', () => { location.hash = '#/plugins/surveys/audience'; });
146
146
 
147
- // Row-action delegation (proven pattern — see admin/js/views/api-tokens.js).
147
+ // Row-action delegation (proven pattern - see admin/js/views/api-tokens.js).
148
148
  // Unnamespaced + idempotent via .off()/.on(); namespaced delegation is
149
149
  // broken in this codebase.
150
150
  $container.off('click', '.btn-edit-survey').on('click', '.btn-edit-survey', function () {
@@ -12,7 +12,7 @@ import {registerPluginResource} from '../../server/services/permissionRegistry.j
12
12
 
13
13
  const col = {createEntry, deleteEntry, getEntry, listEntries, updateEntry};
14
14
 
15
- // Register the `surveys` permission family (idempotent — no-op if already present).
15
+ // Register the `surveys` permission family (idempotent - no-op if already present).
16
16
  // Custom roles are NOT back-filled; admins grant it in the role editor (same gotcha
17
17
  // as Menus/Projects).
18
18
  registerPluginResource({
@@ -45,19 +45,19 @@
45
45
  ],
46
46
  "views": {
47
47
  "plugin-surveys": {
48
- "entry": "surveys/admin/views/surveys.js?v=62e94063",
48
+ "entry": "surveys/admin/views/surveys.js?v=86946458",
49
49
  "exportName": "surveysView"
50
50
  },
51
51
  "plugin-survey-editor": {
52
- "entry": "surveys/admin/views/survey-editor.js?v=322a3ad4",
52
+ "entry": "surveys/admin/views/survey-editor.js?v=c6b3e1b7",
53
53
  "exportName": "surveyEditorView"
54
54
  },
55
55
  "plugin-survey-audience": {
56
- "entry": "surveys/admin/views/audience.js?v=66eea1d5",
56
+ "entry": "surveys/admin/views/audience.js?v=6aca096f",
57
57
  "exportName": "audienceView"
58
58
  },
59
59
  "plugin-survey-results": {
60
- "entry": "surveys/admin/views/results.js?v=13ceda01",
60
+ "entry": "surveys/admin/views/results.js?v=97b8e1fd",
61
61
  "exportName": "resultsView"
62
62
  }
63
63
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Theme Switcher — Admin Settings View
2
+ * Theme Switcher - Admin Settings View
3
3
  */
4
4
  import {apiRequest} from '/admin/js/api.js';
5
5
 
@@ -32,7 +32,7 @@
32
32
  ],
33
33
  "views": {
34
34
  "pluginThemeSwitcher": {
35
- "entry": "theme-switcher/admin/views/theme-switcher.js?v=c668a895",
35
+ "entry": "theme-switcher/admin/views/theme-switcher.js?v=c906bed1",
36
36
  "exportName": "themeSwitcherView"
37
37
  }
38
38
  }
@@ -46,11 +46,11 @@
46
46
  "options": [
47
47
  {
48
48
  "value": "right-center",
49
- "label": "Right — Centre"
49
+ "label": "Right - Centre"
50
50
  },
51
51
  {
52
52
  "value": "left-center",
53
- "label": "Left — Centre"
53
+ "label": "Left - Centre"
54
54
  },
55
55
  {
56
56
  "value": "bottom-right",
@@ -1,30 +1,6 @@
1
1
  <div class="dm-theme-switcher" id="dm-theme-switcher" role="navigation" aria-label="Theme switcher">
2
2
  <button class="dm-ts-trigger" data-tooltip="Switch theme" aria-haspopup="true" aria-expanded="false"></button>
3
3
  <div class="dm-ts-options" role="menu">
4
- <button class="dm-ts-dot dm-ts-dot-ocean-dark" data-theme="ocean-dark" data-tooltip="Ocean Dark"
5
- aria-label="Ocean Dark"></button>
6
- <button class="dm-ts-dot dm-ts-dot-ocean-light" data-theme="ocean-light" data-tooltip="Ocean Light"
7
- aria-label="Ocean Light"></button>
8
- <button class="dm-ts-dot dm-ts-dot-forest-dark" data-theme="forest-dark" data-tooltip="Forest Dark"
9
- aria-label="Forest Dark"></button>
10
- <button class="dm-ts-dot dm-ts-dot-forest-light" data-theme="forest-light" data-tooltip="Forest Light"
11
- aria-label="Forest Light"></button>
12
- <button class="dm-ts-dot dm-ts-dot-sunset-dark" data-theme="sunset-dark" data-tooltip="Sunset Dark"
13
- aria-label="Sunset Dark"></button>
14
- <button class="dm-ts-dot dm-ts-dot-sunset-light" data-theme="sunset-light" data-tooltip="Sunset Light"
15
- aria-label="Sunset Light"></button>
16
- <button class="dm-ts-dot dm-ts-dot-royal-dark" data-theme="royal-dark" data-tooltip="Royal Dark"
17
- aria-label="Royal Dark"></button>
18
- <button class="dm-ts-dot dm-ts-dot-royal-light" data-theme="royal-light" data-tooltip="Royal Light"
19
- aria-label="Royal Light"></button>
20
- <button class="dm-ts-dot dm-ts-dot-lemon-dark" data-theme="lemon-dark" data-tooltip="Lemon Dark"
21
- aria-label="Lemon Dark"></button>
22
- <button class="dm-ts-dot dm-ts-dot-lemon-light" data-theme="lemon-light" data-tooltip="Lemon Light"
23
- aria-label="Lemon Light"></button>
24
- <button class="dm-ts-dot dm-ts-dot-silver-dark" data-theme="silver-dark" data-tooltip="Silver Dark"
25
- aria-label="Silver Dark"></button>
26
- <button class="dm-ts-dot dm-ts-dot-silver-light" data-theme="silver-light" data-tooltip="Silver Light"
27
- aria-label="Silver Light"></button>
28
4
  <button class="dm-ts-dot dm-ts-dot-charcoal-dark" data-theme="charcoal-dark" data-tooltip="Charcoal Dark"
29
5
  aria-label="Charcoal Dark"></button>
30
6
  <button class="dm-ts-dot dm-ts-dot-charcoal-light" data-theme="charcoal-light" data-tooltip="Charcoal Light"
@@ -33,22 +9,46 @@
33
9
  aria-label="Christmas Dark"></button>
34
10
  <button class="dm-ts-dot dm-ts-dot-christmas-light" data-theme="christmas-light" data-tooltip="Christmas Light"
35
11
  aria-label="Christmas Light"></button>
36
- <button class="dm-ts-dot dm-ts-dot-unicorn-dark" data-theme="unicorn-dark" data-tooltip="Unicorn Dark"
37
- aria-label="Unicorn Dark"></button>
38
- <button class="dm-ts-dot dm-ts-dot-unicorn-light" data-theme="unicorn-light" data-tooltip="Unicorn Light"
39
- aria-label="Unicorn Light"></button>
40
12
  <button class="dm-ts-dot dm-ts-dot-dreamy-dark" data-theme="dreamy-dark" data-tooltip="Dreamy Dark"
41
13
  aria-label="Dreamy Dark"></button>
42
14
  <button class="dm-ts-dot dm-ts-dot-dreamy-light" data-theme="dreamy-light" data-tooltip="Dreamy Light"
43
15
  aria-label="Dreamy Light"></button>
16
+ <button class="dm-ts-dot dm-ts-dot-forest-dark" data-theme="forest-dark" data-tooltip="Forest Dark"
17
+ aria-label="Forest Dark"></button>
18
+ <button class="dm-ts-dot dm-ts-dot-forest-light" data-theme="forest-light" data-tooltip="Forest Light"
19
+ aria-label="Forest Light"></button>
44
20
  <button class="dm-ts-dot dm-ts-dot-grayve-dark" data-theme="grayve-dark" data-tooltip="Grayve Dark"
45
21
  aria-label="Grayve Dark"></button>
46
22
  <button class="dm-ts-dot dm-ts-dot-grayve-light" data-theme="grayve-light" data-tooltip="Grayve Light"
47
23
  aria-label="Grayve Light"></button>
24
+ <button class="dm-ts-dot dm-ts-dot-lemon-dark" data-theme="lemon-dark" data-tooltip="Lemon Dark"
25
+ aria-label="Lemon Dark"></button>
26
+ <button class="dm-ts-dot dm-ts-dot-lemon-light" data-theme="lemon-light" data-tooltip="Lemon Light"
27
+ aria-label="Lemon Light"></button>
48
28
  <button class="dm-ts-dot dm-ts-dot-mint-dark" data-theme="mint-dark" data-tooltip="Mint Dark"
49
29
  aria-label="Mint Dark"></button>
50
30
  <button class="dm-ts-dot dm-ts-dot-mint-light" data-theme="mint-light" data-tooltip="Mint Light"
51
31
  aria-label="Mint Light"></button>
32
+ <button class="dm-ts-dot dm-ts-dot-ocean-dark" data-theme="ocean-dark" data-tooltip="Ocean Dark"
33
+ aria-label="Ocean Dark"></button>
34
+ <button class="dm-ts-dot dm-ts-dot-ocean-light" data-theme="ocean-light" data-tooltip="Ocean Light"
35
+ aria-label="Ocean Light"></button>
36
+ <button class="dm-ts-dot dm-ts-dot-royal-dark" data-theme="royal-dark" data-tooltip="Royal Dark"
37
+ aria-label="Royal Dark"></button>
38
+ <button class="dm-ts-dot dm-ts-dot-royal-light" data-theme="royal-light" data-tooltip="Royal Light"
39
+ aria-label="Royal Light"></button>
40
+ <button class="dm-ts-dot dm-ts-dot-silver-dark" data-theme="silver-dark" data-tooltip="Silver Dark"
41
+ aria-label="Silver Dark"></button>
42
+ <button class="dm-ts-dot dm-ts-dot-silver-light" data-theme="silver-light" data-tooltip="Silver Light"
43
+ aria-label="Silver Light"></button>
44
+ <button class="dm-ts-dot dm-ts-dot-sunset-dark" data-theme="sunset-dark" data-tooltip="Sunset Dark"
45
+ aria-label="Sunset Dark"></button>
46
+ <button class="dm-ts-dot dm-ts-dot-sunset-light" data-theme="sunset-light" data-tooltip="Sunset Light"
47
+ aria-label="Sunset Light"></button>
48
+ <button class="dm-ts-dot dm-ts-dot-unicorn-dark" data-theme="unicorn-dark" data-tooltip="Unicorn Dark"
49
+ aria-label="Unicorn Dark"></button>
50
+ <button class="dm-ts-dot dm-ts-dot-unicorn-light" data-theme="unicorn-light" data-tooltip="Unicorn Light"
51
+ aria-label="Unicorn Light"></button>
52
52
  <button class="dm-ts-dot dm-ts-dot-wedding-dark" data-theme="wedding-dark" data-tooltip="Wedding Dark"
53
53
  aria-label="Wedding Dark"></button>
54
54
  <button class="dm-ts-dot dm-ts-dot-wedding-light" data-theme="wedding-light" data-tooltip="Wedding Light"
@@ -1,6 +1,6 @@
1
1
  <style>
2
2
  /* ============================================================
3
- Theme Switcher — Floating Disc
3
+ Theme Switcher - Floating Disc
4
4
  Position is applied inline by inject-body.html script.
5
5
  ============================================================ */
6
6
  .dm-theme-switcher {
@@ -78,7 +78,7 @@ export default async function todoPlugin(fastify, options) {
78
78
  return reply.send(toTodo(updated));
79
79
  });
80
80
 
81
- /** DELETE /api/plugins/todo/completed — must be registered before /:id */
81
+ /** DELETE /api/plugins/todo/completed - must be registered before /:id */
82
82
  fastify.delete('/completed', {preHandler: [authenticate]}, async (request, reply) => {
83
83
  const uid = userId(request);
84
84
  const all = await loadAll(uid);
@@ -1 +1 @@
1
- .fb-form-wrapper{max-width:600px;margin:2rem auto}.fb-form-honeypot{position:absolute;left:-9999px;top:-9999px;width:0;height:0;overflow:hidden;opacity:0;z-index:-1}.fb-form-success{padding:1rem 1.25rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-success) 12%,transparent);border:1px solid color-mix(in srgb,var(--dm-success) 30%,transparent);color:var(--dm-success);font-size:.95rem;margin-top:.5rem}.fb-form-error{padding:.75rem 1rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-danger) 10%,transparent);border:1px solid color-mix(in srgb,var(--dm-danger) 25%,transparent);color:var(--dm-danger);font-size:.875rem;margin-top:.75rem}.fb-form-loading{opacity:.6;pointer-events:none}.wizard-progress{height:4px;background:var(--dm-border);border-radius:2px;margin-bottom:1rem}.wizard-progress-bar{height:100%;background:var(--dm-primary);border-radius:2px;transition:width .3s ease}.wizard-step-title{font-size:1.1rem;font-weight:600;margin-bottom:.25rem}.wizard-step-description{font-size:.875rem;color:var(--dm-text-muted);margin-bottom:1rem}.wizard-nav{display:flex;justify-content:space-between;gap:.5rem;margin-top:1rem}.fb-field-hidden{display:none!important}.fb-validation-error{color:var(--dm-danger);font-size:.8rem;margin-top:.25rem}.fb-form-wrapper .domma-form-field{margin-bottom:2rem}.fb-form-wrapper .form-group:not(.form-buttons){margin-bottom:2rem}.fb-spacer{height:2rem}.fb-field-required .picker-label:after,.fb-field-required>.form-label:after{content:" *";color:var(--dm-danger)}.fb-field-required .picker-label .picker-required{display:none}
1
+ .fb-form-wrapper{max-width:600px;margin:2rem auto}.fb-form-honeypot{position:absolute;left:-9999px;top:-9999px;width:0;height:0;overflow:hidden;opacity:0;z-index:-1}.fb-form-success{padding:1rem 1.25rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-success) 12%,transparent);border:1px solid color-mix(in srgb,var(--dm-success) 30%,transparent);color:var(--dm-success);font-size:.95rem;margin-top:.5rem}.fb-form-error{padding:.75rem 1rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-danger) 10%,transparent);border:1px solid color-mix(in srgb,var(--dm-danger) 25%,transparent);color:var(--dm-danger);font-size:.875rem;margin-top:.75rem}.fb-form-loading{opacity:.6;pointer-events:none}.wizard-progress{height:4px;background:var(--dm-border);border-radius:2px;margin-bottom:1rem}.wizard-progress-bar{height:100%;background:var(--dm-primary);border-radius:2px;transition:width .3s ease}.wizard-step-title{font-size:1.1rem;font-weight:600;margin-bottom:.25rem}.wizard-step-description{font-size:.875rem;color:var(--dm-text-muted);margin-bottom:1rem}.wizard-nav{display:flex;justify-content:space-between;gap:.5rem;margin-top:1rem}.fb-field-hidden{display:none!important}.fb-validation-error{color:var(--dm-danger);font-size:.8rem;margin-top:.25rem}.fb-form-wrapper .domma-form-field{margin-bottom:2rem}.fb-form-wrapper .form-group:not(.form-buttons){margin-bottom:2rem}.fb-spacer{height:2rem}.fb-field-required .picker-label:after,.fb-field-required>.form-label:after{content:" *";color:var(--dm-danger)}.fb-field-required .picker-label .picker-required{display:none}.fb-field-invalid>.form-label,.fb-field-invalid .picker-label{color:var(--dm-danger)}.fb-field-invalid .form-input,.fb-field-invalid .form-select,.fb-field-invalid textarea,.fb-field-invalid .picker-options{border-color:var(--dm-danger)}@media(max-width:700px){.fb-form-wrapper form.grid,[data-form-inline] form.grid,.fb-form-wrapper .wizard form.grid,[data-form-inline] .wizard form.grid{grid-template-columns:1fr!important}.fb-form-wrapper form.grid>[class*=col-span-],[data-form-inline] form.grid>[class*=col-span-]{grid-column:span 1 / span 1!important}}.wizard-nav{gap:1rem;flex-wrap:wrap}.wizard-nav .btn{min-width:7.5rem}@media(max-width:480px){.wizard-nav{flex-direction:column-reverse}.wizard-nav .btn{width:100%}}.fb-form-wrapper .form-buttons,[data-form-inline] .form-buttons{display:flex;gap:1rem;flex-wrap:wrap;margin-top:1.25rem}