domma-cms 1.13.2 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/js/site.js CHANGED
@@ -1 +1 @@
1
- import{applyMobileMenu as ae,initCarouselPopup as ie}from"/public/js/mobile-ui.mjs?v=20261016-mobile-options";import{installSmoothCarets as re}from"/public/js/smooth-caret.js";import{decodeBase64Json as W}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as U,applyColour as G,applyPill as ce,applyFloat as le,applyHighlight as V,applyItemHighlight as de,itemHighlightAttrs as me,isCurrentItem as K,menuAlign as ue,applyClasses as P,cssClasses as Y,applyEntrance as X}from"/public/js/menu-decor.mjs?v=20261014-menu-entrance";import{applyMenuLook as pe}from"/public/js/menu-cards.mjs?v=20261029-glider-layout";import{initPageMotion as fe}from"/public/js/page-motion.mjs?v=20261029-page-motion";import{applyFooterShowcase as he}from"/public/js/footer-showcase.mjs?v=20261029-footer-showcase";import{initFloatingMenus as ge}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as Q,markInvalidFields as Z,showValidationPopup as ee}from"/public/js/forms.js?v=20261025-forms-files-total";import{buildWizardSteps as ye}from"/public/js/form-steps.mjs";import{applyFormClasses as te,applySubmitButtons as ve,applyWizardButtons as be}from"/public/js/form-submit.mjs";import{captureFileFields as oe,destroyDropzones as we,fileBlueprint as Ce,restoreFileFields as Se,setFileLimits as xe,splitFiles as ke,submitBody as Le,totalTooLarge as $e,wireFileFields as Ee}from"/public/js/form-files.mjs";document.addEventListener("click",u=>{const i=u.target?.closest?.(".dm-banner__dismiss");i&&(u.preventDefault(),i.closest(".dm-banner")?.remove())}),$(()=>{re(document);const u=window.__CMS_NAV__||{},i=window.__CMS_SITE__||{};if(i.autoTheme?.enabled){let t=function(e){const n=(e||"07:00").split(":");return+n[0]*60+(+n[1]||0)},s=function(){const e=new Date,n=e.getHours()*60+e.getMinutes();return n>=t(l.dayStart)&&n<t(l.nightStart)?l.dayTheme:l.nightTheme},o=function(e){const n=l.apply&&l.apply[e]||{theme:e,custom:""};Domma.theme.set(n.theme);for(const m of[...document.body.classList])m.startsWith("dm-custom-")&&document.body.classList.remove(m);n.custom&&document.body.classList.add(n.custom)};const l=i.autoTheme;o(s()),setInterval(()=>o(s()),6e4)}const L=$("#site-navbar");if(L.length&&u.brand){let s=function(p,v=0){return Array.isArray(p)?p.filter(f=>!(f&&(f.type==="spacer"||f.type==="theme-switcher"))).filter(f=>!(f&&f.type==="separator"&&v===0)).map(f=>f&&f.type==="separator"?{divider:!0}:Array.isArray(f?.items)?{...f,items:s(f.items,v+1)}:f):p};const l={...u.brand},t=l.size&&l.size!=="md"?` navbar-brand-${l.size}`:"";if(l.logo||l.icon||l.tagline){let p="";l.logo?p+=`<img src="${l.logo}" class="navbar-brand-logo" alt="${l.text||""}">`:l.icon&&(p+=`<span data-icon="${l.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),l.text&&(p+=`<span class="navbar-brand-text${t}">${l.text}</span>`),l.tagline&&(p+=`<small class="navbar-brand-tagline">${l.tagline}</small>`),l.html=p}else t&&l.text&&(l.html=`<span class="navbar-brand-text${t}">${l.text}</span>`);const o=s(u.items||[]),e=u.position==="floating",n=u.orientation==="vertical";L.get(0).querySelector(":scope > .cms-nojs-links")?.remove(),Domma.elements.navbar("#site-navbar",{brand:l,items:o,variant:u.variant||"dark",position:e?"static":u.position||"sticky",collapsible:!0,appearOnHover:!!u.appearOnHover}),Domma.icons.scan("#site-navbar");const m=L.get(0);ae(m,u.mobile);const b=()=>{if(!n)return;const v=m.querySelector('a[aria-current="page"]')?.closest(".navbar-dropdown");v&&!v.classList.contains("open")&&v.querySelector(":scope > .navbar-dropdown-toggle")?.click()};m.classList.add(`dm-nav-align-${ue(u)||"centre"}`),n&&L.get(0).classList.add("dm-nav-vertical",u.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left");const a=u.dock||{};n&&!e&&Ae(m,u.side==="right"),!n&&a.hideOnScroll&&Te(m),V(m,u),X(m,u),P(m,u.class),e&&(le(L.get(0),u),ge(L.get(0).parentNode||document));const c=m.querySelector(".navbar-toggle"),g=m.querySelector(".navbar-collapse");if(c&&g){let p=null;const v=()=>{g.classList.contains("show")&&c.click()},f=()=>{p&&(p.remove(),p=null),document.body.classList.remove("dm-drawer-open")},d=()=>{p||(p=document.createElement("div"),p.className="dm-navbar-backdrop",p.addEventListener("click",v),document.body.appendChild(p),document.body.classList.add("dm-drawer-open"))};c.addEventListener("click",()=>{requestAnimationFrame(()=>{g.classList.contains("show")?(b(),d()):f()})}),g.addEventListener("click",y=>{y.target.closest("a")&&requestAnimationFrame(f)}),document.addEventListener("keydown",y=>{y.key==="Escape"&&g.classList.contains("show")&&v()})}const w=m.querySelector(".navbar-nav");if(w){const p=Array.from(w.children);let v=0;for(const f of u.items||[])if(!(f&&f.type==="separator")){if(f&&f.type==="spacer"){const d=document.createElement("li"),y=["xs","sm","md","lg","xl","flex"].includes(f.size)?f.size:"md";d.className=`dm-menu-spacer dm-menu-spacer--${y}`,d.setAttribute("aria-hidden","true"),w.insertBefore(d,p[v]||null);continue}if(f&&f.type==="theme-switcher"){const d=document.createElement("li");d.className="dm-menu-theme-switcher";const y=document.createElement("span");y.dataset.themeSwitcher="menu",y.dataset.position="inline",d.appendChild(y),w.insertBefore(d,p[v]||null);continue}v++}window.CMSThemeSwitcher?.scan(w)}m.querySelectorAll("[data-path]").forEach(p=>{const v=p.dataset.path.split(".").map(Number),f=v.length>1,d=v.reduce((C,D)=>C?.items?.[D],{items:o});if(!d)return;d.colour&&G(p,d.colour),d.pill&&!f&&ce(p,d.pill),de(p,d),P(p.closest("li"),d.class);const y=U(d.badge);y&&p.appendChild(y),K(d.url,location.pathname)&&(p.classList.add("active"),p.setAttribute("aria-current","page"))}),pe(m,u,o),b()}const h=$("#site-footer");if(h.length){let e=function(r){return String(r??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},n=function(r){return e(r).replace(/'/g,"&#39;")},m=function(r){if(r&&r.type==="separator")return'<li class="footer-sep"><hr></li>';if(r&&r.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md"}" aria-hidden="true"></li>`;if(r&&r.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const N=n(r.url||"#"),k=e(r.text||""),M=Array.isArray(r.items)&&r.items.length?`<ul>${r.items.map(m).join("")}</ul>`:"",j=me(r),ne=[j.hover&&` data-menu-item-hover="${n(j.hover)}"`,j.active&&` data-menu-item-active="${n(j.active)}"`].filter(Boolean).join(""),se=j.accent?` style="--dm-menu-highlight:${n(j.accent)}"`:"",J=Y(r.class).join(" ");return`<li${J?` class="${n(J)}"`:""}><a href="${N}"${ne}${se}>${k}</a>${M}</li>`},a=function(){if(!i.footer)return"";const r=Object.keys(t).filter(k=>l[k]);if(!r.length)return"";const N=Y(i.footer.socialClass).join(" ");return`<div class="footer-social">${r.map(k=>{const{label:M,svg:j}=t[k];return`<a href="${l[k]}" target="_blank" rel="noopener noreferrer" aria-label="${M}" class="footer-social-link${N?` ${n(N)}`:""}">${j}</a>`}).join("")}</div>`},p=function(r){if(!r||r.type==="separator"||r.type==="spacer")return"";if(r.type==="theme-switcher")return`<li class="cms-footer-col">${m(r).replace(/^<li[^>]*>|<\/li>$/g,"")}</li>`;const N=Array.isArray(r.items)&&r.items.length?`<ul>${r.items.map(m).join("")}</ul>`:"",k=w(r)?`<span class="cms-footer-col-title">${e(r.text||"")}</span>`:`<a class="cms-footer-col-title" href="${n(r.url||"#")}">${e(r.text||"")}</a>`,M=["cms-footer-col",...Y(r.class)].join(" ");return`<li class="${n(M)}">${k}${N}</li>`},d=function(r,N,k=!1){return(r||[]).forEach(M=>{M&&(M.type==="separator"||M.type==="spacer"||M.type==="theme-switcher")||(k&&w(M)||N.push(M),Array.isArray(M.items)&&M.items.length&&d(M.items,N))}),N};const l=i.social||{},t={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 o=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""},b=(()=>{const r=i.cookieConsent;if(!r||r.showSettingsLink===!1)return"";const N=k=>(k||[]).some(M=>M&&(M.url==="#cookie-settings"||N(M.items)));return N(o.primary)||N(o.legal)?"":`<li class="cms-cookie-settings"><a href="#cookie-settings">${e(r.settingsLinkText||"Cookie settings")}</a></li>`})(),c=["columns","row"].includes(i.footer?.layout)?i.footer.layout:"auto",g=i.footer?.look==="showcase"||c==="columns"||c==="auto"&&o.primary.some(r=>Array.isArray(r?.items)&&r.items.length),w=r=>g&&!r.url&&Array.isArray(r.items)&&r.items.length>0;if(g){const r=u.brand||{},N=r.text||i.title||"",k=r.logo?`<img src="${n(r.logo)}" class="cms-footer-brand-logo" alt="">`:r.icon?'<span class="cms-footer-brand-icon"></span>':"",M=String(i.footer?.blurb||"").trim();s='<div class="footer-inner footer-inner--columns container"><div class="cms-footer-top">',s+=`<div class="cms-footer-brand">${N||k?`<a class="cms-footer-brand-name" href="${n(r.url||"/")}">${k}<span>${e(N)}</span></a>`:""}${M?`<p class="cms-footer-blurb">${e(M)}</p>`:""}${a()}</div>`,o.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary footer-nav--columns" aria-label="Footer"><ul>${o.primary.map(p).join("")}</ul></nav>`),s+='</div><div class="cms-footer-bottom">',o.copyright&&(s+=`<p class="cms-footer-copyright">${e(o.copyright)}</p>`),(o.legal.length||b)&&(s+=`<nav class="footer-nav footer-nav--legal" aria-label="Legal"><ul>${o.legal.map(m).join("")}${b}</ul></nav>`),s+="</div>"}else o.copyright&&(s+=`<p>${e(o.copyright)}</p>`),o.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${o.primary.map(m).join("")}</ul></nav>`),(o.legal.length||b)&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${o.legal.map(m).join("")}${b}</ul></nav>`),s+=a();s+="</div>",h.get(0).querySelector(":scope > .cms-nojs-links")?.remove();const v=h.get(0).querySelector(":scope > .cms-footer-blocks");v?.remove(),h.html(s),v&&h.get(0).prepend(v),window.CMSThemeSwitcher?.scan(h.get(0));const f=h.get(0).querySelector(".cms-footer-brand-icon");f&&u.brand?.icon&&f.setAttribute("data-icon",u.brand.icon),P(h.get(0),i.footer?.class),g&&he(h.get(0),i);const y=[...d(o.primary,[],!0),...d(o.legal,[])];h.get(0).querySelectorAll(".footer-nav a").forEach((r,N)=>{const k=y[N];if(!k)return;k.colour&&G(r,k.colour);const M=U(k.badge);M&&r.appendChild(M),K(k.url,location.pathname)&&(r.classList.add("is-active"),r.setAttribute("aria-current","page"))}),V(h.get(0).querySelector(".footer-nav--primary"),{highlight:o.primaryHighlight}),V(h.get(0).querySelector(".footer-nav--legal"),{highlight:o.legalHighlight}),X(h.get(0).querySelector(".footer-nav--primary"),{entrance:o.primaryEntrance}),X(h.get(0).querySelector(".footer-nav--legal"),{entrance:o.legalEntrance}),P(h.get(0).querySelector(".footer-nav--primary"),o.primaryClass),P(h.get(0).querySelector(".footer-nav--legal"),o.legalClass);const D=i.footer?.showMotionToggle!==!1,z=S.get("reduced_motion"),B=i.footer?.motionDefault,O=z!=null?!!z:B==="on"?!0:B==="off"?!1:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),A=i.footer?.motionControl==="checkbox",I=h.get(0).querySelector(".cms-footer-bottom")||h.get(0).querySelector(".footer-inner");if(D&&I){const r=document.createElement("input");r.type="checkbox",r.className=A?"footer-motion-checkbox":"form-switch-input",r.id="dm-motion-switch",r.checked=O,r.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const N=document.createElement("span");N.className=A?"footer-motion-label":"form-switch-label",N.textContent="Reduce motion";const k=document.createElement("label");k.className=A?"footer-motion-check":"form-switch footer-motion-switch",k.title="Reduce motion",k.appendChild(r),k.appendChild(N),I.appendChild(k)}}const q=document.getElementById("site-sidebar");q&&_e(q),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const x=$(".page-body");if(x.length){x.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),x.find(".tabs").each(function(){Domma.elements.tabs(this)}),x.find(".carousel").each(function(){const t={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"},s=a=>{const c=String(a||"").trim();return c?t[c.toLowerCase()]?`var(${t[c.toLowerCase()]})`:CSS.supports("color",c)?c:"":""},o=s(this.dataset.background),e=s(this.dataset.arrowBackground),n=s(this.dataset.arrowColor);o&&(this.style.setProperty("--dm-carousel-background",o),this.classList.add("dm-carousel-custom-background")),e&&this.style.setProperty("--dm-carousel-arrow-background",e),n&&this.style.setProperty("--dm-carousel-arrow-color",n);const m=["top","middle","bottom"].includes(this.dataset.arrowPosition)?this.dataset.arrowPosition:"middle";this.classList.add(`dm-carousel-arrows-${m}`);const b={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 a=Number(this.dataset.height);Number.isFinite(a)&&a>0&&(b.height=a)}if(this.dataset.animationDuration){const a=parseInt(this.dataset.animationDuration,10);Number.isFinite(a)&&(b.animationDuration=a)}this.dataset.animationEasing&&(b.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(a=>a.cloneNode(!0)),this._dmCarouselOpts=b),this._dmCarousel=Domma.elements.carousel(this,b),ie(this)}),x.find(".dm-countdown").each(function(){const t={autoStart:!0},s=String(this.dataset.format||"").trim(),o=String(this.dataset.to||"").trim(),e=/^(\d{4})-(\d{2})-(\d{2})$/.exec(o),n=e?new Date(+e[1],+e[2]-1,+e[3]).getTime():o?new Date(o).getTime():NaN;Number.isFinite(n)?t.duration=Math.max(0,n-Date.now()):this.dataset.duration&&(t.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const m=/^dd:/i.test(s);t.format=m?"hh:mm:ss":s||(t.duration>=36e5?"hh:mm:ss":"mm:ss");const b=this,a=g=>String(g).padStart(2,"0"),c=g=>{const w=Math.max(0,Math.floor(g/1e3)),p=b.querySelector(".dm-timer-time");p&&(p.textContent=`${a(Math.floor(w/86400))}:${a(Math.floor(w%86400/3600))}:${a(Math.floor(w%3600/60))}:${a(w%60)}`)};m&&(t.onTick=c),Domma.elements.timer(this,t),m&&c(t.duration||0)}),x.find("[data-tooltip]:not(.dm-range-slider)").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),x.find(".dm-progression").each(function(){const t=Array.from(this.querySelectorAll(".dm-progression-item")).map(e=>{const n={title:e.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:e.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return e.dataset.date&&(n.date=e.dataset.date),e.dataset.status&&(n.status=e.dataset.status),e.dataset.eventIcon&&(n.icon=e.dataset.eventIcon),e.dataset.entryId&&(n._entryId=e.dataset.entryId),n}),s=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",o=Domma.elements.progression(this,{layout:s,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...t.length?{items:t}:{}});if((this.dataset.mode||"timeline")==="timeline"){const e={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((n,m)=>{const b=t[m];if(!b)return;const a=n.querySelector(".dm-progression-title");if(b.icon&&a){const g=document.createElement("span");g.dataset.icon=b.icon,g.style.cssText="display:inline-flex;vertical-align:middle;margin-right:.4em",g.setAttribute("aria-hidden","true"),a.prepend(g)}const c=e[b.status];if(c&&a){const g=document.createElement("span");g.className=`badge badge-${c.tone} cms-timeline-status`,g.style.cssText="display:inline-flex;align-items:center;gap:.35em;margin:.4rem 0";const w=document.createElement("span");w.dataset.icon=c.icon,w.dataset.iconSize="14",w.setAttribute("aria-hidden","true"),g.append(w,document.createTextNode(c.label)),a.after(g)}})}Domma.icons.scan(this),t.length&&(this._dmCtx={instance:o,items:t})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}const l=matchMedia("(prefers-reduced-motion: reduce)").matches||document.documentElement.classList.contains("dm-reduced-motion");document.querySelectorAll(".page-body .row[data-reveal]").forEach(t=>{const s=t.dataset.revealMode||"stagger",o=t.dataset.revealAnimation||"slide-up",e=parseInt(t.dataset.revealDuration,10)||(o.startsWith("swoosh")?700:400),n=parseInt(t.dataset.revealStagger,10)||(o.startsWith("swoosh")?90:60),m=parseInt(t.dataset.revealDelay,10)||0,b=t.dataset.revealDirection==="rtl",a=t.dataset.revealReplay==="true",c=Array.from(t.children);if(l&&o.startsWith("swoosh"))return;const g={"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)",swoosh:"translateY(36px) scale(0.96)"},w=d=>o!=="swoosh-sides"?g[o]||"":c.length>1&&d===0?"translateX(-64px) rotate(-1.5deg)":c.length>1&&d===c.length-1?"translateX(64px) rotate(1.5deg)":"translateY(40px) scale(0.94)",p=o.startsWith("swoosh"),v=p?"cubic-bezier(.2,.8,.2,1)":"ease",f=(d,y)=>{d.style.opacity="0",d.style.transform=w(y),p&&(d.style.filter="blur(10px)")};c.forEach((d,y)=>{f(d,y),d.style.transition=`opacity ${e}ms ${v}, transform ${e}ms ${v}`+(p?`, filter ${e}ms ${v}`:"");const C=b?c.length-1-y:y;d.style.transitionDelay=s==="stagger"?`${m+C*n}ms`:`${m}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const d=new IntersectionObserver(y=>{y.forEach(C=>{if(C.isIntersecting){if(C.target.offsetWidth,C.target.style.opacity="1",C.target.style.transform="",p&&(C.target.style.filter=""),!a){d.unobserve(C.target);const D=C.target;D.addEventListener("transitionend",function z(B){B.target!==D||B.propertyName!=="opacity"||(D.removeEventListener("transitionend",z),D.style.transition="",D.style.transitionDelay="")})}}else a&&C.boundingClientRect.top>0&&f(C.target,c.indexOf(C.target))})},{threshold:.1});c.forEach(y=>d.observe(y))}))}),fe(document.querySelector(".page-body")||document),x.find(".card[data-collapsible]").each(function(){const t=this.querySelector(".card-header");t&&t.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),x.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const t=this.dataset.soTarget,s=document.getElementById(t);if(!s)return;const o=E.slideover({title:s.dataset.soTitle||"",size:s.dataset.soSize||"md",position:s.dataset.soPosition||"right"});s.style.display="",o.setContent(s),o.open()})})}if(typeof $.setup=="function"){const l=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const s=W(t.dataset.config);Object.assign(l,s)}catch{}}),Object.keys(l).length>0){const t={};for(const[s,o]of Object.entries(l)){const e=o?.events?.click,{confirm:n,toast:m,alert:b,prompt:a,...c}=e||{};if(n||m||b||a){$(s).on("click",async function(N){if(N.preventDefault(),n&&!await E.confirm(n))return;let k=null;if(!(a&&(k=await E.prompt(a,{inputPlaceholder:c.promptPlaceholder||"",inputValue:c.promptDefault||""}),k===null))){{const M=$(c.target||this);c.toggleClass&&M.toggleClass(c.toggleClass),c.addClass&&M.addClass(c.addClass),c.removeClass&&M.removeClass(c.removeClass),k!==null&&(c.setText&&M.text(k),c.setVal&&M.val(k),c.setAttr&&M.attr(c.setAttr,k))}c.href&&(window.location.href=c.href),m&&E.toast(m,{type:c.toastType||"success"}),b&&E.alert(b)}});const{target:w,toggleClass:p,addClass:v,removeClass:f,setText:d,setVal:y,setAttr:C,href:D,toastType:z,promptPlaceholder:B,promptDefault:O,...A}=c,I={...o.events};Object.keys(A).length?I.click=w?{target:w,...A}:A:delete I.click;const r={...o,events:I};Object.keys(I).length||delete r.events,Object.keys(r).length&&(t[s]=r)}else t[s]=o}$.setup(t)}}x.length&&R(x.get(0))}),window.wireCTAButtons=R;function R(u){u.querySelectorAll(".dm-cta-trigger").forEach(i=>{i.__ctaWired||(i.__ctaWired=!0,i.addEventListener("click",async()=>{const L=i.dataset.action,h=i.dataset.entry,q=i.dataset.confirm;let x=S.get("auth_token");if(!x){E.toast("Please log in to perform this action.",{type:"warning"});return}if(q&&!await E.confirm(q))return;const l=Array.from(i.childNodes).map(s=>s.cloneNode(!0));i.disabled=!0,i.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${L}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(i.dataset.scope?{entryId:h,scope:i.dataset.scope}:{entryId:h})});try{let s=await t(x);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const n=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(n.ok){const{token:m}=await n.json();S.set("auth_token",m),x=m,s=await t(x)}}}const o=await s.json().catch(()=>({}));if(!s.ok||o.success===!1)throw new Error(o.error||o.message||`Error ${s.status}`);E.toast(o.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{i.disabled=!1,i.textContent="",l.forEach(s=>i.appendChild(s)),Domma.icons.scan(i)}}))})}(function(){const i=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!i.length)return;const L=S.get("auth_token");function h(x,l){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(l){s.appendChild(document.createTextNode("Please "));const o=document.createElement("a");o.href="/login",o.textContent="sign in",s.appendChild(o),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=x;return t.appendChild(s),t}function q(x,l){const t=document.createElement("template");t.innerHTML=l||"",x.replaceWith(t.content)}i.forEach(async x=>{const l=x.dataset.collectionAttrs;if(!l)return;if(!L){x.replaceChildren(h("",!0));return}const t=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:l})});try{let s=L,o=await t(s);if(o.status===401){const n=S.get("auth_refresh_token");if(n){const m=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:n})});if(m.ok){const{token:b}=await m.json();S.set("auth_token",b),s=b,o=await t(s)}}}if(!o.ok){const{error:n}=await o.json().catch(()=>({}));x.replaceChildren(h(n||"Unable to load entries.",!1));return}const{html:e}=await o.json();q(x,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{x.replaceChildren(h("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),R(document.body)},100)})(),(function(){const i=document.querySelectorAll("[data-collection-table]");!i.length||typeof T>"u"||!T.create||i.forEach(L=>{let h;try{h=W(L.dataset.payload)}catch{return}const{columns:q,rows:x,search:l,sortable:t,exportable:s,pageSize:o,empty:e,ctaConfig:n,slug:m,exportCfg:b}=h;if(!q?.length)return;if(n){const g=q.findIndex(w=>w.key==="_cta");g!==-1&&(q[g]={key:"_cta",title:"",render:(w,p)=>{const v=document.createElement("button");if(v.className=`btn btn-${n.style||"primary"} dm-cta-trigger`,v.dataset.action=n.action||"",n.scope&&(v.dataset.scope=n.scope),v.dataset.entry=p._entryId||"",n.confirm&&(v.dataset.confirm=n.confirm),n.icon){const f=document.createElement("span");f.dataset.icon=n.icon,v.appendChild(f),v.appendChild(document.createTextNode(" "))}return v.appendChild(document.createTextNode(n.label||"Run")),v}})}const a="col-table-"+Math.random().toString(36).slice(2,7),c=document.createElement("div");c.id=a,L.replaceChildren(c),T.create("#"+a,{data:x,columns:q,search:l,sortable:t,exportable:s,pageSize:o,emptyMessage:e}),n&&R(c),L._dmTable={columns:q,rows:x,slug:m,exportCfg:b,render(g){T.create("#"+a,{data:g,columns:q,search:l,sortable:t,exportable:s,pageSize:o,emptyMessage:e}),n&&R(c)}}})})(),(function(){const i=document.querySelectorAll("[data-form-inline]");if(!i.length||typeof F>"u")return;function L(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function h(t,s){const o={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const n=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),m=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":n?"chooser":e.type,b={...e.formConfig||{}};b.span==="full"&&s&&(b.span=s);const a={type:m,required:L(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},...b}};e.minLength!==void 0&&(a.minLength=e.minLength),e.maxLength!==void 0&&(a.maxLength=e.maxLength),e.min!==void 0&&(a.min=e.min),e.max!==void 0&&(a.max=e.max),n&&(e.variant&&(a.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(a.multiple=!0),e.density&&(a.density=e.density),e.columns&&(a.columns=e.columns),e.accent&&(a.accent=e.accent),e.accentStyle&&(a.accentStyle=e.accentStyle),e.glow&&(a.glow=!0),e.glowColour&&(a.glowColour=e.glowColour),e.shadow&&(a.shadow=e.shadow),e.shadowColour&&(a.shadowColour=e.shadowColour)),o[e.name]=e.type==="file"?Ce(e,a):a}),o}function q(t){const s={};return(t||[]).forEach(o=>{if(!(!o.name||o.type==="page-break"||o.type==="spacer")&&(o.type==="select"||o.type==="multiselect")&&o.required){const e=(o.options||[])[0];e&&(s[o.name]=typeof e=="object"?e.value:e)}}),s}function x(t,s){(s||[]).forEach(o=>{if(o.type!=="date"||!o.name)return;const e=t.querySelector(`[name="${o.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function l(t,s,o){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=s,e.style.cssText=o?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}i.forEach(t=>{let s;try{s=W(t.dataset.formInline)}catch{return}t.querySelector(":scope > .cms-form-embed-summary")?.remove();const o=s.fields||[],e=s.settings||{},n=Number(e.columns)===3?3:2,m=e.layout||"grid",b=o.some(f=>f.type==="page-break"),a=new Map;xe(t,s.fileLimits,a),Ee(t,o);const c=async f=>{if(t.dataset.triggerBlocked==="true"){const d=t._formLogicRuntime,y=d&&d.submitBlock?d.submitBlock().reasons:[];l(t,y.join(" ")||"This form cannot be submitted yet.",!0);const C=new Error("Blocked by a form trigger");throw C.formSubmitFailed=!0,C}try{const d=t.querySelector(".fb-form-honeypot"),y=d?.querySelector('input[type="text"]')||null,C=d?.querySelector('[name="_t"]')||null,D=Object.assign({},f);delete D._t,d?.dataset.hpName&&delete D[d.dataset.hpName],y!==null&&(D._hp=y.value),C!==null&&(D._t=C.value);const z=new Map(a);oe(t,z);const B=ke(D,o,z),O=$e(t,B.files);if(O){l(t,O,!0);const I=new Error(O);throw I.formSubmitFailed=!0,I}const A=await H.post(`/api/forms/submit/${s.slug}`,B.files.size?Le(B.values,B.files).body:B.values);if(A&&A.error){l(t,A.error,!0);const I=new Error(A.error);throw I.formSubmitFailed=!0,I}if(A?.redirect){window.location.href=A.redirect;return}for(we(t);t.firstChild;)t.removeChild(t.firstChild);l(t,A?.message||e.successMessage||"Thank you for your submission.",!1)}catch(d){throw d.formSubmitFailed||l(t,d.message||"Submission failed. Please try again.",!0),d}},g=Date.now();function w(f){const d=f.querySelector("form");if(!d||d.querySelector(".fb-form-honeypot"))return;const y=document.createElement("div");y.className="fb-form-honeypot",y.setAttribute("aria-hidden","true");const C=document.createElement("input");C.name=d.querySelector('[name="website"]')?"_website":"website",y.dataset.hpName=C.name,C.type="text",C.tabIndex=-1,C.autocomplete="url",C.placeholder="https://",y.appendChild(C);const D=document.createElement("input");D.name="_t",D.type="hidden",D.value=g,y.appendChild(D),d.appendChild(y)}function p(f){if(!window.FormLogicEngine||!o.some(y=>y.logic||Array.isArray(y.triggers)&&y.triggers.length))return null;const d=new window.FormLogicEngine.FormLogicRuntime(s,t,f?{baseValues:f}:void 0);if(d.init(),t._formLogicRuntime=d,t._formLogicObserved)return d;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const y=new MutationObserver(function(C){for(const D of C)for(const z of D.removedNodes)if(z===t||z.nodeType===1&&z.contains&&z.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),y.disconnect();return}});y.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=y}return d}let v=!1;if(t.addEventListener("dm-form-end",f=>{const d=f.detail?.validation;if(d&&!d.valid){Z(t,d.missing),ee(d);return}v||(v=!0,c(f.detail?.values||{}).catch(()=>{}).finally(()=>{v=!1}))}),b&&F.wizard){const f=ye(o,s.title),d=f.map(A=>({title:A.title,description:A.description,fields:h(A.fields,n)})),y=f.map(A=>A.fields);let C=0,D=null,z=null;const B=A=>{const I=window.FormLogicEngine;if(!I||!I.validateFields)return;const r=I.validateFields(t,y[C]||[]);r.valid||(A.preventDefault(),A.stopImmediatePropagation(),Z(t,r.missing),ee(r))},O=()=>{const A=y[C]||o;be(t,e),te(t,e,A),x(t,A),Q(t,A),Se(t,a),e.honeypot!==!1&&w(t),D&&D.destroy(),D=p(z?.getStepData?z.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(I=>I.addEventListener("click",B,!0))};z=F.wizard(t,{schema:{steps:d},layout:m,columns:n,finishText:e.submitText||"Finish",onSubmit:c,onStepChange:A=>{oe(t,a),C=A,setTimeout(O,0)}}),t.addEventListener("dm-form-trigger",A=>{if(A.detail?.type!=="goto-step"||!z?.goToStep)return;const I=Number(A.detail.action.step);!Number.isFinite(I)||I<0||I>=d.length||I!==C&&z.goToStep(I)}),Promise.resolve(z).then(O)}else if(F.render){const f=F.render(t,h(o,n),q(o),{submitText:e.submitText||"Submit",layout:m,columns:n,onSubmit:c});Promise.resolve(f).then(function(){ve(t,e,m),te(t,e,o),x(t,o),Q(t,o),e.honeypot!==!1&&w(t),p()})}})})();function Ae(u,i){const L=document.body,h=L.classList,q=new Set((L.dataset.railSite||"").split(" ").filter(Boolean)),x=()=>window.matchMedia("(min-width: 993px)").matches;u.querySelectorAll(".navbar-link, .navbar-dropdown-toggle").forEach(n=>{const m=n.textContent.trim();m&&(n.setAttribute("title",m),n.querySelector("svg, [data-icon]")||(n.dataset.initial=m.charAt(0).toUpperCase()))});const l=document.createElement("button");l.type="button",l.className="dm-nav-collapse-toggle";const t=()=>{const n=h.contains("dm-vnav-collapsed");l.setAttribute("aria-pressed",String(n)),l.setAttribute("aria-label",n?"Expand menu":"Collapse menu"),l.title=l.getAttribute("aria-label");const m=i?"chevrons-left":"chevrons-right",b=i?"chevrons-right":"chevrons-left";l.innerHTML=`<span data-icon="${n?m:b}"></span>`,window.Domma&&Domma.icons&&Domma.icons.scan(l)},s=n=>{h.toggle("dm-vnav-collapsed",n),S.set("nav_collapsed",n),t()};l.addEventListener("click",()=>s(!h.contains("dm-vnav-collapsed"))),t();const o=u.querySelector(".navbar-container")||u;o.insertBefore(l,o.firstChild?.nextSibling||null);const e=n=>{h.toggle("dm-vnav-autohide",n),h.toggle("dm-vnav-collapsible",!n&&q.has("collapsible")),n?h.remove("dm-vnav-collapsed"):q.has("collapsible")&&S.get("nav_collapsed")===!0&&h.add("dm-vnav-collapsed"),u.classList.remove("dm-nav-revealed"),t()};u.addEventListener("pointerdown",n=>{h.contains("dm-vnav-autohide")&&n.pointerType!=="mouse"&&!u.classList.contains("dm-nav-revealed")&&(u.classList.add("dm-nav-revealed"),n.preventDefault())}),document.addEventListener("pointerdown",n=>{u.contains(n.target)||u.classList.remove("dm-nav-revealed")}),window.E&&typeof E.contextMenu=="function"&&E.contextMenu(u,{items:()=>{const n=h.contains("dm-vnav-autohide"),m=h.contains("dm-vnav-collapsed"),b=S.has("nav_autohide")||S.has("nav_collapsed");return[{header:"Menu"},{label:m?"Expand menu":"Collapse to icons",icon:m?"maximize":"minimize",disabled:!x()||n||!q.has("collapsible"),action:()=>s(!m)},{label:n?"Keep on screen":"Hide when not in use",icon:n?"eye":"eye-off",disabled:!x(),action:()=>{S.set("nav_autohide",!n),e(!n)}},{type:"divider"},{label:"Reset to the site's setting",icon:"refresh",disabled:!b,action:()=>{S.remove("nav_autohide"),S.remove("nav_collapsed"),e(q.has("autohide")),h.toggle("dm-vnav-collapsed",!q.has("autohide")&&q.has("start-collapsed")),t()}}]}})}function Te(u){u.classList.add("dm-nav-scroll-hide");let i=window.scrollY,L=!1;window.addEventListener("scroll",()=>{L||(L=!0,requestAnimationFrame(()=>{L=!1;const h=window.scrollY,q=u.matches(":focus-within")||u.querySelector(".navbar-dropdown.open, .navbar-collapse.show");h>i&&h>u.offsetHeight&&!q?u.classList.add("dm-nav-scrolled-away"):h<i&&u.classList.remove("dm-nav-scrolled-away"),i=h}))},{passive:!0})}function _e(u){let i={};try{i=JSON.parse(u.dataset.contents||"{}")}catch{}const L=u.closest(".site-main"),h=document.querySelector(".site-content"),q=new Set(String(i.exclude||"").split(",").map(a=>a.trim().toLowerCase()).filter(Boolean)),x=a=>!a.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),l=a=>(h?[...h.querySelectorAll(a)]:[]).filter(x).filter(c=>!q.has(c.textContent.trim().toLowerCase())),t=i.headings==="h2"?l("h2"):i.headings==="h3"?l("h3"):i.headings==="h2h3"?l("h2, h3"):l("h2").length?l("h2"):l("h3");if(!t.length){L?.classList.add("no-sidebar-items");return}const s=new Set([...document.querySelectorAll("[id]")].map(a=>a.id)),o=document.createElement("nav");o.className="dm-contents",o.setAttribute("aria-label",i.title||"Page contents"),i.hover&&(o.dataset.menuHover=i.hover),i.selected&&(o.dataset.menuActive=i.selected),i.accent&&o.style.setProperty("--dm-menu-highlight",i.accent.startsWith("#")?i.accent:`var(--dm-${i.accent})`),i.font&&(o.style.fontFamily=i.font),i.fontSize&&(o.style.fontSize=i.fontSize),i.fontWeight&&(o.style.fontWeight=i.fontWeight);const e=document.createElement("div");e.className="dm-contents-head";const n=document.createElement("p");n.className="dm-contents-title",n.textContent=i.title||"",e.appendChild(n),o.appendChild(e);const m=document.createElement("ol");m.className="dm-contents-list"+(i.numbered?" is-numbered":"");const b=[];for(const a of t){if(!a.id){const w=(a.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let p=w;for(let v=2;s.has(p);v++)p=`${w}-${v}`;s.add(p),a.id=p}const c=document.createElement("li");c.className=`dm-contents-item dm-contents-${a.tagName.toLowerCase()}`;const g=document.createElement("a");g.href=`#${a.id}`,g.textContent=a.textContent.trim(),c.appendChild(g),m.appendChild(c),b.push([a,g])}if(o.appendChild(m),u.replaceChildren(o),i.scrollSpy!==!1&&"IntersectionObserver"in window){const a=new Map,c=()=>{const w=b.find(([p])=>a.get(p))||null;b.forEach(([,p])=>{const v=w&&p===w[1];p.classList.toggle("is-active",!!v),v?p.setAttribute("aria-current","location"):p.removeAttribute("aria-current")})},g=new IntersectionObserver(w=>{w.forEach(p=>a.set(p.target,p.isIntersecting)),c()},{rootMargin:"-80px 0px -60% 0px"});b.forEach(([w])=>g.observe(w))}if(L?.classList.contains("contents-collapsible")){const a=document.createElement("button");a.type="button",a.className="dm-contents-toggle";const c=()=>{const g=L.classList.contains("contents-collapsed");a.setAttribute("aria-expanded",String(!g)),a.setAttribute("aria-label",g?"Show the contents":"Hide the contents"),a.title=a.getAttribute("aria-label"),a.innerHTML=`<span data-icon="${g?"list":"x"}"></span>`,window.Domma?.icons&&Domma.icons.scan(a)};a.addEventListener("click",()=>{S.set("contents_collapsed",L.classList.toggle("contents-collapsed")),c()}),c(),e.insertBefore(a,e.firstChild)}if(L?.classList.contains("contents-floating")&&i.movable){o.classList.add("is-movable");const a=S.get("contents_position");a&&Number.isFinite(a.x)&&Object.assign(u.style,{left:`${a.x}px`,top:`${a.y}px`,right:"auto",bottom:"auto"}),e.addEventListener("pointerdown",c=>{if(c.target.closest("button"))return;const g=u.getBoundingClientRect(),w=c.clientX-g.left,p=c.clientY-g.top,v=d=>{const y=Math.max(0,Math.min(window.innerWidth-g.width,d.clientX-w)),C=Math.max(0,Math.min(window.innerHeight-40,d.clientY-p));Object.assign(u.style,{left:`${y}px`,top:`${C}px`,right:"auto",bottom:"auto"})},f=()=>{document.removeEventListener("pointermove",v),S.set("contents_position",{x:parseInt(u.style.left,10),y:parseInt(u.style.top,10)})};document.addEventListener("pointermove",v),document.addEventListener("pointerup",f,{once:!0})})}window.E&&typeof E.contextMenu=="function"&&E.contextMenu(u,{items:()=>{const a=L?.classList.contains("contents-collapsible"),c=L?.classList.contains("contents-collapsed"),g=b.find(([,w])=>w.classList.contains("is-active"));return[{header:"Contents"},...a?[{label:c?"Show the contents":"Collapse to a button",icon:c?"list":"minimize",action:()=>u.querySelector(".dm-contents-toggle")?.click()}]:[],{label:"Copy a link to this section",icon:"link",disabled:!g,action:async()=>{const w=`${location.origin}${location.pathname}#${g[0].id}`;try{await _.copyToClipboard(w),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"})}]}}),L?.classList.contains("contents-autohide")&&(u.addEventListener("pointerdown",a=>{a.pointerType!=="mouse"&&!u.classList.contains("is-revealed")&&(u.classList.add("is-revealed"),a.preventDefault())}),document.addEventListener("pointerdown",a=>{u.contains(a.target)||u.classList.remove("is-revealed")}))}
1
+ import{applyMobileMenu as oe,initCarouselPopup as ne}from"/public/js/mobile-ui.mjs?v=20261016-mobile-options";import{installSmoothCarets as se}from"/public/js/smooth-caret.js";import{decodeBase64Json as W}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as J,applyColour as U,applyPill as ae,applyFloat as ie,applyHighlight as V,applyItemHighlight as re,itemHighlightAttrs as ce,isCurrentItem as G,menuAlign as le,applyClasses as j,cssClasses as Y,applyEntrance as X}from"/public/js/menu-decor.mjs?v=20261014-menu-entrance";import{applyMenuLook as de}from"/public/js/menu-cards.mjs?v=20261029-glider-layout";import{initPageMotion as me}from"/public/js/page-motion.mjs?v=20261029-page-motion";import{applyFooterShowcase as ue}from"/public/js/footer-showcase.mjs?v=20261029-footer-showcase";import{initFloatingMenus as pe}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=20261025-forms-files-total";import{buildWizardSteps as fe}from"/public/js/form-steps.mjs";import{mountMotionControl as he}from"/public/js/motion-control.mjs?v=20261029-motion-under-switcher";import{applyFormClasses as ee,applySubmitButtons as ge,applyWizardButtons as ye}from"/public/js/form-submit.mjs";import{captureFileFields as te,destroyDropzones as ve,fileBlueprint as be,restoreFileFields as we,setFileLimits as Ce,splitFiles as Se,submitBody as xe,totalTooLarge as ke,wireFileFields as Le}from"/public/js/form-files.mjs";document.addEventListener("click",u=>{const r=u.target?.closest?.(".dm-banner__dismiss");r&&(u.preventDefault(),r.closest(".dm-banner")?.remove())}),$(()=>{se(document);const u=window.__CMS_NAV__||{},r=window.__CMS_SITE__||{};if(r.autoTheme?.enabled){let s=function(o){const c=(o||"07:00").split(":");return+c[0]*60+(+c[1]||0)},n=function(){const o=new Date,c=o.getHours()*60+o.getMinutes();return c>=s(t.dayStart)&&c<s(t.nightStart)?t.dayTheme:t.nightTheme},e=function(o){const c=t.apply&&t.apply[o]||{theme:o,custom:""};Domma.theme.set(c.theme);for(const f of[...document.body.classList])f.startsWith("dm-custom-")&&document.body.classList.remove(f);c.custom&&document.body.classList.add(c.custom)};const t=r.autoTheme;e(n()),setInterval(()=>e(n()),6e4)}const L=$("#site-navbar");if(L.length&&u.brand){let n=function(m,w=0){return Array.isArray(m)?m.filter(d=>!(d&&(d.type==="spacer"||d.type==="theme-switcher"))).filter(d=>!(d&&d.type==="separator"&&w===0)).map(d=>d&&d.type==="separator"?{divider:!0}:Array.isArray(d?.items)?{...d,items:n(d.items,w+1)}:d):m};const t={...u.brand},s=t.size&&t.size!=="md"?` navbar-brand-${t.size}`:"";if(t.logo||t.icon||t.tagline){let m="";t.logo?m+=`<img src="${t.logo}" class="navbar-brand-logo" alt="${t.text||""}">`:t.icon&&(m+=`<span data-icon="${t.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),t.text&&(m+=`<span class="navbar-brand-text${s}">${t.text}</span>`),t.tagline&&(m+=`<small class="navbar-brand-tagline">${t.tagline}</small>`),t.html=m}else s&&t.text&&(t.html=`<span class="navbar-brand-text${s}">${t.text}</span>`);const e=n(u.items||[]),o=u.position==="floating",c=u.orientation==="vertical";L.get(0).querySelector(":scope > .cms-nojs-links")?.remove(),Domma.elements.navbar("#site-navbar",{brand:t,items:e,variant:u.variant||"dark",position:o?"static":u.position||"sticky",collapsible:!0,appearOnHover:!!u.appearOnHover}),Domma.icons.scan("#site-navbar");const f=L.get(0);oe(f,u.mobile);const a=()=>{if(!c)return;const w=f.querySelector('a[aria-current="page"]')?.closest(".navbar-dropdown");w&&!w.classList.contains("open")&&w.querySelector(":scope > .navbar-dropdown-toggle")?.click()};f.classList.add(`dm-nav-align-${le(u)||"centre"}`),c&&L.get(0).classList.add("dm-nav-vertical",u.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left");const h=u.dock||{};c&&!o&&$e(f,u.side==="right"),!c&&h.hideOnScroll&&Ee(f),V(f,u),X(f,u),j(f,u.class),o&&(ie(L.get(0),u),pe(L.get(0).parentNode||document));const l=f.querySelector(".navbar-toggle"),y=f.querySelector(".navbar-collapse");if(l&&y){let m=null;const w=()=>{y.classList.contains("show")&&l.click()},d=()=>{m&&(m.remove(),m=null),document.body.classList.remove("dm-drawer-open")},p=()=>{m||(m=document.createElement("div"),m.className="dm-navbar-backdrop",m.addEventListener("click",w),document.body.appendChild(m),document.body.classList.add("dm-drawer-open"))};l.addEventListener("click",()=>{requestAnimationFrame(()=>{y.classList.contains("show")?(a(),p()):d()})}),y.addEventListener("click",v=>{v.target.closest("a")&&requestAnimationFrame(d)}),document.addEventListener("keydown",v=>{v.key==="Escape"&&y.classList.contains("show")&&w()})}const C=f.querySelector(".navbar-nav");if(C){const m=Array.from(C.children);let w=0;for(const d of u.items||[])if(!(d&&d.type==="separator")){if(d&&d.type==="spacer"){const p=document.createElement("li"),v=["xs","sm","md","lg","xl","flex"].includes(d.size)?d.size:"md";p.className=`dm-menu-spacer dm-menu-spacer--${v}`,p.setAttribute("aria-hidden","true"),C.insertBefore(p,m[w]||null);continue}if(d&&d.type==="theme-switcher"){const p=document.createElement("li");p.className="dm-menu-theme-switcher";const v=document.createElement("span");v.dataset.themeSwitcher="menu",v.dataset.position="inline",p.appendChild(v),C.insertBefore(p,m[w]||null);continue}w++}window.CMSThemeSwitcher?.scan(C)}f.querySelectorAll("[data-path]").forEach(m=>{const w=m.dataset.path.split(".").map(Number),d=w.length>1,p=w.reduce((A,i)=>A?.items?.[i],{items:e});if(!p)return;p.colour&&U(m,p.colour),p.pill&&!d&&ae(m,p.pill),re(m,p),j(m.closest("li"),p.class);const v=J(p.badge);v&&m.appendChild(v),G(p.url,location.pathname)&&(m.classList.add("active"),m.setAttribute("aria-current","page"))}),de(f,u,e),a()}let k=null;const x=$("#site-footer");if(x.length){let o=function(i){return String(i??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},c=function(i){return o(i).replace(/'/g,"&#39;")},f=function(i){if(i&&i.type==="separator")return'<li class="footer-sep"><hr></li>';if(i&&i.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(i.size)?i.size:"md"}" aria-hidden="true"></li>`;if(i&&i.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const M=c(i.url||"#"),q=o(i.text||""),g=Array.isArray(i.items)&&i.items.length?`<ul>${i.items.map(f).join("")}</ul>`:"",D=ce(i),N=[D.hover&&` data-menu-item-hover="${c(D.hover)}"`,D.active&&` data-menu-item-active="${c(D.active)}"`].filter(Boolean).join(""),O=D.accent?` style="--dm-menu-highlight:${c(D.accent)}"`:"",R=Y(i.class).join(" ");return`<li${R?` class="${c(R)}"`:""}><a href="${M}"${N}${O}>${q}</a>${g}</li>`},h=function(){if(!r.footer)return"";const i=Object.keys(s).filter(q=>t[q]);if(!i.length)return"";const M=Y(r.footer.socialClass).join(" ");return`<div class="footer-social">${i.map(q=>{const{label:g,svg:D}=s[q];return`<a href="${t[q]}" target="_blank" rel="noopener noreferrer" aria-label="${g}" class="footer-social-link${M?` ${c(M)}`:""}">${D}</a>`}).join("")}</div>`},m=function(i){if(!i||i.type==="separator"||i.type==="spacer")return"";if(i.type==="theme-switcher")return`<li class="cms-footer-col">${f(i).replace(/^<li[^>]*>|<\/li>$/g,"")}</li>`;const M=Array.isArray(i.items)&&i.items.length?`<ul>${i.items.map(f).join("")}</ul>`:"",q=C(i)?`<span class="cms-footer-col-title">${o(i.text||"")}</span>`:`<a class="cms-footer-col-title" href="${c(i.url||"#")}">${o(i.text||"")}</a>`,g=["cms-footer-col",...Y(i.class)].join(" ");return`<li class="${c(g)}">${q}${M}</li>`},p=function(i,M,q=!1){return(i||[]).forEach(g=>{g&&(g.type==="separator"||g.type==="spacer"||g.type==="theme-switcher")||(q&&C(g)||M.push(g),Array.isArray(g.items)&&g.items.length&&p(g.items,M))}),M};const t=r.social||{},s={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 n='<div class="footer-inner container">';const e=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""},a=(()=>{const i=r.cookieConsent;if(!i||i.showSettingsLink===!1)return"";const M=q=>(q||[]).some(g=>g&&(g.url==="#cookie-settings"||M(g.items)));return M(e.primary)||M(e.legal)?"":`<li class="cms-cookie-settings"><a href="#cookie-settings">${o(i.settingsLinkText||"Cookie settings")}</a></li>`})(),l=["columns","row"].includes(r.footer?.layout)?r.footer.layout:"auto",y=r.footer?.look==="showcase"||l==="columns"||l==="auto"&&e.primary.some(i=>Array.isArray(i?.items)&&i.items.length),C=i=>y&&!i.url&&Array.isArray(i.items)&&i.items.length>0;if(y){const i=u.brand||{},M=i.text||r.title||"",q=i.logo?`<img src="${c(i.logo)}" class="cms-footer-brand-logo" alt="">`:i.icon?'<span class="cms-footer-brand-icon"></span>':"",g=String(r.footer?.blurb||"").trim();n='<div class="footer-inner footer-inner--columns container"><div class="cms-footer-top">',n+=`<div class="cms-footer-brand">${M||q?`<a class="cms-footer-brand-name" href="${c(i.url||"/")}">${q}<span>${o(M)}</span></a>`:""}${g?`<p class="cms-footer-blurb">${o(g)}</p>`:""}${h()}</div>`,e.primary.length&&(n+=`<nav class="footer-nav footer-nav--primary footer-nav--columns" aria-label="Footer"><ul>${e.primary.map(m).join("")}</ul></nav>`),n+='</div><div class="cms-footer-bottom">',e.copyright&&(n+=`<p class="cms-footer-copyright">${o(e.copyright)}</p>`),(e.legal.length||a)&&(n+=`<nav class="footer-nav footer-nav--legal" aria-label="Legal"><ul>${e.legal.map(f).join("")}${a}</ul></nav>`),n+="</div>"}else e.copyright&&(n+=`<p>${o(e.copyright)}</p>`),e.primary.length&&(n+=`<nav class="footer-nav footer-nav--primary"><ul>${e.primary.map(f).join("")}</ul></nav>`),(e.legal.length||a)&&(n+=`<nav class="footer-nav footer-nav--legal"><ul>${e.legal.map(f).join("")}${a}</ul></nav>`),n+=h();n+="</div>",x.get(0).querySelector(":scope > .cms-nojs-links")?.remove();const w=x.get(0).querySelector(":scope > .cms-footer-blocks");w?.remove(),x.html(n),w&&x.get(0).prepend(w),window.CMSThemeSwitcher?.scan(x.get(0));const d=x.get(0).querySelector(".cms-footer-brand-icon");d&&u.brand?.icon&&d.setAttribute("data-icon",u.brand.icon),j(x.get(0),r.footer?.class),y&&ue(x.get(0),r);const v=[...p(e.primary,[],!0),...p(e.legal,[])];x.get(0).querySelectorAll(".footer-nav a").forEach((i,M)=>{const q=v[M];if(!q)return;q.colour&&U(i,q.colour);const g=J(q.badge);g&&i.appendChild(g),G(q.url,location.pathname)&&(i.classList.add("is-active"),i.setAttribute("aria-current","page"))}),V(x.get(0).querySelector(".footer-nav--primary"),{highlight:e.primaryHighlight}),V(x.get(0).querySelector(".footer-nav--legal"),{highlight:e.legalHighlight}),X(x.get(0).querySelector(".footer-nav--primary"),{entrance:e.primaryEntrance}),X(x.get(0).querySelector(".footer-nav--legal"),{entrance:e.legalEntrance}),j(x.get(0).querySelector(".footer-nav--primary"),e.primaryClass),j(x.get(0).querySelector(".footer-nav--legal"),e.legalClass),k=x.get(0).querySelector(".cms-footer-bottom")||x.get(0).querySelector(".footer-inner")}he(r.motion||{enabled:r.footer?.showMotionToggle!==!1,default:r.footer?.motionDefault,placement:"footer",control:r.footer?.motionControl,label:"Reduce motion"},{footer:k,navbar:document.querySelector("#site-navbar .navbar-container")?.closest("#site-navbar")||null});const I=document.getElementById("site-sidebar");I&&Ae(I),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const b=$(".page-body");if(b.length){b.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),b.find(".tabs").each(function(){Domma.elements.tabs(this)}),b.find(".carousel").each(function(){const s={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"},n=h=>{const l=String(h||"").trim();return l?s[l.toLowerCase()]?`var(${s[l.toLowerCase()]})`:CSS.supports("color",l)?l:"":""},e=n(this.dataset.background),o=n(this.dataset.arrowBackground),c=n(this.dataset.arrowColor);e&&(this.style.setProperty("--dm-carousel-background",e),this.classList.add("dm-carousel-custom-background")),o&&this.style.setProperty("--dm-carousel-arrow-background",o),c&&this.style.setProperty("--dm-carousel-arrow-color",c);const f=["top","middle","bottom"].includes(this.dataset.arrowPosition)?this.dataset.arrowPosition:"middle";this.classList.add(`dm-carousel-arrows-${f}`);const a={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&&(a.height=h)}if(this.dataset.animationDuration){const h=parseInt(this.dataset.animationDuration,10);Number.isFinite(h)&&(a.animationDuration=h)}this.dataset.animationEasing&&(a.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(h=>h.cloneNode(!0)),this._dmCarouselOpts=a),this._dmCarousel=Domma.elements.carousel(this,a),ne(this)}),b.find(".dm-countdown").each(function(){const s={autoStart:!0},n=String(this.dataset.format||"").trim(),e=String(this.dataset.to||"").trim(),o=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e),c=o?new Date(+o[1],+o[2]-1,+o[3]).getTime():e?new Date(e).getTime():NaN;Number.isFinite(c)?s.duration=Math.max(0,c-Date.now()):this.dataset.duration&&(s.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const f=/^dd:/i.test(n);s.format=f?"hh:mm:ss":n||(s.duration>=36e5?"hh:mm:ss":"mm:ss");const a=this,h=y=>String(y).padStart(2,"0"),l=y=>{const C=Math.max(0,Math.floor(y/1e3)),m=a.querySelector(".dm-timer-time");m&&(m.textContent=`${h(Math.floor(C/86400))}:${h(Math.floor(C%86400/3600))}:${h(Math.floor(C%3600/60))}:${h(C%60)}`)};f&&(s.onTick=l),Domma.elements.timer(this,s),f&&l(s.duration||0)}),b.find("[data-tooltip]:not(.dm-range-slider)").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),b.find(".dm-progression").each(function(){const s=Array.from(this.querySelectorAll(".dm-progression-item")).map(o=>{const c={title:o.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:o.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return o.dataset.date&&(c.date=o.dataset.date),o.dataset.status&&(c.status=o.dataset.status),o.dataset.eventIcon&&(c.icon=o.dataset.eventIcon),o.dataset.entryId&&(c._entryId=o.dataset.entryId),c}),n=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",e=Domma.elements.progression(this,{layout:n,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...s.length?{items:s}:{}});if((this.dataset.mode||"timeline")==="timeline"){const o={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((c,f)=>{const a=s[f];if(!a)return;const h=c.querySelector(".dm-progression-title");if(a.icon&&h){const y=document.createElement("span");y.dataset.icon=a.icon,y.style.cssText="display:inline-flex;vertical-align:middle;margin-right:.4em",y.setAttribute("aria-hidden","true"),h.prepend(y)}const l=o[a.status];if(l&&h){const y=document.createElement("span");y.className=`badge badge-${l.tone} cms-timeline-status`,y.style.cssText="display:inline-flex;align-items:center;gap:.35em;margin:.4rem 0";const C=document.createElement("span");C.dataset.icon=l.icon,C.dataset.iconSize="14",C.setAttribute("aria-hidden","true"),y.append(C,document.createTextNode(l.label)),h.after(y)}})}Domma.icons.scan(this),s.length&&(this._dmCtx={instance:e,items:s})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}const t=matchMedia("(prefers-reduced-motion: reduce)").matches||document.documentElement.classList.contains("dm-reduced-motion");document.querySelectorAll(".page-body .row[data-reveal]").forEach(s=>{const n=s.dataset.revealMode||"stagger",e=s.dataset.revealAnimation||"slide-up",o=parseInt(s.dataset.revealDuration,10)||(e.startsWith("swoosh")?700:400),c=parseInt(s.dataset.revealStagger,10)||(e.startsWith("swoosh")?90:60),f=parseInt(s.dataset.revealDelay,10)||0,a=s.dataset.revealDirection==="rtl",h=s.dataset.revealReplay==="true",l=Array.from(s.children);if(t&&e.startsWith("swoosh"))return;const y={"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)",swoosh:"translateY(36px) scale(0.96)"},C=p=>e!=="swoosh-sides"?y[e]||"":l.length>1&&p===0?"translateX(-64px) rotate(-1.5deg)":l.length>1&&p===l.length-1?"translateX(64px) rotate(1.5deg)":"translateY(40px) scale(0.94)",m=e.startsWith("swoosh"),w=m?"cubic-bezier(.2,.8,.2,1)":"ease",d=(p,v)=>{p.style.opacity="0",p.style.transform=C(v),m&&(p.style.filter="blur(10px)")};l.forEach((p,v)=>{d(p,v),p.style.transition=`opacity ${o}ms ${w}, transform ${o}ms ${w}`+(m?`, filter ${o}ms ${w}`:"");const A=a?l.length-1-v:v;p.style.transitionDelay=n==="stagger"?`${f+A*c}ms`:`${f}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const p=new IntersectionObserver(v=>{v.forEach(A=>{if(A.isIntersecting){if(A.target.offsetWidth,A.target.style.opacity="1",A.target.style.transform="",m&&(A.target.style.filter=""),!h){p.unobserve(A.target);const i=A.target;i.addEventListener("transitionend",function M(q){q.target!==i||q.propertyName!=="opacity"||(i.removeEventListener("transitionend",M),i.style.transition="",i.style.transitionDelay="")})}}else h&&A.boundingClientRect.top>0&&d(A.target,l.indexOf(A.target))})},{threshold:.1});l.forEach(v=>p.observe(v))}))}),me(document.querySelector(".page-body")||document),b.find(".card[data-collapsible]").each(function(){const s=this.querySelector(".card-header");s&&s.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),b.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const s=this.dataset.soTarget,n=document.getElementById(s);if(!n)return;const e=E.slideover({title:n.dataset.soTitle||"",size:n.dataset.soSize||"md",position:n.dataset.soPosition||"right"});n.style.display="",e.setContent(n),e.open()})})}if(typeof $.setup=="function"){const t=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(s=>{try{const n=W(s.dataset.config);Object.assign(t,n)}catch{}}),Object.keys(t).length>0){const s={};for(const[n,e]of Object.entries(t)){const o=e?.events?.click,{confirm:c,toast:f,alert:a,prompt:h,...l}=o||{};if(c||f||a||h){$(n).on("click",async function(R){if(R.preventDefault(),c&&!await E.confirm(c))return;let z=null;if(!(h&&(z=await E.prompt(h,{inputPlaceholder:l.promptPlaceholder||"",inputValue:l.promptDefault||""}),z===null))){{const B=$(l.target||this);l.toggleClass&&B.toggleClass(l.toggleClass),l.addClass&&B.addClass(l.addClass),l.removeClass&&B.removeClass(l.removeClass),z!==null&&(l.setText&&B.text(z),l.setVal&&B.val(z),l.setAttr&&B.attr(l.setAttr,z))}l.href&&(window.location.href=l.href),f&&E.toast(f,{type:l.toastType||"success"}),a&&E.alert(a)}});const{target:C,toggleClass:m,addClass:w,removeClass:d,setText:p,setVal:v,setAttr:A,href:i,toastType:M,promptPlaceholder:q,promptDefault:g,...D}=l,N={...e.events};Object.keys(D).length?N.click=C?{target:C,...D}:D:delete N.click;const O={...e,events:N};Object.keys(N).length||delete O.events,Object.keys(O).length&&(s[n]=O)}else s[n]=e}$.setup(s)}}b.length&&P(b.get(0))}),window.wireCTAButtons=P;function P(u){u.querySelectorAll(".dm-cta-trigger").forEach(r=>{r.__ctaWired||(r.__ctaWired=!0,r.addEventListener("click",async()=>{const L=r.dataset.action,k=r.dataset.entry,x=r.dataset.confirm;let I=S.get("auth_token");if(!I){E.toast("Please log in to perform this action.",{type:"warning"});return}if(x&&!await E.confirm(x))return;const b=Array.from(r.childNodes).map(s=>s.cloneNode(!0));r.disabled=!0,r.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${L}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(r.dataset.scope?{entryId:k,scope:r.dataset.scope}:{entryId:k})});try{let s=await t(I);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const o=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(o.ok){const{token:c}=await o.json();S.set("auth_token",c),I=c,s=await t(I)}}}const n=await s.json().catch(()=>({}));if(!s.ok||n.success===!1)throw new Error(n.error||n.message||`Error ${s.status}`);E.toast(n.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{r.disabled=!1,r.textContent="",b.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 L=S.get("auth_token");function k(I,b){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(b){s.appendChild(document.createTextNode("Please "));const n=document.createElement("a");n.href="/login",n.textContent="sign in",s.appendChild(n),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=I;return t.appendChild(s),t}function x(I,b){const t=document.createElement("template");t.innerHTML=b||"",I.replaceWith(t.content)}r.forEach(async I=>{const b=I.dataset.collectionAttrs;if(!b)return;if(!L){I.replaceChildren(k("",!0));return}const t=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:b})});try{let s=L,n=await t(s);if(n.status===401){const o=S.get("auth_refresh_token");if(o){const c=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:o})});if(c.ok){const{token:f}=await c.json();S.set("auth_token",f),s=f,n=await t(s)}}}if(!n.ok){const{error:o}=await n.json().catch(()=>({}));I.replaceChildren(k(o||"Unable to load entries.",!1));return}const{html:e}=await n.json();x(I,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{I.replaceChildren(k("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),P(document.body)},100)})(),(function(){const r=document.querySelectorAll("[data-collection-table]");!r.length||typeof T>"u"||!T.create||r.forEach(L=>{let k;try{k=W(L.dataset.payload)}catch{return}const{columns:x,rows:I,search:b,sortable:t,exportable:s,pageSize:n,empty:e,ctaConfig:o,slug:c,exportCfg:f}=k;if(!x?.length)return;if(o){const l=x.findIndex(y=>y.key==="_cta");l!==-1&&(x[l]={key:"_cta",title:"",render:(y,C)=>{const m=document.createElement("button");if(m.className=`btn btn-${o.style||"primary"} dm-cta-trigger`,m.dataset.action=o.action||"",o.scope&&(m.dataset.scope=o.scope),m.dataset.entry=C._entryId||"",o.confirm&&(m.dataset.confirm=o.confirm),o.icon){const w=document.createElement("span");w.dataset.icon=o.icon,m.appendChild(w),m.appendChild(document.createTextNode(" "))}return m.appendChild(document.createTextNode(o.label||"Run")),m}})}const a="col-table-"+Math.random().toString(36).slice(2,7),h=document.createElement("div");h.id=a,L.replaceChildren(h),T.create("#"+a,{data:I,columns:x,search:b,sortable:t,exportable:s,pageSize:n,emptyMessage:e}),o&&P(h),L._dmTable={columns:x,rows:I,slug:c,exportCfg:f,render(l){T.create("#"+a,{data:l,columns:x,search:b,sortable:t,exportable:s,pageSize:n,emptyMessage:e}),o&&P(h)}}})})(),(function(){const r=document.querySelectorAll("[data-form-inline]");if(!r.length||typeof F>"u")return;function L(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function k(t,s){const n={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const o=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),c=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":o?"chooser":e.type,f={...e.formConfig||{}};f.span==="full"&&s&&(f.span=s);const a={type:c,required:L(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},...f}};e.minLength!==void 0&&(a.minLength=e.minLength),e.maxLength!==void 0&&(a.maxLength=e.maxLength),e.min!==void 0&&(a.min=e.min),e.max!==void 0&&(a.max=e.max),o&&(e.variant&&(a.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(a.multiple=!0),e.density&&(a.density=e.density),e.columns&&(a.columns=e.columns),e.accent&&(a.accent=e.accent),e.accentStyle&&(a.accentStyle=e.accentStyle),e.glow&&(a.glow=!0),e.glowColour&&(a.glowColour=e.glowColour),e.shadow&&(a.shadow=e.shadow),e.shadowColour&&(a.shadowColour=e.shadowColour)),n[e.name]=e.type==="file"?be(e,a):a}),n}function x(t){const s={};return(t||[]).forEach(n=>{if(!(!n.name||n.type==="page-break"||n.type==="spacer")&&(n.type==="select"||n.type==="multiselect")&&n.required){const e=(n.options||[])[0];e&&(s[n.name]=typeof e=="object"?e.value:e)}}),s}function I(t,s){(s||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const e=t.querySelector(`[name="${n.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function b(t,s,n){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=s,e.style.cssText=n?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}r.forEach(t=>{let s;try{s=W(t.dataset.formInline)}catch{return}t.querySelector(":scope > .cms-form-embed-summary")?.remove();const n=s.fields||[],e=s.settings||{},o=Number(e.columns)===3?3:2,c=e.layout||"grid",f=n.some(w=>w.type==="page-break"),a=new Map;Ce(t,s.fileLimits,a),Le(t,n);const h=async w=>{if(t.dataset.triggerBlocked==="true"){const d=t._formLogicRuntime,p=d&&d.submitBlock?d.submitBlock().reasons:[];b(t,p.join(" ")||"This form cannot be submitted yet.",!0);const v=new Error("Blocked by a form trigger");throw v.formSubmitFailed=!0,v}try{const d=t.querySelector(".fb-form-honeypot"),p=d?.querySelector('input[type="text"]')||null,v=d?.querySelector('[name="_t"]')||null,A=Object.assign({},w);delete A._t,d?.dataset.hpName&&delete A[d.dataset.hpName],p!==null&&(A._hp=p.value),v!==null&&(A._t=v.value);const i=new Map(a);te(t,i);const M=Se(A,n,i),q=ke(t,M.files);if(q){b(t,q,!0);const D=new Error(q);throw D.formSubmitFailed=!0,D}const g=await H.post(`/api/forms/submit/${s.slug}`,M.files.size?xe(M.values,M.files).body:M.values);if(g&&g.error){b(t,g.error,!0);const D=new Error(g.error);throw D.formSubmitFailed=!0,D}if(g?.redirect){window.location.href=g.redirect;return}for(ve(t);t.firstChild;)t.removeChild(t.firstChild);b(t,g?.message||e.successMessage||"Thank you for your submission.",!1)}catch(d){throw d.formSubmitFailed||b(t,d.message||"Submission failed. Please try again.",!0),d}},l=Date.now();function y(w){const d=w.querySelector("form");if(!d||d.querySelector(".fb-form-honeypot"))return;const p=document.createElement("div");p.className="fb-form-honeypot",p.setAttribute("aria-hidden","true");const v=document.createElement("input");v.name=d.querySelector('[name="website"]')?"_website":"website",p.dataset.hpName=v.name,v.type="text",v.tabIndex=-1,v.autocomplete="url",v.placeholder="https://",p.appendChild(v);const A=document.createElement("input");A.name="_t",A.type="hidden",A.value=l,p.appendChild(A),d.appendChild(p)}function C(w){if(!window.FormLogicEngine||!n.some(p=>p.logic||Array.isArray(p.triggers)&&p.triggers.length))return null;const d=new window.FormLogicEngine.FormLogicRuntime(s,t,w?{baseValues:w}:void 0);if(d.init(),t._formLogicRuntime=d,t._formLogicObserved)return d;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const p=new MutationObserver(function(v){for(const A of v)for(const i of A.removedNodes)if(i===t||i.nodeType===1&&i.contains&&i.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),p.disconnect();return}});p.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=p}return d}let m=!1;if(t.addEventListener("dm-form-end",w=>{const d=w.detail?.validation;if(d&&!d.valid){Q(t,d.missing),Z(d);return}m||(m=!0,h(w.detail?.values||{}).catch(()=>{}).finally(()=>{m=!1}))}),f&&F.wizard){const w=fe(n,s.title),d=w.map(g=>({title:g.title,description:g.description,fields:k(g.fields,o)})),p=w.map(g=>g.fields);let v=0,A=null,i=null;const M=g=>{const D=window.FormLogicEngine;if(!D||!D.validateFields)return;const N=D.validateFields(t,p[v]||[]);N.valid||(g.preventDefault(),g.stopImmediatePropagation(),Q(t,N.missing),Z(N))},q=()=>{const g=p[v]||n;ye(t,e),ee(t,e,g),I(t,g),K(t,g),we(t,a),e.honeypot!==!1&&y(t),A&&A.destroy(),A=C(i?.getStepData?i.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(D=>D.addEventListener("click",M,!0))};i=F.wizard(t,{schema:{steps:d},layout:c,columns:o,finishText:e.submitText||"Finish",onSubmit:h,onStepChange:g=>{te(t,a),v=g,setTimeout(q,0)}}),t.addEventListener("dm-form-trigger",g=>{if(g.detail?.type!=="goto-step"||!i?.goToStep)return;const D=Number(g.detail.action.step);!Number.isFinite(D)||D<0||D>=d.length||D!==v&&i.goToStep(D)}),Promise.resolve(i).then(q)}else if(F.render){const w=F.render(t,k(n,o),x(n),{submitText:e.submitText||"Submit",layout:c,columns:o,onSubmit:h});Promise.resolve(w).then(function(){ge(t,e,c),ee(t,e,n),I(t,n),K(t,n),e.honeypot!==!1&&y(t),C()})}})})();function $e(u,r){const L=document.body,k=L.classList,x=new Set((L.dataset.railSite||"").split(" ").filter(Boolean)),I=()=>window.matchMedia("(min-width: 993px)").matches;u.querySelectorAll(".navbar-link, .navbar-dropdown-toggle").forEach(o=>{const c=o.textContent.trim();c&&(o.setAttribute("title",c),o.querySelector("svg, [data-icon]")||(o.dataset.initial=c.charAt(0).toUpperCase()))});const b=document.createElement("button");b.type="button",b.className="dm-nav-collapse-toggle";const t=()=>{const o=k.contains("dm-vnav-collapsed");b.setAttribute("aria-pressed",String(o)),b.setAttribute("aria-label",o?"Expand menu":"Collapse menu"),b.title=b.getAttribute("aria-label");const c=r?"chevrons-left":"chevrons-right",f=r?"chevrons-right":"chevrons-left";b.innerHTML=`<span data-icon="${o?c:f}"></span>`,window.Domma&&Domma.icons&&Domma.icons.scan(b)},s=o=>{k.toggle("dm-vnav-collapsed",o),S.set("nav_collapsed",o),t()};b.addEventListener("click",()=>s(!k.contains("dm-vnav-collapsed"))),t();const n=u.querySelector(".navbar-container")||u;n.insertBefore(b,n.firstChild?.nextSibling||null);const e=o=>{k.toggle("dm-vnav-autohide",o),k.toggle("dm-vnav-collapsible",!o&&x.has("collapsible")),o?k.remove("dm-vnav-collapsed"):x.has("collapsible")&&S.get("nav_collapsed")===!0&&k.add("dm-vnav-collapsed"),u.classList.remove("dm-nav-revealed"),t()};u.addEventListener("pointerdown",o=>{k.contains("dm-vnav-autohide")&&o.pointerType!=="mouse"&&!u.classList.contains("dm-nav-revealed")&&(u.classList.add("dm-nav-revealed"),o.preventDefault())}),document.addEventListener("pointerdown",o=>{u.contains(o.target)||u.classList.remove("dm-nav-revealed")}),window.E&&typeof E.contextMenu=="function"&&E.contextMenu(u,{items:()=>{const o=k.contains("dm-vnav-autohide"),c=k.contains("dm-vnav-collapsed"),f=S.has("nav_autohide")||S.has("nav_collapsed");return[{header:"Menu"},{label:c?"Expand menu":"Collapse to icons",icon:c?"maximize":"minimize",disabled:!I()||o||!x.has("collapsible"),action:()=>s(!c)},{label:o?"Keep on screen":"Hide when not in use",icon:o?"eye":"eye-off",disabled:!I(),action:()=>{S.set("nav_autohide",!o),e(!o)}},{type:"divider"},{label:"Reset to the site's setting",icon:"refresh",disabled:!f,action:()=>{S.remove("nav_autohide"),S.remove("nav_collapsed"),e(x.has("autohide")),k.toggle("dm-vnav-collapsed",!x.has("autohide")&&x.has("start-collapsed")),t()}}]}})}function Ee(u){u.classList.add("dm-nav-scroll-hide");let r=window.scrollY,L=!1;window.addEventListener("scroll",()=>{L||(L=!0,requestAnimationFrame(()=>{L=!1;const k=window.scrollY,x=u.matches(":focus-within")||u.querySelector(".navbar-dropdown.open, .navbar-collapse.show");k>r&&k>u.offsetHeight&&!x?u.classList.add("dm-nav-scrolled-away"):k<r&&u.classList.remove("dm-nav-scrolled-away"),r=k}))},{passive:!0})}function Ae(u){let r={};try{r=JSON.parse(u.dataset.contents||"{}")}catch{}const L=u.closest(".site-main"),k=document.querySelector(".site-content"),x=new Set(String(r.exclude||"").split(",").map(a=>a.trim().toLowerCase()).filter(Boolean)),I=a=>!a.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),b=a=>(k?[...k.querySelectorAll(a)]:[]).filter(I).filter(h=>!x.has(h.textContent.trim().toLowerCase())),t=r.headings==="h2"?b("h2"):r.headings==="h3"?b("h3"):r.headings==="h2h3"?b("h2, h3"):b("h2").length?b("h2"):b("h3");if(!t.length){L?.classList.add("no-sidebar-items");return}const s=new Set([...document.querySelectorAll("[id]")].map(a=>a.id)),n=document.createElement("nav");n.className="dm-contents",n.setAttribute("aria-label",r.title||"Page contents"),r.hover&&(n.dataset.menuHover=r.hover),r.selected&&(n.dataset.menuActive=r.selected),r.accent&&n.style.setProperty("--dm-menu-highlight",r.accent.startsWith("#")?r.accent:`var(--dm-${r.accent})`),r.font&&(n.style.fontFamily=r.font),r.fontSize&&(n.style.fontSize=r.fontSize),r.fontWeight&&(n.style.fontWeight=r.fontWeight);const e=document.createElement("div");e.className="dm-contents-head";const o=document.createElement("p");o.className="dm-contents-title",o.textContent=r.title||"",e.appendChild(o),n.appendChild(e);const c=document.createElement("ol");c.className="dm-contents-list"+(r.numbered?" is-numbered":"");const f=[];for(const a of t){if(!a.id){const y=(a.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let C=y;for(let m=2;s.has(C);m++)C=`${y}-${m}`;s.add(C),a.id=C}const h=document.createElement("li");h.className=`dm-contents-item dm-contents-${a.tagName.toLowerCase()}`;const l=document.createElement("a");l.href=`#${a.id}`,l.textContent=a.textContent.trim(),h.appendChild(l),c.appendChild(h),f.push([a,l])}if(n.appendChild(c),u.replaceChildren(n),r.scrollSpy!==!1&&"IntersectionObserver"in window){const a=new Map,h=()=>{const y=f.find(([C])=>a.get(C))||null;f.forEach(([,C])=>{const m=y&&C===y[1];C.classList.toggle("is-active",!!m),m?C.setAttribute("aria-current","location"):C.removeAttribute("aria-current")})},l=new IntersectionObserver(y=>{y.forEach(C=>a.set(C.target,C.isIntersecting)),h()},{rootMargin:"-80px 0px -60% 0px"});f.forEach(([y])=>l.observe(y))}if(L?.classList.contains("contents-collapsible")){const a=document.createElement("button");a.type="button",a.className="dm-contents-toggle";const h=()=>{const l=L.classList.contains("contents-collapsed");a.setAttribute("aria-expanded",String(!l)),a.setAttribute("aria-label",l?"Show the contents":"Hide the contents"),a.title=a.getAttribute("aria-label"),a.innerHTML=`<span data-icon="${l?"list":"x"}"></span>`,window.Domma?.icons&&Domma.icons.scan(a)};a.addEventListener("click",()=>{S.set("contents_collapsed",L.classList.toggle("contents-collapsed")),h()}),h(),e.insertBefore(a,e.firstChild)}if(L?.classList.contains("contents-floating")&&r.movable){n.classList.add("is-movable");const a=S.get("contents_position");a&&Number.isFinite(a.x)&&Object.assign(u.style,{left:`${a.x}px`,top:`${a.y}px`,right:"auto",bottom:"auto"}),e.addEventListener("pointerdown",h=>{if(h.target.closest("button"))return;const l=u.getBoundingClientRect(),y=h.clientX-l.left,C=h.clientY-l.top,m=d=>{const p=Math.max(0,Math.min(window.innerWidth-l.width,d.clientX-y)),v=Math.max(0,Math.min(window.innerHeight-40,d.clientY-C));Object.assign(u.style,{left:`${p}px`,top:`${v}px`,right:"auto",bottom:"auto"})},w=()=>{document.removeEventListener("pointermove",m),S.set("contents_position",{x:parseInt(u.style.left,10),y:parseInt(u.style.top,10)})};document.addEventListener("pointermove",m),document.addEventListener("pointerup",w,{once:!0})})}window.E&&typeof E.contextMenu=="function"&&E.contextMenu(u,{items:()=>{const a=L?.classList.contains("contents-collapsible"),h=L?.classList.contains("contents-collapsed"),l=f.find(([,y])=>y.classList.contains("is-active"));return[{header:"Contents"},...a?[{label:h?"Show the contents":"Collapse to a button",icon:h?"list":"minimize",action:()=>u.querySelector(".dm-contents-toggle")?.click()}]:[],{label:"Copy a link to this section",icon:"link",disabled:!l,action:async()=>{const y=`${location.origin}${location.pathname}#${l[0].id}`;try{await _.copyToClipboard(y),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"})}]}}),L?.classList.contains("contents-autohide")&&(u.addEventListener("pointerdown",a=>{a.pointerType!=="mouse"&&!u.classList.contains("is-revealed")&&(u.classList.add("is-revealed"),a.preventDefault())}),document.addEventListener("pointerdown",a=>{u.contains(a.target)||u.classList.remove("is-revealed")}))}
@@ -20,6 +20,7 @@ import {fileURLToPath} from 'url';
20
20
  import * as cache from '../../services/cache/index.js';
21
21
  import {normaliseAdminPath} from '../../services/roles.js';
22
22
  import {cssClassProblems} from '../../../public/js/css-classes.mjs';
23
+ import {motionFooterMirror, normaliseMotionSettings} from '../../services/motionSettings.js';
23
24
  import {invalidateMeasurementId, measurementIdOf, normaliseMeasurementId} from '../../services/googleAnalytics.js';
24
25
 
25
26
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -124,7 +125,9 @@ export async function settingsRoutes(fastify) {
124
125
  // Designer classes on <body>, every page (Site Settings > Appearance).
125
126
  'bodyClass',
126
127
  // Google Analytics (Site Settings > Analytics) - services/googleAnalytics.js.
127
- 'googleAnalytics'
128
+ 'googleAnalytics',
129
+ // The "Reduce motion" control (Site Settings > Reduce motion) - services/motionSettings.js.
130
+ 'motion'
128
131
  ]);
129
132
  const unknownKeys = Object.keys(data).filter(k => !ALLOWED_KEYS.has(k));
130
133
  if (unknownKeys.length > 0) {
@@ -141,7 +144,7 @@ export async function settingsRoutes(fastify) {
141
144
  }
142
145
  // Designer classes - the same rules as menus and forms (css-classes.mjs).
143
146
  for (const [label, value] of [['Body CSS classes', data.bodyClass], ['Footer CSS classes', data.footer?.class],
144
- ['Social link CSS classes', data.footer?.socialClass]]) {
147
+ ['Social link CSS classes', data.footer?.socialClass], ['Reduce motion CSS classes', data.motion?.class]]) {
145
148
  const problems = cssClassProblems(value);
146
149
  if (problems.length) return reply.status(400).send({error: `${label}: ${problems[0]}.`});
147
150
  }
@@ -184,6 +187,24 @@ export async function settingsRoutes(fastify) {
184
187
  merged[k] = v;
185
188
  }
186
189
  }
190
+ // The Reduce motion control: stored whitelisted, with the footer keys it used to live
191
+ // under kept in step for older readers. A client that still writes only those footer
192
+ // keys (fleet tooling) moves the block with them, so its change is not overruled.
193
+ if ('motion' in data) {
194
+ if (data.motion !== null && (typeof data.motion !== 'object' || Array.isArray(data.motion))) {
195
+ return reply.status(400).send({error: 'Reduce motion: send an object.'});
196
+ }
197
+ merged.motion = normaliseMotionSettings(merged.motion, merged.footer);
198
+ merged.footer = {...merged.footer, ...motionFooterMirror(merged.motion)};
199
+ } else if (merged.motion && data.footer && typeof data.footer === 'object') {
200
+ const legacy = {showMotionToggle: 'enabled', motionDefault: 'default', motionControl: 'control'};
201
+ const moved = Object.entries(legacy).filter(([k]) => k in data.footer);
202
+ if (moved.length) {
203
+ const next = {...merged.motion};
204
+ for (const [k, key] of moved) next[key] = k === 'showMotionToggle' ? data.footer[k] !== false : data.footer[k];
205
+ merged.motion = normaliseMotionSettings(next, merged.footer);
206
+ }
207
+ }
187
208
  // Never erase smtp.pass with the empty string that the GET endpoint injects for safety
188
209
  if (merged.smtp && merged.smtp.pass === '' && existing.smtp?.pass) {
189
210
  merged.smtp = {...merged.smtp, pass: existing.smtp.pass};
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The "Reduce motion" control - `site.json` `motion` (Site Settings > Reduce motion).
3
+ *
4
+ * One pure normaliser, shared by the renderer (both render paths: the page's
5
+ * bootstrap default and the object site.js draws the control from) and the
6
+ * settings route (what is stored). Whitelisted and clamped rather than merged,
7
+ * because the result is written into the source of every public page.
8
+ *
9
+ * Until it had a tab of its own the control lived in the footer settings: `footer.showMotionToggle`,
10
+ * `footer.motionDefault` and `footer.motionControl`. A site with no `motion`
11
+ * block - or one missing a key - falls back to those, key by key, so every
12
+ * existing site renders exactly as before with no migration. The admin keeps
13
+ * writing them as a mirror for older readers and fleet tooling.
14
+ *
15
+ * No I/O here; tested in tests/services/motion-settings.test.js.
16
+ */
17
+ import {cssClasses} from '../../public/js/css-classes.mjs';
18
+
19
+ /** Today's behaviour: shown, in the footer, as a switch, following the device. */
20
+ export const MOTION_DEFAULTS = Object.freeze({
21
+ enabled: true,
22
+ default: 'system',
23
+ placement: 'footer',
24
+ control: 'switch',
25
+ triggerStyle: 'icon',
26
+ label: 'Reduce motion',
27
+ // Bottom left: clear of Search (right-centre) and Back to top (bottom right)
28
+ // at their defaults. public/js/motion-control.mjs stacks it clear of them
29
+ // anyway when a site moves one into the same corner.
30
+ position: 'BL',
31
+ offsetX: 32,
32
+ offsetY: 32,
33
+ iconSize: 52,
34
+ iconRadius: 26,
35
+ class: ''
36
+ });
37
+
38
+ export const MOTION_DEFAULT_CHOICES = ['system', 'off', 'on'];
39
+ export const MOTION_PLACEMENTS = ['footer', 'floating', 'navbar'];
40
+ export const MOTION_CONTROLS = ['switch', 'checkbox'];
41
+ export const MOTION_TRIGGER_STYLES = ['icon', 'icon-text'];
42
+ /** The breadcrumb corners - the Placement card's corner picker. */
43
+ export const MOTION_POSITIONS = ['TL', 'TR', 'BL', 'BR'];
44
+ export const MOTION_LABEL_MAX = 40;
45
+ /** The same limits as Search's floating disc (services/search.js). */
46
+ export const MOTION_ICON_SIZE_MIN = 32;
47
+ export const MOTION_ICON_SIZE_MAX = 96;
48
+ export const MOTION_OFFSET_MAX = 500;
49
+
50
+ const pick = (value, list, fallback) => (list.includes(value) ? value : fallback);
51
+
52
+ function num(value, fallback, min, max) {
53
+ const n = typeof value === 'number' ? value : (typeof value === 'string' && value.trim() ? Number(value) : NaN);
54
+ if (!Number.isFinite(n)) return fallback;
55
+ return Math.min(max, Math.max(min, Math.round(n)));
56
+ }
57
+
58
+ /**
59
+ * The settings a page and the admin act on.
60
+ *
61
+ * @param {object} [raw] - site.json `motion` (absent or partial is fine)
62
+ * @param {object} [footer] - site.json `footer`, for the keys the control used to live under
63
+ * @returns {object} every key of MOTION_DEFAULTS, nothing else
64
+ */
65
+ export function normaliseMotionSettings(raw, footer) {
66
+ const m = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
67
+ const f = footer && typeof footer === 'object' ? footer : {};
68
+ const has = (k) => m[k] !== undefined && m[k] !== null;
69
+
70
+ const enabledRaw = has('enabled') ? m.enabled : f.showMotionToggle;
71
+ const defaultRaw = has('default') ? m.default : f.motionDefault;
72
+ const controlRaw = has('control') ? m.control : f.motionControl;
73
+
74
+ const label = typeof m.label === 'string' && m.label.trim()
75
+ ? m.label.trim().replace(/\s+/g, ' ').slice(0, MOTION_LABEL_MAX)
76
+ : MOTION_DEFAULTS.label;
77
+
78
+ // The radius is clamped against the size (half of it is already a circle) - Search's rule.
79
+ const iconSize = num(m.iconSize, MOTION_DEFAULTS.iconSize, MOTION_ICON_SIZE_MIN, MOTION_ICON_SIZE_MAX);
80
+ const maxRadius = Math.floor(iconSize / 2);
81
+
82
+ return {
83
+ // Absent means shown, as footer.showMotionToggle always did.
84
+ enabled: enabledRaw !== false,
85
+ default: pick(defaultRaw, MOTION_DEFAULT_CHOICES, MOTION_DEFAULTS.default),
86
+ placement: pick(m.placement, MOTION_PLACEMENTS, MOTION_DEFAULTS.placement),
87
+ control: pick(controlRaw, MOTION_CONTROLS, MOTION_DEFAULTS.control),
88
+ triggerStyle: pick(m.triggerStyle, MOTION_TRIGGER_STYLES, MOTION_DEFAULTS.triggerStyle),
89
+ label,
90
+ position: pick(m.position, MOTION_POSITIONS, MOTION_DEFAULTS.position),
91
+ offsetX: num(m.offsetX, MOTION_DEFAULTS.offsetX, 0, MOTION_OFFSET_MAX),
92
+ offsetY: num(m.offsetY, MOTION_DEFAULTS.offsetY, 0, MOTION_OFFSET_MAX),
93
+ iconSize,
94
+ iconRadius: Math.min(maxRadius, num(m.iconRadius, MOTION_DEFAULTS.iconRadius, 0, maxRadius)),
95
+ class: cssClasses(typeof m.class === 'string' ? m.class : '').join(' ')
96
+ };
97
+ }
98
+
99
+ /** The settings for a site.json. */
100
+ export function motionSettingsOf(site) {
101
+ return normaliseMotionSettings(site?.motion, site?.footer);
102
+ }
103
+
104
+ /** The footer keys older readers look at, kept in step with a `motion` block. */
105
+ export function motionFooterMirror(settings) {
106
+ return {showMotionToggle: settings.enabled, motionDefault: settings.default, motionControl: settings.control};
107
+ }
@@ -16,6 +16,7 @@ import {getProjectForPage} from './projects.js';
16
16
  import {resolveContextMenusForPage} from './contextMenus.js';
17
17
  import {buildCustomThemeStyleTag, buildOverrideStyleTag, getThemeTokenMap, listThemeIds, loadThemeConfig, resolveThemeClasses} from './themeSettings.js';
18
18
  import {getSearchSettings} from './search.js';
19
+ import {motionSettingsOf} from './motionSettings.js';
19
20
  import {isToolEnabled} from './tools.js';
20
21
  import {consentSettingsFor, measurementIdOf} from './googleAnalytics.js';
21
22
  import {fmtDateTime} from './dates.js';
@@ -209,10 +210,30 @@ export async function buildFooterBlocks(site, ctx = {}) {
209
210
  return cols.length ? `<div class="cms-footer-blocks">${cols.join('')}</div>` : '';
210
211
  }
211
212
 
213
+ const MOTION_ASSET_V = '20261029-motion-under-switcher';
214
+
212
215
  /** The site's reduced-motion default for visitors who have not chosen: 'system', 'off' or 'on'. */
213
216
  function motionDefaultOf(site) {
214
- const d = site?.footer?.motionDefault;
215
- return d === 'off' || d === 'on' ? d : 'system';
217
+ return motionSettingsOf(site).default;
218
+ }
219
+
220
+ /**
221
+ * The "Reduce motion" control (site.json `motion`, Site Settings > Reduce motion):
222
+ * the whitelisted settings for window.__CMS_SITE__.motion - site.js draws the
223
+ * control from them (public/js/motion-control.mjs) - and its stylesheet. The
224
+ * old footer keys still count where `motion` says nothing (motionSettings.js).
225
+ *
226
+ * Both render paths need this - the standing trap in this file.
227
+ *
228
+ * @param {object} site - site.json
229
+ * @returns {{siteFields: {motion: object}, headTag: string}}
230
+ */
231
+ export function buildMotionAssets(site) {
232
+ const motion = motionSettingsOf(site);
233
+ return {
234
+ siteFields: {motion},
235
+ headTag: motion.enabled ? `<link rel="stylesheet" href="/public/css/motion.css?v=${MOTION_ASSET_V}">` : ''
236
+ };
216
237
  }
217
238
 
218
239
  /** The override a page's [navbar] tag left in its html (the first one), or null. */
@@ -450,6 +471,7 @@ export async function renderPage(page, opts = {}) {
450
471
 
451
472
  const themeView = await buildThemeView(page);
452
473
  const searchAssets = buildSearchAssets();
474
+ const motionAssets = buildMotionAssets(site);
453
475
  const footerBlocksHtml = preset.footer !== false ? await buildFooterBlocks(site, {user: opts.user || null, urlPath: menuCtx.urlPath, project: menuCtx.project, tags: opts.cacheTags}) : '';
454
476
  const switcherAssets = buildThemeSwitcherAssets(themeView.cfg, {
455
477
  html: `${page.html || ''}${overlayMenus}${footerBlocksHtml}`,
@@ -547,6 +569,8 @@ export async function renderPage(page, opts = {}) {
547
569
  footerScript: footerJson ? `window.__CMS_FOOTER__ = ${footerJson};` : '',
548
570
  ctxMenusScript: ctxMenusScript,
549
571
  ctxMenusModule: ctxMenusModule,
572
+ // Every `<` escaped, not only `</script>`: a label holding `<!--<script` would
573
+ // otherwise put the parser in script-data-escaped state and swallow the page.
550
574
  siteJson: JSON.stringify(Object.assign(
551
575
  {
552
576
  title: site.title,
@@ -561,13 +585,14 @@ export async function renderPage(page, opts = {}) {
561
585
  site.backToTop?.enabled ? { backToTop: site.backToTop } : {},
562
586
  site.goToBottom?.enabled ? { goToBottom: site.goToBottom } : {},
563
587
  consentAssets.siteFields,
588
+ motionAssets.siteFields,
564
589
  autoTheme ? {autoTheme} : {}
565
- )).replace(/<\/script>/gi, '<\\/script>'),
590
+ )).replace(/</g, '\\u003c'),
566
591
  headInject: [injection.head, navbarFontLink].filter(Boolean).join('\n'),
567
592
  // Theme overrides land BEFORE content/custom.css: the overrides are
568
593
  // generated, custom.css is hand-written, and the hand-written one stays
569
594
  // the last word.
570
- headInjectLate: [injection.headLate, searchAssets.headTag, switcherAssets.headTag, themeView.customThemeStyleTag, themeView.overrideStyleTag, customCssTag, navbarStyleTag]
595
+ headInjectLate: [injection.headLate, searchAssets.headTag, motionAssets.headTag, switcherAssets.headTag, themeView.customThemeStyleTag, themeView.overrideStyleTag, customCssTag, navbarStyleTag]
571
596
  .filter(Boolean).join('\n'),
572
597
  bodyEndInject: [
573
598
  // Draft banner - first, so it is the topmost fixed element and a
@@ -1256,6 +1281,7 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
1256
1281
  // other is the standing trap in this file.
1257
1282
  const themeView = await buildThemeView({});
1258
1283
  const searchAssets = buildSearchAssets();
1284
+ const motionAssets = buildMotionAssets(site);
1259
1285
  const footerBlocksHtml = await buildFooterBlocks(site, {user, urlPath: seoMeta.urlPath || '/', project: menuCtx.project ?? null});
1260
1286
  const switcherAssets = buildThemeSwitcherAssets(themeView.cfg, {
1261
1287
  html: `${renderedFragment || ''}${overlayMenus}${footerBlocksHtml}`,
@@ -1340,6 +1366,7 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
1340
1366
  footerScript: footerJson ? `window.__CMS_FOOTER__ = ${footerJson};` : '',
1341
1367
  ctxMenusScript: ctxMenusScript,
1342
1368
  ctxMenusModule: ctxMenusModule,
1369
+ // Every `<` escaped, as on the page path above.
1343
1370
  siteJson: JSON.stringify({
1344
1371
  title: site.title,
1345
1372
  footer: site.footer
@@ -1349,13 +1376,14 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
1349
1376
  }
1350
1377
  : site.footer,
1351
1378
  social: site.social || null,
1379
+ ...motionAssets.siteFields,
1352
1380
  ...(bare ? {} : consentAssets.siteFields)
1353
- }).replace(/<\/script>/gi, '<\\/script>'),
1381
+ }).replace(/</g, '\\u003c'),
1354
1382
  headInject: [bare ? '' : injection.head, navbarFontLink].filter(Boolean).join('\n'),
1355
1383
  // Theme overrides land BEFORE content/custom.css: the overrides are
1356
1384
  // generated, custom.css is hand-written, and the hand-written one stays
1357
1385
  // the last word.
1358
- headInjectLate: [bare ? '' : injection.headLate, searchAssets.headTag, switcherAssets.headTag, themeView.customThemeStyleTag, themeView.overrideStyleTag, customCssTag, navbarStyleTag]
1386
+ headInjectLate: [bare ? '' : injection.headLate, searchAssets.headTag, motionAssets.headTag, switcherAssets.headTag, themeView.customThemeStyleTag, themeView.overrideStyleTag, customCssTag, navbarStyleTag]
1359
1387
  .filter(Boolean).join('\n'),
1360
1388
  bodyEndInject: [
1361
1389
  overlayMenus,
@@ -112,7 +112,7 @@
112
112
  _stored = JSON.parse(localStorage.getItem('domma:reduced_motion'));
113
113
  } catch (e) {
114
114
  }
115
- // No choice of the visitor's yet: the site's default (Site Settings > Footer) -
115
+ // No choice of the visitor's yet: the site's default (Site Settings > Reduce motion) -
116
116
  // 'on' or 'off' decide it; 'system' (or nothing) leaves it to the device.
117
117
  if (_stored === null || _stored === undefined) {
118
118
  var _def = '{{motionDefault}}';
@@ -188,7 +188,7 @@
188
188
  <script src="/public/js/form-logic-engine.js?v=20261025-dropzone-disable" defer></script>
189
189
 
190
190
  <!-- Site initialisation -->
191
- <script src="/public/js/site.js?v=20261029-glider-layout" type="module"></script>
191
+ <script src="/public/js/site.js?v=20261029-reduce-motion" type="module"></script>
192
192
  <script src="/public/js/collection-context.js?v=20261010-utf8-payloads" type="module"></script>
193
193
  {{ctxMenusModule}}
194
194