domma-cms 1.8.34 → 1.8.36
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.
- package/CHANGELOG.md +12 -0
- package/admin/index.html +1 -1
- package/admin/js/app.js +1 -1
- package/admin/js/lib/seo-analyse.js +1 -1
- package/admin/js/lib/seo-settings.js +2 -2
- package/admin/js/templates/docs/usage-search-engines.html +84 -0
- package/admin/js/templates/documentation.html +4 -0
- package/admin/js/views/doc-pages.js +1 -1
- package/admin/js/views/seo.js +15 -14
- package/docs/DommaFeatures.md +9 -2
- package/docs/plugin-development.md +1 -1
- package/package.json +1 -1
- package/plugins/booking/CLAUDE.md +5 -0
- package/plugins/booking/admin/views/settings.js +1 -1
- package/plugins/booking/docs/guide.md +2 -0
- package/plugins/booking/plugin.json +2 -2
- package/plugins/booking/plugin.public.js +15 -2
- package/plugins/booking/tests/seo.test.js +71 -0
- package/plugins/free-tier.lock.json +18 -16
- package/plugins/shopping-cart/CLAUDE.md +9 -0
- package/plugins/shopping-cart/admin/views/settings.js +1 -1
- package/plugins/shopping-cart/docs/guide.md +2 -1
- package/plugins/shopping-cart/plugin.js +18 -0
- package/plugins/shopping-cart/plugin.json +2 -2
- package/plugins/shopping-cart/plugin.public.js +39 -4
- package/plugins/shopping-cart/tests/seo.test.js +95 -0
- package/public/js/site.js +1 -1
- package/public/js/vendor/dompurify/LICENSE +202 -0
- package/public/js/vendor/dompurify/LICENSE-MPL +373 -0
- package/public/js/vendor/dompurify/purify.min.js +7 -0
- package/scripts/build.js +3 -0
- package/server/routes/api/collections.js +2 -0
- package/server/routes/api/effects.js +5 -1
- package/server/routes/api/forms.js +2 -0
- package/server/routes/api/views.js +2 -0
- package/server/routes/public.js +36 -1
- package/server/server.js +1 -0
- package/server/services/docs.js +1 -0
- package/server/services/hooks.js +3 -2
- package/server/services/markdown.js +200 -120
- package/server/services/nojsLinks.js +130 -0
- package/server/services/renderer.js +23 -6
- package/server/services/sitemap.js +100 -2
- package/server/templates/page.html +17 -12
|
@@ -109,7 +109,7 @@ export async function openSettings(ctx, section = 'store') {
|
|
|
109
109
|
<input class="form-input" data-model="shopTitle.value" maxlength="80"></div>
|
|
110
110
|
<div><label class="form-label">Address <span data-help="Where the shop lives on your site: /shop gives /shop, /shop/cart and a page per product. Changing it takes effect at once; links people saved to the old address stop working."></span></label>
|
|
111
111
|
<input class="form-input" data-model="shopPath.value" maxlength="60"></div>
|
|
112
|
-
<div class="shp-wide"><label class="form-label">Introduction <span data-help="A line or two under the shop's name."></span></label>
|
|
112
|
+
<div class="shp-wide"><label class="form-label">Introduction <span data-help="A line or two under the shop's name. Search engines show it too; left empty, they get a line made from your site name and products."></span></label>
|
|
113
113
|
<textarea class="form-input" rows="2" data-model="shopIntro.value" maxlength="1000"></textarea></div>
|
|
114
114
|
<div><label class="form-label">Currency <span data-help="Every price in the shop. Changing it does not convert the prices you have entered."></span></label>
|
|
115
115
|
<select class="form-select" data-model="currency.value">${Object.entries(CURRENCIES).map(([c, x]) => `<option value="${c}">${c} - ${esc(x.label)}</option>`).join('')}</select></div>
|
|
@@ -120,7 +120,8 @@ Click the cog in the Shop banner to open **Shop settings**. It has four sections
|
|
|
120
120
|
|
|
121
121
|
### Storefront
|
|
122
122
|
|
|
123
|
-
- **Shop name**, **Address** (default `/shop`; takes effect at once, and old links stop working), **Introduction**.
|
|
123
|
+
- **Shop name**, **Address** (default `/shop`; takes effect at once, and old links stop working), **Introduction**. Search engines show the introduction as the shop's description; left empty, they get a line made from your site's name and first products.
|
|
124
|
+
- **While nothing is on sale** the shop page tells search engines not to list it, and it stays out of the site's `sitemap.xml`. As soon as one product is active (and not unlisted), the shop and every product page are indexed and listed in the sitemap.
|
|
124
125
|
- **Currency** - changing it does not convert prices you have entered.
|
|
125
126
|
- **Products per row** (2, 3 or 4).
|
|
126
127
|
- **Category filters**, **Search box** (shown once there are more than four products), **Basket button on every page**, **Say "Only 3 left"**.
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
} from './lib/shop.js';
|
|
44
44
|
import {refundPlan} from './lib/refunds.js';
|
|
45
45
|
import {cardHtml, esc, gridHtml} from './lib/render.js';
|
|
46
|
+
import {shopSitemapEntries} from './plugin.public.js';
|
|
46
47
|
|
|
47
48
|
/** The Site URL setting as an origin, or ''. */
|
|
48
49
|
function configuredBase() {
|
|
@@ -171,6 +172,23 @@ export default async function shoppingCart(fastify, options) {
|
|
|
171
172
|
await refreshShelf();
|
|
172
173
|
registerShortcodes(hooks);
|
|
173
174
|
|
|
175
|
+
// The shop in /sitemap.xml (core 0.89+; feature-detected), 1.7.2: the storefront and its
|
|
176
|
+
// products - nothing while nothing is on sale (the empty shop is noindex). A product or
|
|
177
|
+
// settings write here rebuilds it on the sitemap's next request.
|
|
178
|
+
if (typeof hooks.registerSitemapSource === 'function') {
|
|
179
|
+
try {
|
|
180
|
+
hooks.registerSitemapSource({id: 'shop', label: 'Shop', list: async () => {
|
|
181
|
+
const [entries, s] = await Promise.all([allProducts(), liveSettings()]);
|
|
182
|
+
return shopSitemapEntries(entries, s);
|
|
183
|
+
}});
|
|
184
|
+
fastify.addHook('onResponse', async (request, reply) => {
|
|
185
|
+
if (request.method !== 'GET' && request.method !== 'HEAD' && reply.statusCode < 400 && /\/(products|samples|settings)\b/.test(request.url)) {
|
|
186
|
+
try { hooks.sitemapChanged?.(); } catch { /* older core */ }
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
} catch { /* older core */ }
|
|
190
|
+
}
|
|
191
|
+
|
|
174
192
|
// ---- Telling people ------------------------------------------------------------
|
|
175
193
|
|
|
176
194
|
function announcePaid(order) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shopping-cart",
|
|
3
3
|
"displayName": "Shopping Cart",
|
|
4
|
-
"version": "1.7.
|
|
4
|
+
"version": "1.7.2",
|
|
5
5
|
"tier": "free",
|
|
6
6
|
"description": "Sell from your site: products with options, stock and pictures, a storefront and a cart that follows shoppers from page to page, and checkout with Stripe, PayPal or payment offline. Orders to fulfil in the sidebar, refunds from the order.",
|
|
7
7
|
"author": "Domma CMS",
|
|
8
|
-
"date": "2026-10-
|
|
8
|
+
"date": "2026-10-22",
|
|
9
9
|
"icon": "shopping-bag",
|
|
10
10
|
"permissions": [
|
|
11
11
|
{
|
|
@@ -17,6 +17,7 @@ import path from 'path';
|
|
|
17
17
|
import {fileURLToPath} from 'url';
|
|
18
18
|
import {renderBlogPage} from '../../server/services/renderer.js';
|
|
19
19
|
import {parseMarkdown} from '../../server/services/markdown.js';
|
|
20
|
+
import {getConfig} from '../../server/config.js';
|
|
20
21
|
import {byShelf, safeImage} from './public/lib/products.js';
|
|
21
22
|
import {accountHtml, cartHtml, esc, productHtml, receiptHtml, scriptJson, storefrontHtml} from './lib/render.js';
|
|
22
23
|
import {allProducts, getOrder, liveSettings, publicOrder, tokenOk} from './lib/shop.js';
|
|
@@ -40,6 +41,34 @@ export function matchShopPath(pathname, base) {
|
|
|
40
41
|
return null;
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
/** The products a shopper can see: on sale and not unlisted. */
|
|
45
|
+
export const onShelf = (entries) => entries.filter(e => e.data?.status === 'active' && !e.data?.unlisted);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The search-engine description (1.7.2): the owner's words (the shop's
|
|
49
|
+
* introduction, a product's summary), else a line made from the site's name -
|
|
50
|
+
* an empty one left /shop with no meta description at all.
|
|
51
|
+
*/
|
|
52
|
+
export function metaDescription(text, fallback) {
|
|
53
|
+
const out = String(text || '').replace(/\s+/g, ' ').trim() || String(fallback || '').trim();
|
|
54
|
+
return out.length > 160 ? `${out.slice(0, 157).trimEnd()}...` : out;
|
|
55
|
+
}
|
|
56
|
+
const siteName = () => String(getConfig('site')?.title || '').trim();
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The shop in /sitemap.xml (1.7.2): the storefront and every product a shopper
|
|
60
|
+
* can open - or nothing at all while there is nothing on sale, since the empty
|
|
61
|
+
* shop is `noindex` until then.
|
|
62
|
+
*/
|
|
63
|
+
export function shopSitemapEntries(entries, s) {
|
|
64
|
+
const shelf = onShelf(entries);
|
|
65
|
+
if (!shelf.length) return [];
|
|
66
|
+
return [{urlPath: s.shopPath, title: s.shopTitle || 'Shop', changefreq: 'daily'},
|
|
67
|
+
...shelf.filter(e => /^[a-z0-9-]{1,80}$/.test(String(e.data.slug || '')))
|
|
68
|
+
.map(e => ({urlPath: `${s.shopPath}/${e.data.slug}`, title: e.data.name || '', lastmod: e.meta?.updatedAt || null,
|
|
69
|
+
...(safeImage(e.data.images?.[0]) && {image: safeImage(e.data.images[0])})}))];
|
|
70
|
+
}
|
|
71
|
+
|
|
43
72
|
/** What the browser script needs, carried in the page. */
|
|
44
73
|
function pageConfig(s, extra = {}) {
|
|
45
74
|
return {
|
|
@@ -59,21 +88,27 @@ export default async function shopPublic(fastify) {
|
|
|
59
88
|
title, description, ogImage: image, urlPath, noindex,
|
|
60
89
|
baseUrl: `${request.protocol}://${request.host || request.headers.host || request.hostname}`
|
|
61
90
|
});
|
|
91
|
+
// The header as well as the meta tag: a crawler reading only headers gets it too.
|
|
92
|
+
if (noindex) reply.header('X-Robots-Tag', 'noindex');
|
|
62
93
|
return reply.type('text/html; charset=utf-8').header('Cache-Control', 'no-store').send(html);
|
|
63
94
|
}
|
|
64
95
|
|
|
65
96
|
const pages = {
|
|
66
97
|
async index(request, reply, s) {
|
|
67
|
-
const entries = (await allProducts()).
|
|
98
|
+
const entries = onShelf(await allProducts()).sort(byShelf);
|
|
68
99
|
const category = String(request.query?.category || '').slice(0, 60);
|
|
69
100
|
const query = String(request.query?.q || '').slice(0, 80);
|
|
101
|
+
const site = siteName();
|
|
70
102
|
return send(reply, request, s, {
|
|
71
103
|
page: 'index',
|
|
72
104
|
body: storefrontHtml({entries, settings: s, base: s.shopPath, category, query}),
|
|
73
105
|
title: s.shopTitle || 'Shop',
|
|
74
|
-
description: s.shopIntro
|
|
106
|
+
description: metaDescription(s.shopIntro, `Shop online${site ? ` with ${site}` : ''}`
|
|
107
|
+
+ `${entries.length ? `: ${entries.slice(0, 3).map(e => e.data.name).filter(Boolean).join(', ')}${entries.length > 3 ? ' and more' : ''}` : ''}.`),
|
|
75
108
|
image: safeImage(entries[0]?.data?.images?.[0]),
|
|
76
109
|
urlPath: s.shopPath,
|
|
110
|
+
// An empty shop is not a page worth finding (1.7.2): out of search until something is on sale.
|
|
111
|
+
noindex: entries.length === 0,
|
|
77
112
|
extra: {category, query}
|
|
78
113
|
});
|
|
79
114
|
},
|
|
@@ -83,7 +118,7 @@ export default async function shopPublic(fastify) {
|
|
|
83
118
|
},
|
|
84
119
|
|
|
85
120
|
async product(request, reply, s, {slug}) {
|
|
86
|
-
const all = (await allProducts())
|
|
121
|
+
const all = onShelf(await allProducts());
|
|
87
122
|
const entry = all.find(e => e.data.slug === slug);
|
|
88
123
|
if (!entry) return null; // fall through to the CMS's own 404 (or a page at that address)
|
|
89
124
|
let descriptionHtml = '';
|
|
@@ -98,7 +133,7 @@ export default async function shopPublic(fastify) {
|
|
|
98
133
|
page: 'product',
|
|
99
134
|
body: productHtml({entry, settings: s, base: s.shopPath, descriptionHtml, related}),
|
|
100
135
|
title: entry.data.name,
|
|
101
|
-
description: entry.data.summary || '',
|
|
136
|
+
description: metaDescription(entry.data.summary || String(entry.data.description || '').replace(/!?\[([^\]]*)\]\([^)]*\)/g, '$1').replace(/^\s*>+/gm, '').replace(/[#*_`]/g, ''), `Buy ${entry.data.name}${siteName() ? ` from ${siteName()}` : ''} online.`),
|
|
102
137
|
image: safeImage(entry.data.images?.[0]),
|
|
103
138
|
urlPath: `${s.shopPath}/${slug}`,
|
|
104
139
|
extra: {product: {id: entry.id, variants: (entry.data.variants || []).length}}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 1.7.2: what search engines are told about the shop. An empty shop is noindex
|
|
3
|
+
* and out of the sitemap; once something is on sale it is indexed and listed
|
|
4
|
+
* with its products, and every storefront page has a meta description.
|
|
5
|
+
* Runs against the real collection service in the checkout `make test` runs in;
|
|
6
|
+
* the two collections are removed after and config/plugins.json restored.
|
|
7
|
+
*/
|
|
8
|
+
import {test, before, after} from 'node:test';
|
|
9
|
+
import assert from 'node:assert/strict';
|
|
10
|
+
import fs from 'node:fs/promises';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import Fastify from 'fastify';
|
|
13
|
+
import shoppingCart from '../plugin.js';
|
|
14
|
+
import shopPublic, {metaDescription, shopSitemapEntries} from '../plugin.public.js';
|
|
15
|
+
|
|
16
|
+
const PLUGINS = path.resolve('config/plugins.json');
|
|
17
|
+
const DIRS = ['shop-products', 'shop-orders'].map(c => path.resolve('content/collections', c));
|
|
18
|
+
let savedPlugins;
|
|
19
|
+
let app;
|
|
20
|
+
let pub;
|
|
21
|
+
const sources = [];
|
|
22
|
+
|
|
23
|
+
before(async () => {
|
|
24
|
+
savedPlugins = await fs.readFile(PLUGINS, 'utf8').catch(() => null);
|
|
25
|
+
for (const d of DIRS) await fs.rm(d, {recursive: true, force: true});
|
|
26
|
+
app = Fastify();
|
|
27
|
+
const authenticate = async (req) => { req.user = {id: 'u1', name: 'Sam', role: 'admin'}; };
|
|
28
|
+
await app.register(shoppingCart, {
|
|
29
|
+
auth: {authenticate, requirePermission: () => async () => {}},
|
|
30
|
+
settings: {},
|
|
31
|
+
hooks: {registerShortcode() {}, registerSitemapSource: (s) => sources.push(s)}
|
|
32
|
+
});
|
|
33
|
+
pub = Fastify();
|
|
34
|
+
await pub.register(shopPublic);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
after(async () => {
|
|
38
|
+
await app?.close();
|
|
39
|
+
await pub?.close();
|
|
40
|
+
for (const d of DIRS) await fs.rm(d, {recursive: true, force: true});
|
|
41
|
+
if (savedPlugins === null) await fs.rm(PLUGINS, {force: true});
|
|
42
|
+
else await fs.writeFile(PLUGINS, savedPlugins);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const sitemap = () => sources.find(s => s.id === 'shop').list();
|
|
46
|
+
const metaOf = (html, name) => (html.match(new RegExp(`<meta name="${name}" content="([^"]*)"`)) || [])[1];
|
|
47
|
+
|
|
48
|
+
test('metaDescription: the owner\'s words, else the made one; one line, 160 at most', () => {
|
|
49
|
+
assert.equal(metaDescription(' Hand-made\n mugs ', 'x'), 'Hand-made mugs');
|
|
50
|
+
assert.equal(metaDescription('', 'Shop online.'), 'Shop online.');
|
|
51
|
+
const long = metaDescription('a'.repeat(300), '');
|
|
52
|
+
assert.equal(long.length, 160);
|
|
53
|
+
assert.ok(long.endsWith('...'));
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('an empty shop is noindex and not in the sitemap; with a product on sale it is both indexed and listed', async () => {
|
|
57
|
+
let res = await app.inject({method: 'PUT', url: '/settings', payload: {shopIntro: ''}});
|
|
58
|
+
assert.equal(res.statusCode, 200, res.body);
|
|
59
|
+
|
|
60
|
+
res = await pub.inject({method: 'GET', url: '/shop'});
|
|
61
|
+
assert.equal(res.statusCode, 200);
|
|
62
|
+
assert.match(res.headers['x-robots-tag'] || '', /noindex/, 'the header');
|
|
63
|
+
assert.match(metaOf(res.body, 'robots') || '', /noindex/, 'and the meta tag');
|
|
64
|
+
assert.ok(metaOf(res.body, 'description'), 'still described');
|
|
65
|
+
assert.deepEqual(await sitemap(), [], 'nothing on sale: not in the sitemap');
|
|
66
|
+
|
|
67
|
+
// A draft is not on sale either (unlisted products: the pure test below).
|
|
68
|
+
await app.inject({method: 'POST', url: '/products', payload: {name: 'Draft mug', price: 900, status: 'draft'}});
|
|
69
|
+
assert.match((await pub.inject({method: 'GET', url: '/shop'})).headers['x-robots-tag'] || '', /noindex/);
|
|
70
|
+
assert.deepEqual(await sitemap(), []);
|
|
71
|
+
|
|
72
|
+
res = await app.inject({method: 'POST', url: '/products', payload: {name: 'Blue mug', price: 1200, status: 'active', summary: ''}});
|
|
73
|
+
assert.equal(res.statusCode, 201, res.body);
|
|
74
|
+
res = await pub.inject({method: 'GET', url: '/shop'});
|
|
75
|
+
assert.equal(res.headers['x-robots-tag'], undefined);
|
|
76
|
+
assert.equal(metaOf(res.body, 'robots'), undefined);
|
|
77
|
+
assert.match(metaOf(res.body, 'description'), /^Shop online.*: Blue mug\.$/);
|
|
78
|
+
const listed = await sitemap();
|
|
79
|
+
assert.deepEqual(listed.map(e => e.urlPath), ['/shop', '/shop/blue-mug']);
|
|
80
|
+
|
|
81
|
+
const product = await pub.inject({method: 'GET', url: '/shop/blue-mug'});
|
|
82
|
+
assert.match(metaOf(product.body, 'description'), /^Buy Blue mug/);
|
|
83
|
+
assert.equal(product.headers['x-robots-tag'], undefined);
|
|
84
|
+
|
|
85
|
+
// The owner's introduction wins.
|
|
86
|
+
await app.inject({method: 'PUT', url: '/settings', payload: {shopIntro: 'Hand-thrown mugs from Devon.'}});
|
|
87
|
+
assert.equal(metaOf((await pub.inject({method: 'GET', url: '/shop'})).body, 'description'), 'Hand-thrown mugs from Devon.');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('shopSitemapEntries is pure: the shop\'s own path, products with a usable slug', () => {
|
|
91
|
+
const e = (data, updatedAt = '2031-01-01T00:00:00.000Z') => ({data: {status: 'active', ...data}, meta: {updatedAt}});
|
|
92
|
+
assert.deepEqual(shopSitemapEntries([e({name: 'A', slug: 'a', status: 'draft'}), e({name: 'U', slug: 'u', unlisted: true})], {shopPath: '/store'}), []);
|
|
93
|
+
assert.deepEqual(shopSitemapEntries([e({name: 'A', slug: 'a'}), e({name: 'B', slug: '../b'})], {shopPath: '/store', shopTitle: 'Store'}),
|
|
94
|
+
[{urlPath: '/store', title: 'Store', changefreq: 'daily'}, {urlPath: '/store/a', title: 'A', lastmod: '2031-01-01T00:00:00.000Z'}]);
|
|
95
|
+
});
|
package/public/js/site.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{applyMobileMenu as ne,initCarouselPopup as ae}from"/public/js/mobile-ui.mjs?v=20261016-mobile-options";import{installSmoothCarets as se}from"/public/js/smooth-caret.js";import{decodeBase64Json as R}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as X,applyColour as U,applyPill as ie,applyFloat as re,applyHighlight as W,applyItemHighlight as ce,itemHighlightAttrs as le,isCurrentItem as G,menuAlign as de,applyClasses as O,cssClasses as V,applyEntrance as Y}from"/public/js/menu-decor.mjs?v=20261014-menu-entrance";import{initFloatingMenus as me}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as K,markInvalidFields as Q,showValidationPopup as Z}from"/public/js/forms.js?v=20261015-smooth-caret";import{buildWizardSteps as ue}from"/public/js/form-steps.mjs";import{applyFormClasses as ee,applySubmitButtons as pe,applyWizardButtons as fe}from"/public/js/form-submit.mjs";document.addEventListener("click",p=>{const r=p.target?.closest?.(".dm-banner__dismiss");r&&(p.preventDefault(),r.closest(".dm-banner")?.remove())}),$(()=>{se(document);const p=window.__CMS_NAV__||{},r=window.__CMS_SITE__||{};if(r.autoTheme?.enabled){let o=function(e){const a=(e||"07:00").split(":");return+a[0]*60+(+a[1]||0)},s=function(){const e=new Date,a=e.getHours()*60+e.getMinutes();return a>=o(n.dayStart)&&a<o(n.nightStart)?n.dayTheme:n.nightTheme},t=function(e){const a=n.apply&&n.apply[e]||{theme:e,custom:""};Domma.theme.set(a.theme);for(const l of[...document.body.classList])l.startsWith("dm-custom-")&&document.body.classList.remove(l);a.custom&&document.body.classList.add(a.custom)};const n=r.autoTheme;t(s()),setInterval(()=>t(s()),6e4)}const x=$("#site-navbar");if(x.length&&p.brand){let s=function(u,f=0){return Array.isArray(u)?u.filter(m=>!(m&&(m.type==="spacer"||m.type==="theme-switcher"))).filter(m=>!(m&&m.type==="separator"&&f===0)).map(m=>m&&m.type==="separator"?{divider:!0}:Array.isArray(m?.items)?{...m,items:s(m.items,f+1)}:m):u};const n={...p.brand},o=n.size&&n.size!=="md"?` navbar-brand-${n.size}`:"";if(n.logo||n.icon||n.tagline){let u="";n.logo?u+=`<img src="${n.logo}" class="navbar-brand-logo" alt="${n.text||""}">`:n.icon&&(u+=`<span data-icon="${n.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),n.text&&(u+=`<span class="navbar-brand-text${o}">${n.text}</span>`),n.tagline&&(u+=`<small class="navbar-brand-tagline">${n.tagline}</small>`),n.html=u}else o&&n.text&&(n.html=`<span class="navbar-brand-text${o}">${n.text}</span>`);const t=s(p.items||[]),e=p.position==="floating",a=p.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:n,items:t,variant:p.variant||"dark",position:e?"static":p.position||"sticky",collapsible:!0,appearOnHover:!!p.appearOnHover}),Domma.icons.scan("#site-navbar");const l=x.get(0);ne(l,p.mobile);const h=()=>{if(!a)return;const f=l.querySelector('a[aria-current="page"]')?.closest(".navbar-dropdown");f&&!f.classList.contains("open")&&f.querySelector(":scope > .navbar-dropdown-toggle")?.click()};l.classList.add(`dm-nav-align-${de(p)||"centre"}`),a&&x.get(0).classList.add("dm-nav-vertical",p.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left");const i=p.dock||{};a&&!e&&he(l,p.side==="right"),!a&&i.hideOnScroll&&ge(l),W(l,p),Y(l,p),O(l,p.class),e&&(re(x.get(0),p),me(x.get(0).parentNode||document));const c=l.querySelector(".navbar-toggle"),g=l.querySelector(".navbar-collapse");if(c&&g){let u=null;const f=()=>{g.classList.contains("show")&&c.click()},m=()=>{u&&(u.remove(),u=null),document.body.classList.remove("dm-drawer-open")},v=()=>{u||(u=document.createElement("div"),u.className="dm-navbar-backdrop",u.addEventListener("click",f),document.body.appendChild(u),document.body.classList.add("dm-drawer-open"))};c.addEventListener("click",()=>{requestAnimationFrame(()=>{g.classList.contains("show")?(h(),v()):m()})}),g.addEventListener("click",C=>{C.target.closest("a")&&requestAnimationFrame(m)}),document.addEventListener("keydown",C=>{C.key==="Escape"&&g.classList.contains("show")&&f()})}const b=l.querySelector(".navbar-nav");if(b){const u=Array.from(b.children);let f=0;for(const m of p.items||[])if(!(m&&m.type==="separator")){if(m&&m.type==="spacer"){const v=document.createElement("li"),C=["xs","sm","md","lg","xl","flex"].includes(m.size)?m.size:"md";v.className=`dm-menu-spacer dm-menu-spacer--${C}`,v.setAttribute("aria-hidden","true"),b.insertBefore(v,u[f]||null);continue}if(m&&m.type==="theme-switcher"){const v=document.createElement("li");v.className="dm-menu-theme-switcher";const C=document.createElement("span");C.dataset.themeSwitcher="menu",C.dataset.position="inline",v.appendChild(C),b.insertBefore(v,u[f]||null);continue}f++}window.CMSThemeSwitcher?.scan(b)}l.querySelectorAll("[data-path]").forEach(u=>{const f=u.dataset.path.split(".").map(Number),m=f.length>1,v=f.reduce((M,L)=>M?.items?.[L],{items:t});if(!v)return;v.colour&&U(u,v.colour),v.pill&&!m&&ie(u,v.pill),ce(u,v),O(u.closest("li"),v.class);const C=X(v.badge);C&&u.appendChild(C),G(v.url,location.pathname)&&(u.classList.add("active"),u.setAttribute("aria-current","page"))}),h()}const y=$("#site-footer");if(y.length){let e=function(d){return String(d??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},a=function(d){return e(d).replace(/'/g,"'")},l=function(d){if(d&&d.type==="separator")return'<li class="footer-sep"><hr></li>';if(d&&d.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(d.size)?d.size:"md"}" aria-hidden="true"></li>`;if(d&&d.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const I=a(d.url||"#"),A=e(d.text||""),D=Array.isArray(d.items)&&d.items.length?`<ul>${d.items.map(l).join("")}</ul>`:"",z=le(d),te=[z.hover&&` data-menu-item-hover="${a(z.hover)}"`,z.active&&` data-menu-item-active="${a(z.active)}"`].filter(Boolean).join(""),oe=z.accent?` style="--dm-menu-highlight:${a(z.accent)}"`:"",J=V(d.class).join(" ");return`<li${J?` class="${a(J)}"`:""}><a href="${I}"${te}${oe}>${A}</a>${D}</li>`},h=function(){if(!r.footer)return"";const d=Object.keys(o).filter(A=>n[A]);if(!d.length)return"";const I=V(r.footer.socialClass).join(" ");return`<div class="footer-social">${d.map(A=>{const{label:D,svg:z}=o[A];return`<a href="${n[A]}" target="_blank" rel="noopener noreferrer" aria-label="${D}" class="footer-social-link${I?` ${a(I)}`:""}">${z}</a>`}).join("")}</div>`},b=function(d){if(!d||d.type==="separator"||d.type==="spacer")return"";if(d.type==="theme-switcher")return`<li class="cms-footer-col">${l(d).replace(/^<li[^>]*>|<\/li>$/g,"")}</li>`;const I=Array.isArray(d.items)&&d.items.length?`<ul>${d.items.map(l).join("")}</ul>`:"",A=g(d)?`<span class="cms-footer-col-title">${e(d.text||"")}</span>`:`<a class="cms-footer-col-title" href="${a(d.url||"#")}">${e(d.text||"")}</a>`,D=["cms-footer-col",...V(d.class)].join(" ");return`<li class="${a(D)}">${A}${I}</li>`},m=function(d,I,A=!1){return(d||[]).forEach(D=>{D&&(D.type==="separator"||D.type==="spacer"||D.type==="theme-switcher")||(A&&g(D)||I.push(D),Array.isArray(D.items)&&D.items.length&&m(D.items,I))}),I};const n=r.social||{},o={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let s='<div class="footer-inner container">';const t=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""},i=["columns","row"].includes(r.footer?.layout)?r.footer.layout:"auto",c=i==="columns"||i==="auto"&&t.primary.some(d=>Array.isArray(d?.items)&&d.items.length),g=d=>c&&!d.url&&Array.isArray(d.items)&&d.items.length>0;if(c){const d=p.brand||{},I=d.text||r.title||"",A=d.logo?`<img src="${a(d.logo)}" class="cms-footer-brand-logo" alt="">`:d.icon?'<span class="cms-footer-brand-icon"></span>':"",D=String(r.footer?.blurb||"").trim();s='<div class="footer-inner footer-inner--columns container"><div class="cms-footer-top">',s+=`<div class="cms-footer-brand">${I||A?`<a class="cms-footer-brand-name" href="${a(d.url||"/")}">${A}<span>${e(I)}</span></a>`:""}${D?`<p class="cms-footer-blurb">${e(D)}</p>`:""}${h()}</div>`,t.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary footer-nav--columns" aria-label="Footer"><ul>${t.primary.map(b).join("")}</ul></nav>`),s+='</div><div class="cms-footer-bottom">',t.copyright&&(s+=`<p class="cms-footer-copyright">${e(t.copyright)}</p>`),t.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal" aria-label="Legal"><ul>${t.legal.map(l).join("")}</ul></nav>`),s+="</div>"}else t.copyright&&(s+=`<p>${e(t.copyright)}</p>`),t.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${t.primary.map(l).join("")}</ul></nav>`),t.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${t.legal.map(l).join("")}</ul></nav>`),s+=h();s+="</div>";const u=y.get(0).querySelector(":scope > .cms-footer-blocks");u?.remove(),y.html(s),u&&y.get(0).prepend(u),window.CMSThemeSwitcher?.scan(y.get(0));const f=y.get(0).querySelector(".cms-footer-brand-icon");f&&p.brand?.icon&&f.setAttribute("data-icon",p.brand.icon),O(y.get(0),r.footer?.class);const v=[...m(t.primary,[],!0),...m(t.legal,[])];y.get(0).querySelectorAll(".footer-nav a").forEach((d,I)=>{const A=v[I];if(!A)return;A.colour&&U(d,A.colour);const D=X(A.badge);D&&d.appendChild(D),G(A.url,location.pathname)&&(d.classList.add("is-active"),d.setAttribute("aria-current","page"))}),W(y.get(0).querySelector(".footer-nav--primary"),{highlight:t.primaryHighlight}),W(y.get(0).querySelector(".footer-nav--legal"),{highlight:t.legalHighlight}),Y(y.get(0).querySelector(".footer-nav--primary"),{entrance:t.primaryEntrance}),Y(y.get(0).querySelector(".footer-nav--legal"),{entrance:t.legalEntrance}),O(y.get(0).querySelector(".footer-nav--primary"),t.primaryClass),O(y.get(0).querySelector(".footer-nav--legal"),t.legalClass);const M=r.footer?.showMotionToggle!==!1,L=S.get("reduced_motion"),B=r.footer?.motionDefault,P=L!=null?!!L:B==="on"?!0:B==="off"?!1:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),q=r.footer?.motionControl==="checkbox",N=y.get(0).querySelector(".cms-footer-bottom")||y.get(0).querySelector(".footer-inner");if(M&&N){const d=document.createElement("input");d.type="checkbox",d.className=q?"footer-motion-checkbox":"form-switch-input",d.id="dm-motion-switch",d.checked=P,d.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const I=document.createElement("span");I.className=q?"footer-motion-label":"form-switch-label",I.textContent="Reduce motion";const A=document.createElement("label");A.className=q?"footer-motion-check":"form-switch footer-motion-switch",A.title="Reduce motion",A.appendChild(d),A.appendChild(I),N.appendChild(A)}}const k=document.getElementById("site-sidebar");k&&ye(k),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const w=$(".page-body");if(w.length){w.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),w.find(".tabs").each(function(){Domma.elements.tabs(this)}),w.find(".carousel").each(function(){const n={primary:"--dm-primary",secondary:"--dm-secondary",accent:"--dm-primary",text:"--dm-text",surface:"--dm-surface",background:"--dm-background",success:"--dm-success",warning:"--dm-warning",danger:"--dm-danger",info:"--dm-info"},o=h=>{const i=String(h||"").trim();return i?n[i.toLowerCase()]?`var(${n[i.toLowerCase()]})`:CSS.supports("color",i)?i:"":""},s=o(this.dataset.background),t=o(this.dataset.arrowBackground),e=o(this.dataset.arrowColor);s&&(this.style.setProperty("--dm-carousel-background",s),this.classList.add("dm-carousel-custom-background")),t&&this.style.setProperty("--dm-carousel-arrow-background",t),e&&this.style.setProperty("--dm-carousel-arrow-color",e);const a=["top","middle","bottom"].includes(this.dataset.arrowPosition)?this.dataset.arrowPosition:"middle";this.classList.add(`dm-carousel-arrows-${a}`);const l={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide",heightMode:this.dataset.heightMode==="average"?"average":"crop"};if(this.dataset.height){const h=Number(this.dataset.height);Number.isFinite(h)&&h>0&&(l.height=h)}if(this.dataset.animationDuration){const h=parseInt(this.dataset.animationDuration,10);Number.isFinite(h)&&(l.animationDuration=h)}this.dataset.animationEasing&&(l.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(h=>h.cloneNode(!0)),this._dmCarouselOpts=l),this._dmCarousel=Domma.elements.carousel(this,l),ae(this)}),w.find(".dm-countdown").each(function(){const n={autoStart:!0},o=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=t?new Date(+t[1],+t[2]-1,+t[3]).getTime():s?new Date(s).getTime():NaN;Number.isFinite(e)?n.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(n.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const a=/^dd:/i.test(o);n.format=a?"hh:mm:ss":o||(n.duration>=36e5?"hh:mm:ss":"mm:ss");const l=this,h=c=>String(c).padStart(2,"0"),i=c=>{const g=Math.max(0,Math.floor(c/1e3)),b=l.querySelector(".dm-timer-time");b&&(b.textContent=`${h(Math.floor(g/86400))}:${h(Math.floor(g%86400/3600))}:${h(Math.floor(g%3600/60))}:${h(g%60)}`)};a&&(n.onTick=i),Domma.elements.timer(this,n),a&&i(n.duration||0)}),w.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),w.find(".dm-progression").each(function(){const n=Array.from(this.querySelectorAll(".dm-progression-item")).map(t=>{const e={title:t.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:t.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return t.dataset.date&&(e.date=t.dataset.date),t.dataset.status&&(e.status=t.dataset.status),t.dataset.eventIcon&&(e.icon=t.dataset.eventIcon),t.dataset.entryId&&(e._entryId=t.dataset.entryId),e}),o=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",s=Domma.elements.progression(this,{layout:o,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...n.length?{items:n}:{}});if((this.dataset.mode||"timeline")==="timeline"){const t={completed:{label:"Completed",icon:"check-circle",tone:"success"},planned:{label:"Planned",icon:"circle",tone:"secondary"},"in-progress":{label:"In progress",icon:"clock",tone:"primary"},blocked:{label:"Blocked",icon:"alert-circle",tone:"danger"}};this.querySelectorAll(".dm-progression-item").forEach((e,a)=>{const l=n[a];if(!l)return;const h=e.querySelector(".dm-progression-title");if(l.icon&&h){const c=document.createElement("span");c.dataset.icon=l.icon,c.style.cssText="display:inline-flex;vertical-align:middle;margin-right:.4em",c.setAttribute("aria-hidden","true"),h.prepend(c)}const i=t[l.status];if(i&&h){const c=document.createElement("span");c.className=`badge badge-${i.tone} cms-timeline-status`,c.style.cssText="display:inline-flex;align-items:center;gap:.35em;margin:.4rem 0";const g=document.createElement("span");g.dataset.icon=i.icon,g.dataset.iconSize="14",g.setAttribute("aria-hidden","true"),c.append(g,document.createTextNode(i.label)),h.after(c)}})}Domma.icons.scan(this),n.length&&(this._dmCtx={instance:s,items:n})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(n=>{const o=n.dataset.revealMode||"stagger",s=n.dataset.revealAnimation||"slide-up",t=parseInt(n.dataset.revealDuration,10)||400,e=parseInt(n.dataset.revealStagger,10)||60,a=parseInt(n.dataset.revealDelay,10)||0,l=n.dataset.revealDirection==="rtl",h=Array.from(n.children),i={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};h.forEach((c,g)=>{c.style.opacity="0",c.style.transform=i[s]||"",c.style.transition=`opacity ${t}ms ease, transform ${t}ms ease`;const b=l?h.length-1-g:g;c.style.transitionDelay=o==="stagger"?`${a+b*e}ms`:`${a}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const c=new IntersectionObserver(g=>{g.forEach(b=>{b.isIntersecting&&(b.target.offsetWidth,b.target.style.opacity="1",b.target.style.transform="none",c.unobserve(b.target))})},{threshold:.1});h.forEach(g=>c.observe(g))}))}),w.find(".card[data-collapsible]").each(function(){const n=this.querySelector(".card-header");n&&n.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),w.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const n=this.dataset.soTarget,o=document.getElementById(n);if(!o)return;const s=E.slideover({title:o.dataset.soTitle||"",size:o.dataset.soSize||"md",position:o.dataset.soPosition||"right"});o.style.display="",s.setContent(o),s.open()})})}if(typeof $.setup=="function"){const n=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(o=>{try{const s=R(o.dataset.config);Object.assign(n,s)}catch{}}),Object.keys(n).length>0){const o={};for(const[s,t]of Object.entries(n)){const e=t?.events?.click,{confirm:a,toast:l,alert:h,prompt:i,...c}=e||{};a||l||h||i?($(s).on("click",async function(b){if(b.preventDefault(),a&&!await E.confirm(a))return;let u=null;if(!(i&&(u=await E.prompt(i,{inputPlaceholder:c.promptPlaceholder||"",inputValue:c.promptDefault||""}),u===null))){if(c.target){const f=$(c.target);c.toggleClass&&f.toggleClass(c.toggleClass),c.addClass&&f.addClass(c.addClass),c.removeClass&&f.removeClass(c.removeClass),u!==null&&(c.setText&&f.text(u),c.setVal&&f.val(u),c.setAttr&&f.attr(c.setAttr,u))}c.href&&(window.location.href=c.href),l&&E.toast(l,{type:c.toastType||"success"}),h&&E.alert(h)}}),Object.keys(c).length&&(o[s]={...t,events:{...t.events,click:c}})):o[s]=t}$.setup(o)}}w.length&&j(w.get(0))}),window.wireCTAButtons=j;function j(p){p.querySelectorAll(".dm-cta-trigger").forEach(r=>{r.__ctaWired||(r.__ctaWired=!0,r.addEventListener("click",async()=>{const x=r.dataset.action,y=r.dataset.entry,k=r.dataset.confirm;let w=S.get("auth_token");if(!w){E.toast("Please log in to perform this action.",{type:"warning"});return}if(k&&!await E.confirm(k))return;const n=Array.from(r.childNodes).map(s=>s.cloneNode(!0));r.disabled=!0,r.textContent="Running\u2026";const o=s=>fetch(`/api/actions/${x}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(r.dataset.scope?{entryId:y,scope:r.dataset.scope}:{entryId:y})});try{let s=await o(w);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const a=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(a.ok){const{token:l}=await a.json();S.set("auth_token",l),w=l,s=await o(w)}}}const t=await s.json().catch(()=>({}));if(!s.ok||t.success===!1)throw new Error(t.error||t.message||`Error ${s.status}`);E.toast(t.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{r.disabled=!1,r.textContent="",n.forEach(s=>r.appendChild(s)),Domma.icons.scan(r)}}))})}(function(){const r=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!r.length)return;const x=S.get("auth_token");function y(w,n){const o=document.createElement("div");o.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(n){s.appendChild(document.createTextNode("Please "));const t=document.createElement("a");t.href="/login",t.textContent="sign in",s.appendChild(t),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=w;return o.appendChild(s),o}function k(w,n){const o=document.createElement("template");o.innerHTML=n||"",w.replaceWith(o.content)}r.forEach(async w=>{const n=w.dataset.collectionAttrs;if(!n)return;if(!x){w.replaceChildren(y("",!0));return}const o=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:n})});try{let s=x,t=await o(s);if(t.status===401){const a=S.get("auth_refresh_token");if(a){const l=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:a})});if(l.ok){const{token:h}=await l.json();S.set("auth_token",h),s=h,t=await o(s)}}}if(!t.ok){const{error:a}=await t.json().catch(()=>({}));w.replaceChildren(y(a||"Unable to load entries.",!1));return}const{html:e}=await t.json();k(w,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{w.replaceChildren(y("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),j(document.body)},100)})(),(function(){const r=document.querySelectorAll("[data-collection-table]");!r.length||typeof T>"u"||!T.create||r.forEach(x=>{let y;try{y=R(x.dataset.payload)}catch{return}const{columns:k,rows:w,search:n,sortable:o,exportable:s,pageSize:t,empty:e,ctaConfig:a,slug:l,exportCfg:h}=y;if(!k?.length)return;if(a){const g=k.findIndex(b=>b.key==="_cta");g!==-1&&(k[g]={key:"_cta",title:"",render:(b,u)=>{const f=document.createElement("button");if(f.className=`btn btn-${a.style||"primary"} dm-cta-trigger`,f.dataset.action=a.action||"",a.scope&&(f.dataset.scope=a.scope),f.dataset.entry=u._entryId||"",a.confirm&&(f.dataset.confirm=a.confirm),a.icon){const m=document.createElement("span");m.dataset.icon=a.icon,f.appendChild(m),f.appendChild(document.createTextNode(" "))}return f.appendChild(document.createTextNode(a.label||"Run")),f}})}const i="col-table-"+Math.random().toString(36).slice(2,7),c=document.createElement("div");c.id=i,x.replaceChildren(c),T.create("#"+i,{data:w,columns:k,search:n,sortable:o,exportable:s,pageSize:t,emptyMessage:e}),a&&j(c),x._dmTable={columns:k,rows:w,slug:l,exportCfg:h,render(g){T.create("#"+i,{data:g,columns:k,search:n,sortable:o,exportable:s,pageSize:t,emptyMessage:e}),a&&j(c)}}})})(),(function(){const r=document.querySelectorAll("[data-form-inline]");if(!r.length||typeof F>"u")return;function x(o){const s=o&&o.logic;return!!(s&&(s.visibility||s.requirement))}function y(o,s){const t={};return(o||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),l=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":a?"chooser":e.type,h={...e.formConfig||{}};h.span==="full"&&s&&(h.span=s);const i={type:l,required:x(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...h}};e.minLength!==void 0&&(i.minLength=e.minLength),e.maxLength!==void 0&&(i.maxLength=e.maxLength),e.min!==void 0&&(i.min=e.min),e.max!==void 0&&(i.max=e.max),a&&(e.variant&&(i.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(i.multiple=!0),e.density&&(i.density=e.density),e.columns&&(i.columns=e.columns),e.accent&&(i.accent=e.accent),e.accentStyle&&(i.accentStyle=e.accentStyle),e.glow&&(i.glow=!0),e.glowColour&&(i.glowColour=e.glowColour),e.shadow&&(i.shadow=e.shadow),e.shadowColour&&(i.shadowColour=e.shadowColour)),t[e.name]=i}),t}function k(o){const s={};return(o||[]).forEach(t=>{if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(s[t.name]=typeof e=="object"?e.value:e)}}),s}function w(o,s){(s||[]).forEach(t=>{if(t.type!=="date"||!t.name)return;const e=o.querySelector(`[name="${t.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function n(o,s,t){let e=o.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",o.appendChild(e)),e.textContent=s,e.style.cssText=t?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}r.forEach(o=>{let s;try{s=R(o.dataset.formInline)}catch{return}const t=s.fields||[],e=s.settings||{},a=Number(e.columns)===3?3:2,l=e.layout||"grid",h=t.some(f=>f.type==="page-break"),i=async f=>{if(o.dataset.triggerBlocked==="true"){const m=o._formLogicRuntime,v=m&&m.submitBlock?m.submitBlock().reasons:[];n(o,v.join(" ")||"This form cannot be submitted yet.",!0);const C=new Error("Blocked by a form trigger");throw C.formSubmitFailed=!0,C}try{const m=o.querySelector(".fb-form-honeypot"),v=m?.querySelector('input[type="text"]')||null,C=m?.querySelector('[name="_t"]')||null,M=Object.assign({},f);delete M._t,m?.dataset.hpName&&delete M[m.dataset.hpName],v!==null&&(M._hp=v.value),C!==null&&(M._t=C.value);const L=await H.post(`/api/forms/submit/${s.slug}`,M);if(L&&L.error){n(o,L.error,!0);const B=new Error(L.error);throw B.formSubmitFailed=!0,B}if(L?.redirect){window.location.href=L.redirect;return}for(;o.firstChild;)o.removeChild(o.firstChild);n(o,L?.message||e.successMessage||"Thank you for your submission.",!1)}catch(m){throw m.formSubmitFailed||n(o,m.message||"Submission failed. Please try again.",!0),m}},c=Date.now();function g(f){const m=f.querySelector("form");if(!m||m.querySelector(".fb-form-honeypot"))return;const v=document.createElement("div");v.className="fb-form-honeypot",v.setAttribute("aria-hidden","true");const C=document.createElement("input");C.name=m.querySelector('[name="website"]')?"_website":"website",v.dataset.hpName=C.name,C.type="text",C.tabIndex=-1,C.autocomplete="url",C.placeholder="https://",v.appendChild(C);const M=document.createElement("input");M.name="_t",M.type="hidden",M.value=c,v.appendChild(M),m.appendChild(v)}function b(f){if(!window.FormLogicEngine||!t.some(v=>v.logic||Array.isArray(v.triggers)&&v.triggers.length))return null;const m=new window.FormLogicEngine.FormLogicRuntime(s,o,f?{baseValues:f}:void 0);if(m.init(),o._formLogicRuntime=m,o._formLogicObserved)return m;if(o._formLogicObserved=!0,o.parentNode&&typeof MutationObserver<"u"){const v=new MutationObserver(function(C){for(const M of C)for(const L of M.removedNodes)if(L===o||L.nodeType===1&&L.contains&&L.contains(o)){o._formLogicRuntime&&o._formLogicRuntime.destroy(),v.disconnect();return}});v.observe(o.parentNode,{childList:!0,subtree:!1}),o._formLogicObserver=v}return m}let u=!1;if(o.addEventListener("dm-form-end",f=>{const m=f.detail?.validation;if(m&&!m.valid){Q(o,m.missing),Z(m);return}u||(u=!0,i(f.detail?.values||{}).catch(()=>{}).finally(()=>{u=!1}))}),h&&F.wizard){const f=ue(t,s.title),m=f.map(q=>({title:q.title,description:q.description,fields:y(q.fields,a)})),v=f.map(q=>q.fields);let C=0,M=null,L=null;const B=q=>{const N=window.FormLogicEngine;if(!N||!N.validateFields)return;const d=N.validateFields(o,v[C]||[]);d.valid||(q.preventDefault(),q.stopImmediatePropagation(),Q(o,d.missing),Z(d))},P=()=>{const q=v[C]||t;fe(o,e),ee(o,e,q),w(o,q),K(o,q),e.honeypot!==!1&&g(o),M&&M.destroy(),M=b(L?.getStepData?L.getStepData():void 0),o.querySelectorAll(".wizard-next, .wizard-submit").forEach(N=>N.addEventListener("click",B,!0))};L=F.wizard(o,{schema:{steps:m},layout:l,columns:a,finishText:e.submitText||"Finish",onSubmit:i,onStepChange:q=>{C=q,setTimeout(P,0)}}),o.addEventListener("dm-form-trigger",q=>{if(q.detail?.type!=="goto-step"||!L?.goToStep)return;const N=Number(q.detail.action.step);!Number.isFinite(N)||N<0||N>=m.length||N!==C&&L.goToStep(N)}),Promise.resolve(L).then(P)}else if(F.render){const f=F.render(o,y(t,a),k(t),{submitText:e.submitText||"Submit",layout:l,columns:a,onSubmit:i});Promise.resolve(f).then(function(){pe(o,e,l),ee(o,e,t),w(o,t),K(o,t),e.honeypot!==!1&&g(o),b()})}})})();function he(p,r){const x=document.body,y=x.classList,k=new Set((x.dataset.railSite||"").split(" ").filter(Boolean)),w=()=>window.matchMedia("(min-width: 993px)").matches;p.querySelectorAll(".navbar-link, .navbar-dropdown-toggle").forEach(a=>{const l=a.textContent.trim();l&&(a.setAttribute("title",l),a.querySelector("svg, [data-icon]")||(a.dataset.initial=l.charAt(0).toUpperCase()))});const n=document.createElement("button");n.type="button",n.className="dm-nav-collapse-toggle";const o=()=>{const a=y.contains("dm-vnav-collapsed");n.setAttribute("aria-pressed",String(a)),n.setAttribute("aria-label",a?"Expand menu":"Collapse menu"),n.title=n.getAttribute("aria-label");const l=r?"chevrons-left":"chevrons-right",h=r?"chevrons-right":"chevrons-left";n.innerHTML=`<span data-icon="${a?l:h}"></span>`,window.Domma&&Domma.icons&&Domma.icons.scan(n)},s=a=>{y.toggle("dm-vnav-collapsed",a),S.set("nav_collapsed",a),o()};n.addEventListener("click",()=>s(!y.contains("dm-vnav-collapsed"))),o();const t=p.querySelector(".navbar-container")||p;t.insertBefore(n,t.firstChild?.nextSibling||null);const e=a=>{y.toggle("dm-vnav-autohide",a),y.toggle("dm-vnav-collapsible",!a&&k.has("collapsible")),a?y.remove("dm-vnav-collapsed"):k.has("collapsible")&&S.get("nav_collapsed")===!0&&y.add("dm-vnav-collapsed"),p.classList.remove("dm-nav-revealed"),o()};p.addEventListener("pointerdown",a=>{y.contains("dm-vnav-autohide")&&a.pointerType!=="mouse"&&!p.classList.contains("dm-nav-revealed")&&(p.classList.add("dm-nav-revealed"),a.preventDefault())}),document.addEventListener("pointerdown",a=>{p.contains(a.target)||p.classList.remove("dm-nav-revealed")}),window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const a=y.contains("dm-vnav-autohide"),l=y.contains("dm-vnav-collapsed"),h=S.has("nav_autohide")||S.has("nav_collapsed");return[{header:"Menu"},{label:l?"Expand menu":"Collapse to icons",icon:l?"maximize":"minimize",disabled:!w()||a||!k.has("collapsible"),action:()=>s(!l)},{label:a?"Keep on screen":"Hide when not in use",icon:a?"eye":"eye-off",disabled:!w(),action:()=>{S.set("nav_autohide",!a),e(!a)}},{type:"divider"},{label:"Reset to the site's setting",icon:"refresh",disabled:!h,action:()=>{S.remove("nav_autohide"),S.remove("nav_collapsed"),e(k.has("autohide")),y.toggle("dm-vnav-collapsed",!k.has("autohide")&&k.has("start-collapsed")),o()}}]}})}function ge(p){p.classList.add("dm-nav-scroll-hide");let r=window.scrollY,x=!1;window.addEventListener("scroll",()=>{x||(x=!0,requestAnimationFrame(()=>{x=!1;const y=window.scrollY,k=p.matches(":focus-within")||p.querySelector(".navbar-dropdown.open, .navbar-collapse.show");y>r&&y>p.offsetHeight&&!k?p.classList.add("dm-nav-scrolled-away"):y<r&&p.classList.remove("dm-nav-scrolled-away"),r=y}))},{passive:!0})}function ye(p){let r={};try{r=JSON.parse(p.dataset.contents||"{}")}catch{}const x=p.closest(".site-main"),y=document.querySelector(".site-content"),k=new Set(String(r.exclude||"").split(",").map(i=>i.trim().toLowerCase()).filter(Boolean)),w=i=>!i.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),n=i=>(y?[...y.querySelectorAll(i)]:[]).filter(w).filter(c=>!k.has(c.textContent.trim().toLowerCase())),o=r.headings==="h2"?n("h2"):r.headings==="h3"?n("h3"):r.headings==="h2h3"?n("h2, h3"):n("h2").length?n("h2"):n("h3");if(!o.length){x?.classList.add("no-sidebar-items");return}const s=new Set([...document.querySelectorAll("[id]")].map(i=>i.id)),t=document.createElement("nav");t.className="dm-contents",t.setAttribute("aria-label",r.title||"Page contents"),r.hover&&(t.dataset.menuHover=r.hover),r.selected&&(t.dataset.menuActive=r.selected),r.accent&&t.style.setProperty("--dm-menu-highlight",r.accent.startsWith("#")?r.accent:`var(--dm-${r.accent})`),r.font&&(t.style.fontFamily=r.font),r.fontSize&&(t.style.fontSize=r.fontSize),r.fontWeight&&(t.style.fontWeight=r.fontWeight);const e=document.createElement("div");e.className="dm-contents-head";const a=document.createElement("p");a.className="dm-contents-title",a.textContent=r.title||"",e.appendChild(a),t.appendChild(e);const l=document.createElement("ol");l.className="dm-contents-list"+(r.numbered?" is-numbered":"");const h=[];for(const i of o){if(!i.id){const b=(i.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let u=b;for(let f=2;s.has(u);f++)u=`${b}-${f}`;s.add(u),i.id=u}const c=document.createElement("li");c.className=`dm-contents-item dm-contents-${i.tagName.toLowerCase()}`;const g=document.createElement("a");g.href=`#${i.id}`,g.textContent=i.textContent.trim(),c.appendChild(g),l.appendChild(c),h.push([i,g])}if(t.appendChild(l),p.replaceChildren(t),r.scrollSpy!==!1&&"IntersectionObserver"in window){const i=new Map,c=()=>{const b=h.find(([u])=>i.get(u))||null;h.forEach(([,u])=>{const f=b&&u===b[1];u.classList.toggle("is-active",!!f),f?u.setAttribute("aria-current","location"):u.removeAttribute("aria-current")})},g=new IntersectionObserver(b=>{b.forEach(u=>i.set(u.target,u.isIntersecting)),c()},{rootMargin:"-80px 0px -60% 0px"});h.forEach(([b])=>g.observe(b))}if(x?.classList.contains("contents-collapsible")){const i=document.createElement("button");i.type="button",i.className="dm-contents-toggle";const c=()=>{const g=x.classList.contains("contents-collapsed");i.setAttribute("aria-expanded",String(!g)),i.setAttribute("aria-label",g?"Show the contents":"Hide the contents"),i.title=i.getAttribute("aria-label"),i.innerHTML=`<span data-icon="${g?"list":"x"}"></span>`,window.Domma?.icons&&Domma.icons.scan(i)};i.addEventListener("click",()=>{S.set("contents_collapsed",x.classList.toggle("contents-collapsed")),c()}),c(),e.insertBefore(i,e.firstChild)}if(x?.classList.contains("contents-floating")&&r.movable){t.classList.add("is-movable");const i=S.get("contents_position");i&&Number.isFinite(i.x)&&Object.assign(p.style,{left:`${i.x}px`,top:`${i.y}px`,right:"auto",bottom:"auto"}),e.addEventListener("pointerdown",c=>{if(c.target.closest("button"))return;const g=p.getBoundingClientRect(),b=c.clientX-g.left,u=c.clientY-g.top,f=v=>{const C=Math.max(0,Math.min(window.innerWidth-g.width,v.clientX-b)),M=Math.max(0,Math.min(window.innerHeight-40,v.clientY-u));Object.assign(p.style,{left:`${C}px`,top:`${M}px`,right:"auto",bottom:"auto"})},m=()=>{document.removeEventListener("pointermove",f),S.set("contents_position",{x:parseInt(p.style.left,10),y:parseInt(p.style.top,10)})};document.addEventListener("pointermove",f),document.addEventListener("pointerup",m,{once:!0})})}window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const i=x?.classList.contains("contents-collapsible"),c=x?.classList.contains("contents-collapsed"),g=h.find(([,b])=>b.classList.contains("is-active"));return[{header:"Contents"},...i?[{label:c?"Show the contents":"Collapse to a button",icon:c?"list":"minimize",action:()=>p.querySelector(".dm-contents-toggle")?.click()}]:[],{label:"Copy a link to this section",icon:"link",disabled:!g,action:async()=>{const b=`${location.origin}${location.pathname}#${g[0].id}`;try{await _.copyToClipboard(b),E.toast("Link copied.",{type:"success"})}catch{E.toast("Could not copy the link.",{type:"error"})}}},{label:"Back to the top",icon:"arrow-up",action:()=>window.scrollTo({top:0,behavior:"smooth"})}]}}),x?.classList.contains("contents-autohide")&&(p.addEventListener("pointerdown",i=>{i.pointerType!=="mouse"&&!p.classList.contains("is-revealed")&&(p.classList.add("is-revealed"),i.preventDefault())}),document.addEventListener("pointerdown",i=>{p.contains(i.target)||p.classList.remove("is-revealed")}))}
|
|
1
|
+
import{applyMobileMenu as ne,initCarouselPopup as ae}from"/public/js/mobile-ui.mjs?v=20261016-mobile-options";import{installSmoothCarets as se}from"/public/js/smooth-caret.js";import{decodeBase64Json as R}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as X,applyColour as U,applyPill as ie,applyFloat as re,applyHighlight as W,applyItemHighlight as ce,itemHighlightAttrs as le,isCurrentItem as G,menuAlign as de,applyClasses as O,cssClasses as V,applyEntrance as Y}from"/public/js/menu-decor.mjs?v=20261014-menu-entrance";import{initFloatingMenus as me}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as K,markInvalidFields as Q,showValidationPopup as Z}from"/public/js/forms.js?v=20261015-smooth-caret";import{buildWizardSteps as ue}from"/public/js/form-steps.mjs";import{applyFormClasses as ee,applySubmitButtons as pe,applyWizardButtons as fe}from"/public/js/form-submit.mjs";document.addEventListener("click",p=>{const r=p.target?.closest?.(".dm-banner__dismiss");r&&(p.preventDefault(),r.closest(".dm-banner")?.remove())}),$(()=>{se(document);const p=window.__CMS_NAV__||{},r=window.__CMS_SITE__||{};if(r.autoTheme?.enabled){let o=function(e){const a=(e||"07:00").split(":");return+a[0]*60+(+a[1]||0)},s=function(){const e=new Date,a=e.getHours()*60+e.getMinutes();return a>=o(n.dayStart)&&a<o(n.nightStart)?n.dayTheme:n.nightTheme},t=function(e){const a=n.apply&&n.apply[e]||{theme:e,custom:""};Domma.theme.set(a.theme);for(const l of[...document.body.classList])l.startsWith("dm-custom-")&&document.body.classList.remove(l);a.custom&&document.body.classList.add(a.custom)};const n=r.autoTheme;t(s()),setInterval(()=>t(s()),6e4)}const x=$("#site-navbar");if(x.length&&p.brand){let s=function(u,f=0){return Array.isArray(u)?u.filter(m=>!(m&&(m.type==="spacer"||m.type==="theme-switcher"))).filter(m=>!(m&&m.type==="separator"&&f===0)).map(m=>m&&m.type==="separator"?{divider:!0}:Array.isArray(m?.items)?{...m,items:s(m.items,f+1)}:m):u};const n={...p.brand},o=n.size&&n.size!=="md"?` navbar-brand-${n.size}`:"";if(n.logo||n.icon||n.tagline){let u="";n.logo?u+=`<img src="${n.logo}" class="navbar-brand-logo" alt="${n.text||""}">`:n.icon&&(u+=`<span data-icon="${n.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),n.text&&(u+=`<span class="navbar-brand-text${o}">${n.text}</span>`),n.tagline&&(u+=`<small class="navbar-brand-tagline">${n.tagline}</small>`),n.html=u}else o&&n.text&&(n.html=`<span class="navbar-brand-text${o}">${n.text}</span>`);const t=s(p.items||[]),e=p.position==="floating",a=p.orientation==="vertical";x.get(0).querySelector(":scope > .cms-nojs-links")?.remove(),Domma.elements.navbar("#site-navbar",{brand:n,items:t,variant:p.variant||"dark",position:e?"static":p.position||"sticky",collapsible:!0,appearOnHover:!!p.appearOnHover}),Domma.icons.scan("#site-navbar");const l=x.get(0);ne(l,p.mobile);const h=()=>{if(!a)return;const f=l.querySelector('a[aria-current="page"]')?.closest(".navbar-dropdown");f&&!f.classList.contains("open")&&f.querySelector(":scope > .navbar-dropdown-toggle")?.click()};l.classList.add(`dm-nav-align-${de(p)||"centre"}`),a&&x.get(0).classList.add("dm-nav-vertical",p.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left");const i=p.dock||{};a&&!e&&he(l,p.side==="right"),!a&&i.hideOnScroll&&ge(l),W(l,p),Y(l,p),O(l,p.class),e&&(re(x.get(0),p),me(x.get(0).parentNode||document));const c=l.querySelector(".navbar-toggle"),g=l.querySelector(".navbar-collapse");if(c&&g){let u=null;const f=()=>{g.classList.contains("show")&&c.click()},m=()=>{u&&(u.remove(),u=null),document.body.classList.remove("dm-drawer-open")},v=()=>{u||(u=document.createElement("div"),u.className="dm-navbar-backdrop",u.addEventListener("click",f),document.body.appendChild(u),document.body.classList.add("dm-drawer-open"))};c.addEventListener("click",()=>{requestAnimationFrame(()=>{g.classList.contains("show")?(h(),v()):m()})}),g.addEventListener("click",C=>{C.target.closest("a")&&requestAnimationFrame(m)}),document.addEventListener("keydown",C=>{C.key==="Escape"&&g.classList.contains("show")&&f()})}const b=l.querySelector(".navbar-nav");if(b){const u=Array.from(b.children);let f=0;for(const m of p.items||[])if(!(m&&m.type==="separator")){if(m&&m.type==="spacer"){const v=document.createElement("li"),C=["xs","sm","md","lg","xl","flex"].includes(m.size)?m.size:"md";v.className=`dm-menu-spacer dm-menu-spacer--${C}`,v.setAttribute("aria-hidden","true"),b.insertBefore(v,u[f]||null);continue}if(m&&m.type==="theme-switcher"){const v=document.createElement("li");v.className="dm-menu-theme-switcher";const C=document.createElement("span");C.dataset.themeSwitcher="menu",C.dataset.position="inline",v.appendChild(C),b.insertBefore(v,u[f]||null);continue}f++}window.CMSThemeSwitcher?.scan(b)}l.querySelectorAll("[data-path]").forEach(u=>{const f=u.dataset.path.split(".").map(Number),m=f.length>1,v=f.reduce((q,L)=>q?.items?.[L],{items:t});if(!v)return;v.colour&&U(u,v.colour),v.pill&&!m&&ie(u,v.pill),ce(u,v),O(u.closest("li"),v.class);const C=X(v.badge);C&&u.appendChild(C),G(v.url,location.pathname)&&(u.classList.add("active"),u.setAttribute("aria-current","page"))}),h()}const y=$("#site-footer");if(y.length){let e=function(d){return String(d??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},a=function(d){return e(d).replace(/'/g,"'")},l=function(d){if(d&&d.type==="separator")return'<li class="footer-sep"><hr></li>';if(d&&d.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(d.size)?d.size:"md"}" aria-hidden="true"></li>`;if(d&&d.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const I=a(d.url||"#"),A=e(d.text||""),D=Array.isArray(d.items)&&d.items.length?`<ul>${d.items.map(l).join("")}</ul>`:"",z=le(d),te=[z.hover&&` data-menu-item-hover="${a(z.hover)}"`,z.active&&` data-menu-item-active="${a(z.active)}"`].filter(Boolean).join(""),oe=z.accent?` style="--dm-menu-highlight:${a(z.accent)}"`:"",J=V(d.class).join(" ");return`<li${J?` class="${a(J)}"`:""}><a href="${I}"${te}${oe}>${A}</a>${D}</li>`},h=function(){if(!r.footer)return"";const d=Object.keys(o).filter(A=>n[A]);if(!d.length)return"";const I=V(r.footer.socialClass).join(" ");return`<div class="footer-social">${d.map(A=>{const{label:D,svg:z}=o[A];return`<a href="${n[A]}" target="_blank" rel="noopener noreferrer" aria-label="${D}" class="footer-social-link${I?` ${a(I)}`:""}">${z}</a>`}).join("")}</div>`},b=function(d){if(!d||d.type==="separator"||d.type==="spacer")return"";if(d.type==="theme-switcher")return`<li class="cms-footer-col">${l(d).replace(/^<li[^>]*>|<\/li>$/g,"")}</li>`;const I=Array.isArray(d.items)&&d.items.length?`<ul>${d.items.map(l).join("")}</ul>`:"",A=g(d)?`<span class="cms-footer-col-title">${e(d.text||"")}</span>`:`<a class="cms-footer-col-title" href="${a(d.url||"#")}">${e(d.text||"")}</a>`,D=["cms-footer-col",...V(d.class)].join(" ");return`<li class="${a(D)}">${A}${I}</li>`},m=function(d,I,A=!1){return(d||[]).forEach(D=>{D&&(D.type==="separator"||D.type==="spacer"||D.type==="theme-switcher")||(A&&g(D)||I.push(D),Array.isArray(D.items)&&D.items.length&&m(D.items,I))}),I};const n=r.social||{},o={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let s='<div class="footer-inner container">';const t=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""},i=["columns","row"].includes(r.footer?.layout)?r.footer.layout:"auto",c=i==="columns"||i==="auto"&&t.primary.some(d=>Array.isArray(d?.items)&&d.items.length),g=d=>c&&!d.url&&Array.isArray(d.items)&&d.items.length>0;if(c){const d=p.brand||{},I=d.text||r.title||"",A=d.logo?`<img src="${a(d.logo)}" class="cms-footer-brand-logo" alt="">`:d.icon?'<span class="cms-footer-brand-icon"></span>':"",D=String(r.footer?.blurb||"").trim();s='<div class="footer-inner footer-inner--columns container"><div class="cms-footer-top">',s+=`<div class="cms-footer-brand">${I||A?`<a class="cms-footer-brand-name" href="${a(d.url||"/")}">${A}<span>${e(I)}</span></a>`:""}${D?`<p class="cms-footer-blurb">${e(D)}</p>`:""}${h()}</div>`,t.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary footer-nav--columns" aria-label="Footer"><ul>${t.primary.map(b).join("")}</ul></nav>`),s+='</div><div class="cms-footer-bottom">',t.copyright&&(s+=`<p class="cms-footer-copyright">${e(t.copyright)}</p>`),t.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal" aria-label="Legal"><ul>${t.legal.map(l).join("")}</ul></nav>`),s+="</div>"}else t.copyright&&(s+=`<p>${e(t.copyright)}</p>`),t.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${t.primary.map(l).join("")}</ul></nav>`),t.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${t.legal.map(l).join("")}</ul></nav>`),s+=h();s+="</div>",y.get(0).querySelector(":scope > .cms-nojs-links")?.remove();const u=y.get(0).querySelector(":scope > .cms-footer-blocks");u?.remove(),y.html(s),u&&y.get(0).prepend(u),window.CMSThemeSwitcher?.scan(y.get(0));const f=y.get(0).querySelector(".cms-footer-brand-icon");f&&p.brand?.icon&&f.setAttribute("data-icon",p.brand.icon),O(y.get(0),r.footer?.class);const v=[...m(t.primary,[],!0),...m(t.legal,[])];y.get(0).querySelectorAll(".footer-nav a").forEach((d,I)=>{const A=v[I];if(!A)return;A.colour&&U(d,A.colour);const D=X(A.badge);D&&d.appendChild(D),G(A.url,location.pathname)&&(d.classList.add("is-active"),d.setAttribute("aria-current","page"))}),W(y.get(0).querySelector(".footer-nav--primary"),{highlight:t.primaryHighlight}),W(y.get(0).querySelector(".footer-nav--legal"),{highlight:t.legalHighlight}),Y(y.get(0).querySelector(".footer-nav--primary"),{entrance:t.primaryEntrance}),Y(y.get(0).querySelector(".footer-nav--legal"),{entrance:t.legalEntrance}),O(y.get(0).querySelector(".footer-nav--primary"),t.primaryClass),O(y.get(0).querySelector(".footer-nav--legal"),t.legalClass);const q=r.footer?.showMotionToggle!==!1,L=S.get("reduced_motion"),B=r.footer?.motionDefault,P=L!=null?!!L:B==="on"?!0:B==="off"?!1:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),M=r.footer?.motionControl==="checkbox",N=y.get(0).querySelector(".cms-footer-bottom")||y.get(0).querySelector(".footer-inner");if(q&&N){const d=document.createElement("input");d.type="checkbox",d.className=M?"footer-motion-checkbox":"form-switch-input",d.id="dm-motion-switch",d.checked=P,d.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const I=document.createElement("span");I.className=M?"footer-motion-label":"form-switch-label",I.textContent="Reduce motion";const A=document.createElement("label");A.className=M?"footer-motion-check":"form-switch footer-motion-switch",A.title="Reduce motion",A.appendChild(d),A.appendChild(I),N.appendChild(A)}}const k=document.getElementById("site-sidebar");k&&ye(k),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const w=$(".page-body");if(w.length){w.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),w.find(".tabs").each(function(){Domma.elements.tabs(this)}),w.find(".carousel").each(function(){const n={primary:"--dm-primary",secondary:"--dm-secondary",accent:"--dm-primary",text:"--dm-text",surface:"--dm-surface",background:"--dm-background",success:"--dm-success",warning:"--dm-warning",danger:"--dm-danger",info:"--dm-info"},o=h=>{const i=String(h||"").trim();return i?n[i.toLowerCase()]?`var(${n[i.toLowerCase()]})`:CSS.supports("color",i)?i:"":""},s=o(this.dataset.background),t=o(this.dataset.arrowBackground),e=o(this.dataset.arrowColor);s&&(this.style.setProperty("--dm-carousel-background",s),this.classList.add("dm-carousel-custom-background")),t&&this.style.setProperty("--dm-carousel-arrow-background",t),e&&this.style.setProperty("--dm-carousel-arrow-color",e);const a=["top","middle","bottom"].includes(this.dataset.arrowPosition)?this.dataset.arrowPosition:"middle";this.classList.add(`dm-carousel-arrows-${a}`);const l={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide",heightMode:this.dataset.heightMode==="average"?"average":"crop"};if(this.dataset.height){const h=Number(this.dataset.height);Number.isFinite(h)&&h>0&&(l.height=h)}if(this.dataset.animationDuration){const h=parseInt(this.dataset.animationDuration,10);Number.isFinite(h)&&(l.animationDuration=h)}this.dataset.animationEasing&&(l.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(h=>h.cloneNode(!0)),this._dmCarouselOpts=l),this._dmCarousel=Domma.elements.carousel(this,l),ae(this)}),w.find(".dm-countdown").each(function(){const n={autoStart:!0},o=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=t?new Date(+t[1],+t[2]-1,+t[3]).getTime():s?new Date(s).getTime():NaN;Number.isFinite(e)?n.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(n.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const a=/^dd:/i.test(o);n.format=a?"hh:mm:ss":o||(n.duration>=36e5?"hh:mm:ss":"mm:ss");const l=this,h=c=>String(c).padStart(2,"0"),i=c=>{const g=Math.max(0,Math.floor(c/1e3)),b=l.querySelector(".dm-timer-time");b&&(b.textContent=`${h(Math.floor(g/86400))}:${h(Math.floor(g%86400/3600))}:${h(Math.floor(g%3600/60))}:${h(g%60)}`)};a&&(n.onTick=i),Domma.elements.timer(this,n),a&&i(n.duration||0)}),w.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),w.find(".dm-progression").each(function(){const n=Array.from(this.querySelectorAll(".dm-progression-item")).map(t=>{const e={title:t.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:t.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return t.dataset.date&&(e.date=t.dataset.date),t.dataset.status&&(e.status=t.dataset.status),t.dataset.eventIcon&&(e.icon=t.dataset.eventIcon),t.dataset.entryId&&(e._entryId=t.dataset.entryId),e}),o=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",s=Domma.elements.progression(this,{layout:o,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...n.length?{items:n}:{}});if((this.dataset.mode||"timeline")==="timeline"){const t={completed:{label:"Completed",icon:"check-circle",tone:"success"},planned:{label:"Planned",icon:"circle",tone:"secondary"},"in-progress":{label:"In progress",icon:"clock",tone:"primary"},blocked:{label:"Blocked",icon:"alert-circle",tone:"danger"}};this.querySelectorAll(".dm-progression-item").forEach((e,a)=>{const l=n[a];if(!l)return;const h=e.querySelector(".dm-progression-title");if(l.icon&&h){const c=document.createElement("span");c.dataset.icon=l.icon,c.style.cssText="display:inline-flex;vertical-align:middle;margin-right:.4em",c.setAttribute("aria-hidden","true"),h.prepend(c)}const i=t[l.status];if(i&&h){const c=document.createElement("span");c.className=`badge badge-${i.tone} cms-timeline-status`,c.style.cssText="display:inline-flex;align-items:center;gap:.35em;margin:.4rem 0";const g=document.createElement("span");g.dataset.icon=i.icon,g.dataset.iconSize="14",g.setAttribute("aria-hidden","true"),c.append(g,document.createTextNode(i.label)),h.after(c)}})}Domma.icons.scan(this),n.length&&(this._dmCtx={instance:s,items:n})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(n=>{const o=n.dataset.revealMode||"stagger",s=n.dataset.revealAnimation||"slide-up",t=parseInt(n.dataset.revealDuration,10)||400,e=parseInt(n.dataset.revealStagger,10)||60,a=parseInt(n.dataset.revealDelay,10)||0,l=n.dataset.revealDirection==="rtl",h=Array.from(n.children),i={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};h.forEach((c,g)=>{c.style.opacity="0",c.style.transform=i[s]||"",c.style.transition=`opacity ${t}ms ease, transform ${t}ms ease`;const b=l?h.length-1-g:g;c.style.transitionDelay=o==="stagger"?`${a+b*e}ms`:`${a}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const c=new IntersectionObserver(g=>{g.forEach(b=>{b.isIntersecting&&(b.target.offsetWidth,b.target.style.opacity="1",b.target.style.transform="none",c.unobserve(b.target))})},{threshold:.1});h.forEach(g=>c.observe(g))}))}),w.find(".card[data-collapsible]").each(function(){const n=this.querySelector(".card-header");n&&n.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),w.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const n=this.dataset.soTarget,o=document.getElementById(n);if(!o)return;const s=E.slideover({title:o.dataset.soTitle||"",size:o.dataset.soSize||"md",position:o.dataset.soPosition||"right"});o.style.display="",s.setContent(o),s.open()})})}if(typeof $.setup=="function"){const n=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(o=>{try{const s=R(o.dataset.config);Object.assign(n,s)}catch{}}),Object.keys(n).length>0){const o={};for(const[s,t]of Object.entries(n)){const e=t?.events?.click,{confirm:a,toast:l,alert:h,prompt:i,...c}=e||{};a||l||h||i?($(s).on("click",async function(b){if(b.preventDefault(),a&&!await E.confirm(a))return;let u=null;if(!(i&&(u=await E.prompt(i,{inputPlaceholder:c.promptPlaceholder||"",inputValue:c.promptDefault||""}),u===null))){if(c.target){const f=$(c.target);c.toggleClass&&f.toggleClass(c.toggleClass),c.addClass&&f.addClass(c.addClass),c.removeClass&&f.removeClass(c.removeClass),u!==null&&(c.setText&&f.text(u),c.setVal&&f.val(u),c.setAttr&&f.attr(c.setAttr,u))}c.href&&(window.location.href=c.href),l&&E.toast(l,{type:c.toastType||"success"}),h&&E.alert(h)}}),Object.keys(c).length&&(o[s]={...t,events:{...t.events,click:c}})):o[s]=t}$.setup(o)}}w.length&&j(w.get(0))}),window.wireCTAButtons=j;function j(p){p.querySelectorAll(".dm-cta-trigger").forEach(r=>{r.__ctaWired||(r.__ctaWired=!0,r.addEventListener("click",async()=>{const x=r.dataset.action,y=r.dataset.entry,k=r.dataset.confirm;let w=S.get("auth_token");if(!w){E.toast("Please log in to perform this action.",{type:"warning"});return}if(k&&!await E.confirm(k))return;const n=Array.from(r.childNodes).map(s=>s.cloneNode(!0));r.disabled=!0,r.textContent="Running\u2026";const o=s=>fetch(`/api/actions/${x}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(r.dataset.scope?{entryId:y,scope:r.dataset.scope}:{entryId:y})});try{let s=await o(w);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const a=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(a.ok){const{token:l}=await a.json();S.set("auth_token",l),w=l,s=await o(w)}}}const t=await s.json().catch(()=>({}));if(!s.ok||t.success===!1)throw new Error(t.error||t.message||`Error ${s.status}`);E.toast(t.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{r.disabled=!1,r.textContent="",n.forEach(s=>r.appendChild(s)),Domma.icons.scan(r)}}))})}(function(){const r=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!r.length)return;const x=S.get("auth_token");function y(w,n){const o=document.createElement("div");o.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(n){s.appendChild(document.createTextNode("Please "));const t=document.createElement("a");t.href="/login",t.textContent="sign in",s.appendChild(t),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=w;return o.appendChild(s),o}function k(w,n){const o=document.createElement("template");o.innerHTML=n||"",w.replaceWith(o.content)}r.forEach(async w=>{const n=w.dataset.collectionAttrs;if(!n)return;if(!x){w.replaceChildren(y("",!0));return}const o=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:n})});try{let s=x,t=await o(s);if(t.status===401){const a=S.get("auth_refresh_token");if(a){const l=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:a})});if(l.ok){const{token:h}=await l.json();S.set("auth_token",h),s=h,t=await o(s)}}}if(!t.ok){const{error:a}=await t.json().catch(()=>({}));w.replaceChildren(y(a||"Unable to load entries.",!1));return}const{html:e}=await t.json();k(w,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{w.replaceChildren(y("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),j(document.body)},100)})(),(function(){const r=document.querySelectorAll("[data-collection-table]");!r.length||typeof T>"u"||!T.create||r.forEach(x=>{let y;try{y=R(x.dataset.payload)}catch{return}const{columns:k,rows:w,search:n,sortable:o,exportable:s,pageSize:t,empty:e,ctaConfig:a,slug:l,exportCfg:h}=y;if(!k?.length)return;if(a){const g=k.findIndex(b=>b.key==="_cta");g!==-1&&(k[g]={key:"_cta",title:"",render:(b,u)=>{const f=document.createElement("button");if(f.className=`btn btn-${a.style||"primary"} dm-cta-trigger`,f.dataset.action=a.action||"",a.scope&&(f.dataset.scope=a.scope),f.dataset.entry=u._entryId||"",a.confirm&&(f.dataset.confirm=a.confirm),a.icon){const m=document.createElement("span");m.dataset.icon=a.icon,f.appendChild(m),f.appendChild(document.createTextNode(" "))}return f.appendChild(document.createTextNode(a.label||"Run")),f}})}const i="col-table-"+Math.random().toString(36).slice(2,7),c=document.createElement("div");c.id=i,x.replaceChildren(c),T.create("#"+i,{data:w,columns:k,search:n,sortable:o,exportable:s,pageSize:t,emptyMessage:e}),a&&j(c),x._dmTable={columns:k,rows:w,slug:l,exportCfg:h,render(g){T.create("#"+i,{data:g,columns:k,search:n,sortable:o,exportable:s,pageSize:t,emptyMessage:e}),a&&j(c)}}})})(),(function(){const r=document.querySelectorAll("[data-form-inline]");if(!r.length||typeof F>"u")return;function x(o){const s=o&&o.logic;return!!(s&&(s.visibility||s.requirement))}function y(o,s){const t={};return(o||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),l=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":a?"chooser":e.type,h={...e.formConfig||{}};h.span==="full"&&s&&(h.span=s);const i={type:l,required:x(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...h}};e.minLength!==void 0&&(i.minLength=e.minLength),e.maxLength!==void 0&&(i.maxLength=e.maxLength),e.min!==void 0&&(i.min=e.min),e.max!==void 0&&(i.max=e.max),a&&(e.variant&&(i.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(i.multiple=!0),e.density&&(i.density=e.density),e.columns&&(i.columns=e.columns),e.accent&&(i.accent=e.accent),e.accentStyle&&(i.accentStyle=e.accentStyle),e.glow&&(i.glow=!0),e.glowColour&&(i.glowColour=e.glowColour),e.shadow&&(i.shadow=e.shadow),e.shadowColour&&(i.shadowColour=e.shadowColour)),t[e.name]=i}),t}function k(o){const s={};return(o||[]).forEach(t=>{if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(s[t.name]=typeof e=="object"?e.value:e)}}),s}function w(o,s){(s||[]).forEach(t=>{if(t.type!=="date"||!t.name)return;const e=o.querySelector(`[name="${t.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function n(o,s,t){let e=o.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",o.appendChild(e)),e.textContent=s,e.style.cssText=t?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}r.forEach(o=>{let s;try{s=R(o.dataset.formInline)}catch{return}o.querySelector(":scope > .cms-form-embed-summary")?.remove();const t=s.fields||[],e=s.settings||{},a=Number(e.columns)===3?3:2,l=e.layout||"grid",h=t.some(f=>f.type==="page-break"),i=async f=>{if(o.dataset.triggerBlocked==="true"){const m=o._formLogicRuntime,v=m&&m.submitBlock?m.submitBlock().reasons:[];n(o,v.join(" ")||"This form cannot be submitted yet.",!0);const C=new Error("Blocked by a form trigger");throw C.formSubmitFailed=!0,C}try{const m=o.querySelector(".fb-form-honeypot"),v=m?.querySelector('input[type="text"]')||null,C=m?.querySelector('[name="_t"]')||null,q=Object.assign({},f);delete q._t,m?.dataset.hpName&&delete q[m.dataset.hpName],v!==null&&(q._hp=v.value),C!==null&&(q._t=C.value);const L=await H.post(`/api/forms/submit/${s.slug}`,q);if(L&&L.error){n(o,L.error,!0);const B=new Error(L.error);throw B.formSubmitFailed=!0,B}if(L?.redirect){window.location.href=L.redirect;return}for(;o.firstChild;)o.removeChild(o.firstChild);n(o,L?.message||e.successMessage||"Thank you for your submission.",!1)}catch(m){throw m.formSubmitFailed||n(o,m.message||"Submission failed. Please try again.",!0),m}},c=Date.now();function g(f){const m=f.querySelector("form");if(!m||m.querySelector(".fb-form-honeypot"))return;const v=document.createElement("div");v.className="fb-form-honeypot",v.setAttribute("aria-hidden","true");const C=document.createElement("input");C.name=m.querySelector('[name="website"]')?"_website":"website",v.dataset.hpName=C.name,C.type="text",C.tabIndex=-1,C.autocomplete="url",C.placeholder="https://",v.appendChild(C);const q=document.createElement("input");q.name="_t",q.type="hidden",q.value=c,v.appendChild(q),m.appendChild(v)}function b(f){if(!window.FormLogicEngine||!t.some(v=>v.logic||Array.isArray(v.triggers)&&v.triggers.length))return null;const m=new window.FormLogicEngine.FormLogicRuntime(s,o,f?{baseValues:f}:void 0);if(m.init(),o._formLogicRuntime=m,o._formLogicObserved)return m;if(o._formLogicObserved=!0,o.parentNode&&typeof MutationObserver<"u"){const v=new MutationObserver(function(C){for(const q of C)for(const L of q.removedNodes)if(L===o||L.nodeType===1&&L.contains&&L.contains(o)){o._formLogicRuntime&&o._formLogicRuntime.destroy(),v.disconnect();return}});v.observe(o.parentNode,{childList:!0,subtree:!1}),o._formLogicObserver=v}return m}let u=!1;if(o.addEventListener("dm-form-end",f=>{const m=f.detail?.validation;if(m&&!m.valid){Q(o,m.missing),Z(m);return}u||(u=!0,i(f.detail?.values||{}).catch(()=>{}).finally(()=>{u=!1}))}),h&&F.wizard){const f=ue(t,s.title),m=f.map(M=>({title:M.title,description:M.description,fields:y(M.fields,a)})),v=f.map(M=>M.fields);let C=0,q=null,L=null;const B=M=>{const N=window.FormLogicEngine;if(!N||!N.validateFields)return;const d=N.validateFields(o,v[C]||[]);d.valid||(M.preventDefault(),M.stopImmediatePropagation(),Q(o,d.missing),Z(d))},P=()=>{const M=v[C]||t;fe(o,e),ee(o,e,M),w(o,M),K(o,M),e.honeypot!==!1&&g(o),q&&q.destroy(),q=b(L?.getStepData?L.getStepData():void 0),o.querySelectorAll(".wizard-next, .wizard-submit").forEach(N=>N.addEventListener("click",B,!0))};L=F.wizard(o,{schema:{steps:m},layout:l,columns:a,finishText:e.submitText||"Finish",onSubmit:i,onStepChange:M=>{C=M,setTimeout(P,0)}}),o.addEventListener("dm-form-trigger",M=>{if(M.detail?.type!=="goto-step"||!L?.goToStep)return;const N=Number(M.detail.action.step);!Number.isFinite(N)||N<0||N>=m.length||N!==C&&L.goToStep(N)}),Promise.resolve(L).then(P)}else if(F.render){const f=F.render(o,y(t,a),k(t),{submitText:e.submitText||"Submit",layout:l,columns:a,onSubmit:i});Promise.resolve(f).then(function(){pe(o,e,l),ee(o,e,t),w(o,t),K(o,t),e.honeypot!==!1&&g(o),b()})}})})();function he(p,r){const x=document.body,y=x.classList,k=new Set((x.dataset.railSite||"").split(" ").filter(Boolean)),w=()=>window.matchMedia("(min-width: 993px)").matches;p.querySelectorAll(".navbar-link, .navbar-dropdown-toggle").forEach(a=>{const l=a.textContent.trim();l&&(a.setAttribute("title",l),a.querySelector("svg, [data-icon]")||(a.dataset.initial=l.charAt(0).toUpperCase()))});const n=document.createElement("button");n.type="button",n.className="dm-nav-collapse-toggle";const o=()=>{const a=y.contains("dm-vnav-collapsed");n.setAttribute("aria-pressed",String(a)),n.setAttribute("aria-label",a?"Expand menu":"Collapse menu"),n.title=n.getAttribute("aria-label");const l=r?"chevrons-left":"chevrons-right",h=r?"chevrons-right":"chevrons-left";n.innerHTML=`<span data-icon="${a?l:h}"></span>`,window.Domma&&Domma.icons&&Domma.icons.scan(n)},s=a=>{y.toggle("dm-vnav-collapsed",a),S.set("nav_collapsed",a),o()};n.addEventListener("click",()=>s(!y.contains("dm-vnav-collapsed"))),o();const t=p.querySelector(".navbar-container")||p;t.insertBefore(n,t.firstChild?.nextSibling||null);const e=a=>{y.toggle("dm-vnav-autohide",a),y.toggle("dm-vnav-collapsible",!a&&k.has("collapsible")),a?y.remove("dm-vnav-collapsed"):k.has("collapsible")&&S.get("nav_collapsed")===!0&&y.add("dm-vnav-collapsed"),p.classList.remove("dm-nav-revealed"),o()};p.addEventListener("pointerdown",a=>{y.contains("dm-vnav-autohide")&&a.pointerType!=="mouse"&&!p.classList.contains("dm-nav-revealed")&&(p.classList.add("dm-nav-revealed"),a.preventDefault())}),document.addEventListener("pointerdown",a=>{p.contains(a.target)||p.classList.remove("dm-nav-revealed")}),window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const a=y.contains("dm-vnav-autohide"),l=y.contains("dm-vnav-collapsed"),h=S.has("nav_autohide")||S.has("nav_collapsed");return[{header:"Menu"},{label:l?"Expand menu":"Collapse to icons",icon:l?"maximize":"minimize",disabled:!w()||a||!k.has("collapsible"),action:()=>s(!l)},{label:a?"Keep on screen":"Hide when not in use",icon:a?"eye":"eye-off",disabled:!w(),action:()=>{S.set("nav_autohide",!a),e(!a)}},{type:"divider"},{label:"Reset to the site's setting",icon:"refresh",disabled:!h,action:()=>{S.remove("nav_autohide"),S.remove("nav_collapsed"),e(k.has("autohide")),y.toggle("dm-vnav-collapsed",!k.has("autohide")&&k.has("start-collapsed")),o()}}]}})}function ge(p){p.classList.add("dm-nav-scroll-hide");let r=window.scrollY,x=!1;window.addEventListener("scroll",()=>{x||(x=!0,requestAnimationFrame(()=>{x=!1;const y=window.scrollY,k=p.matches(":focus-within")||p.querySelector(".navbar-dropdown.open, .navbar-collapse.show");y>r&&y>p.offsetHeight&&!k?p.classList.add("dm-nav-scrolled-away"):y<r&&p.classList.remove("dm-nav-scrolled-away"),r=y}))},{passive:!0})}function ye(p){let r={};try{r=JSON.parse(p.dataset.contents||"{}")}catch{}const x=p.closest(".site-main"),y=document.querySelector(".site-content"),k=new Set(String(r.exclude||"").split(",").map(i=>i.trim().toLowerCase()).filter(Boolean)),w=i=>!i.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),n=i=>(y?[...y.querySelectorAll(i)]:[]).filter(w).filter(c=>!k.has(c.textContent.trim().toLowerCase())),o=r.headings==="h2"?n("h2"):r.headings==="h3"?n("h3"):r.headings==="h2h3"?n("h2, h3"):n("h2").length?n("h2"):n("h3");if(!o.length){x?.classList.add("no-sidebar-items");return}const s=new Set([...document.querySelectorAll("[id]")].map(i=>i.id)),t=document.createElement("nav");t.className="dm-contents",t.setAttribute("aria-label",r.title||"Page contents"),r.hover&&(t.dataset.menuHover=r.hover),r.selected&&(t.dataset.menuActive=r.selected),r.accent&&t.style.setProperty("--dm-menu-highlight",r.accent.startsWith("#")?r.accent:`var(--dm-${r.accent})`),r.font&&(t.style.fontFamily=r.font),r.fontSize&&(t.style.fontSize=r.fontSize),r.fontWeight&&(t.style.fontWeight=r.fontWeight);const e=document.createElement("div");e.className="dm-contents-head";const a=document.createElement("p");a.className="dm-contents-title",a.textContent=r.title||"",e.appendChild(a),t.appendChild(e);const l=document.createElement("ol");l.className="dm-contents-list"+(r.numbered?" is-numbered":"");const h=[];for(const i of o){if(!i.id){const b=(i.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let u=b;for(let f=2;s.has(u);f++)u=`${b}-${f}`;s.add(u),i.id=u}const c=document.createElement("li");c.className=`dm-contents-item dm-contents-${i.tagName.toLowerCase()}`;const g=document.createElement("a");g.href=`#${i.id}`,g.textContent=i.textContent.trim(),c.appendChild(g),l.appendChild(c),h.push([i,g])}if(t.appendChild(l),p.replaceChildren(t),r.scrollSpy!==!1&&"IntersectionObserver"in window){const i=new Map,c=()=>{const b=h.find(([u])=>i.get(u))||null;h.forEach(([,u])=>{const f=b&&u===b[1];u.classList.toggle("is-active",!!f),f?u.setAttribute("aria-current","location"):u.removeAttribute("aria-current")})},g=new IntersectionObserver(b=>{b.forEach(u=>i.set(u.target,u.isIntersecting)),c()},{rootMargin:"-80px 0px -60% 0px"});h.forEach(([b])=>g.observe(b))}if(x?.classList.contains("contents-collapsible")){const i=document.createElement("button");i.type="button",i.className="dm-contents-toggle";const c=()=>{const g=x.classList.contains("contents-collapsed");i.setAttribute("aria-expanded",String(!g)),i.setAttribute("aria-label",g?"Show the contents":"Hide the contents"),i.title=i.getAttribute("aria-label"),i.innerHTML=`<span data-icon="${g?"list":"x"}"></span>`,window.Domma?.icons&&Domma.icons.scan(i)};i.addEventListener("click",()=>{S.set("contents_collapsed",x.classList.toggle("contents-collapsed")),c()}),c(),e.insertBefore(i,e.firstChild)}if(x?.classList.contains("contents-floating")&&r.movable){t.classList.add("is-movable");const i=S.get("contents_position");i&&Number.isFinite(i.x)&&Object.assign(p.style,{left:`${i.x}px`,top:`${i.y}px`,right:"auto",bottom:"auto"}),e.addEventListener("pointerdown",c=>{if(c.target.closest("button"))return;const g=p.getBoundingClientRect(),b=c.clientX-g.left,u=c.clientY-g.top,f=v=>{const C=Math.max(0,Math.min(window.innerWidth-g.width,v.clientX-b)),q=Math.max(0,Math.min(window.innerHeight-40,v.clientY-u));Object.assign(p.style,{left:`${C}px`,top:`${q}px`,right:"auto",bottom:"auto"})},m=()=>{document.removeEventListener("pointermove",f),S.set("contents_position",{x:parseInt(p.style.left,10),y:parseInt(p.style.top,10)})};document.addEventListener("pointermove",f),document.addEventListener("pointerup",m,{once:!0})})}window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const i=x?.classList.contains("contents-collapsible"),c=x?.classList.contains("contents-collapsed"),g=h.find(([,b])=>b.classList.contains("is-active"));return[{header:"Contents"},...i?[{label:c?"Show the contents":"Collapse to a button",icon:c?"list":"minimize",action:()=>p.querySelector(".dm-contents-toggle")?.click()}]:[],{label:"Copy a link to this section",icon:"link",disabled:!g,action:async()=>{const b=`${location.origin}${location.pathname}#${g[0].id}`;try{await _.copyToClipboard(b),E.toast("Link copied.",{type:"success"})}catch{E.toast("Could not copy the link.",{type:"error"})}}},{label:"Back to the top",icon:"arrow-up",action:()=>window.scrollTo({top:0,behavior:"smooth"})}]}}),x?.classList.contains("contents-autohide")&&(p.addEventListener("pointerdown",i=>{i.pointerType!=="mouse"&&!p.classList.contains("is-revealed")&&(p.classList.add("is-revealed"),i.preventDefault())}),document.addEventListener("pointerdown",i=>{p.contains(i.target)||p.classList.remove("is-revealed")}))}
|