domma-cms 1.6.9 → 1.6.11

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{decodeBase64Json as N}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as B,applyColour as j,applyPill as Y,applyFloat as G,applyHighlight as O,applyItemHighlight as U,itemHighlightAttrs as K,isCurrentItem as R,menuAlign as Q,applyClasses as D,cssClasses as P}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{initFloatingMenus as Z}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as V,markInvalidFields as W,showValidationPopup as J}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as ee}from"/public/js/form-steps.mjs";import{applyFormClasses as X,applySubmitButtons as te,applyWizardButtons as ae}from"/public/js/form-submit.mjs";$(()=>{const x=window.__CMS_NAV__||{},h=window.__CMS_SITE__||{};if(h.autoTheme?.enabled){let t=function(e){const r=(e||"07:00").split(":");return+r[0]*60+(+r[1]||0)},o=function(){const e=new Date,r=e.getHours()*60+e.getMinutes();return r>=t(a.dayStart)&&r<t(a.nightStart)?a.dayTheme:a.nightTheme},n=function(e){const r=a.apply&&a.apply[e]||{theme:e,custom:""};Domma.theme.set(r.theme);for(const l of[...document.body.classList])l.startsWith("dm-custom-")&&document.body.classList.remove(l);r.custom&&document.body.classList.add(r.custom)};const a=h.autoTheme;n(o()),setInterval(()=>n(o()),6e4)}const A=$("#site-navbar");if(A.length&&x.brand){let o=function(c,y=0){return Array.isArray(c)?c.filter(i=>!(i&&i.type==="spacer")).filter(i=>!(i&&i.type==="separator"&&y===0)).map(i=>i&&i.type==="separator"?{divider:!0}:Array.isArray(i?.items)?{...i,items:o(i.items,y+1)}:i):c},n=function(c){return Array.isArray(c)?c.filter(y=>!(y&&(y.type==="separator"||y.type==="spacer"))):[]};const a={...x.brand},t=a.size&&a.size!=="md"?` navbar-brand-${a.size}`:"";if(a.logo||a.icon||a.tagline){let c="";a.logo?c+=`<img src="${a.logo}" class="navbar-brand-logo" alt="${a.text||""}">`:a.icon&&(c+=`<span data-icon="${a.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),a.text&&(c+=`<span class="navbar-brand-text${t}">${a.text}</span>`),a.tagline&&(c+=`<small class="navbar-brand-tagline">${a.tagline}</small>`),a.html=c}else t&&a.text&&(a.html=`<span class="navbar-brand-text${t}">${a.text}</span>`);const e=x.position==="floating",r=x.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:a,items:o(x.items||[]),variant:x.variant||"dark",position:e?"static":x.position||"sticky",collapsible:!0,appearOnHover:!!x.appearOnHover}),Domma.icons.scan("#site-navbar");const l=A.get(0);l.classList.add(`dm-nav-align-${Q(x)||"centre"}`),r&&A.get(0).classList.add("dm-nav-vertical",x.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),O(l,x),D(l,x.class),e&&(G(A.get(0),x),Z(A.get(0).parentNode||document));const f=l.querySelector(".navbar-toggle"),p=l.querySelector(".navbar-collapse");if(f&&p){let c=null;const y=()=>{p.classList.contains("show")&&f.click()},i=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},s=()=>{c||(c=document.createElement("div"),c.className="dm-navbar-backdrop",c.addEventListener("click",y),document.body.appendChild(c),document.body.classList.add("dm-drawer-open"))};f.addEventListener("click",()=>{requestAnimationFrame(()=>{p.classList.contains("show")?s():i()})}),p.addEventListener("click",u=>{u.target.closest("a")&&requestAnimationFrame(i)}),document.addEventListener("keydown",u=>{u.key==="Escape"&&p.classList.contains("show")&&y()})}const m=l.querySelector(".navbar-nav");if(m){const c=Array.from(m.children);let y=0;for(const i of x.items||[])if(!(i&&i.type==="separator")){if(i&&i.type==="spacer"){const s=document.createElement("li"),u=["xs","sm","md","lg","xl","flex"].includes(i.size)?i.size:"md";s.className=`dm-menu-spacer dm-menu-spacer--${u}`,s.setAttribute("aria-hidden","true"),m.insertBefore(s,c[y]||null);continue}y++}}const b=n(x.items||[]);l.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const y=b[parseInt(c.dataset.index,10)];if(!y)return;const i=c.dataset.subindex!=null,s=i&&Array.isArray(y.items)?y.items[parseInt(c.dataset.subindex,10)]:y;if(!s)return;s.colour&&j(c,s.colour),s.pill&&!i&&Y(c,s.pill),U(c,s),D(c.closest("li"),s.class);const u=B(s.badge);u&&c.appendChild(u),R(s.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const C=$("#site-footer");if(C.length){let e=function(s){return String(s??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},r=function(s){return e(s).replace(/'/g,"&#39;")},l=function(s){if(s&&s.type==="separator")return'<li class="footer-sep"><hr></li>';if(s&&s.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(s.size)?s.size:"md"}" aria-hidden="true"></li>`;const u=r(s.url||"#"),d=e(s.text||""),w=Array.isArray(s.items)&&s.items.length?`<ul>${s.items.map(l).join("")}</ul>`:"",v=K(s),q=[v.hover&&` data-menu-item-hover="${r(v.hover)}"`,v.active&&` data-menu-item-active="${r(v.active)}"`].filter(Boolean).join(""),M=v.accent?` style="--dm-menu-highlight:${r(v.accent)}"`:"",k=P(s.class).join(" ");return`<li${k?` class="${r(k)}"`:""}><a href="${u}"${q}${M}>${d}</a>${w}</li>`},f=function(s,u){return(s||[]).forEach(d=>{d&&(d.type==="separator"||d.type==="spacer")||(u.push(d),Array.isArray(d.items)&&d.items.length&&f(d.items,u))}),u};const a=h.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 o='<div class="footer-inner container">';const n=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(n.copyright&&(o+=`<p>${e(n.copyright)}</p>`),n.primary.length&&(o+=`<nav class="footer-nav footer-nav--primary"><ul>${n.primary.map(l).join("")}</ul></nav>`),n.legal.length&&(o+=`<nav class="footer-nav footer-nav--legal"><ul>${n.legal.map(l).join("")}</ul></nav>`),h.footer){const s=Object.keys(t).filter(d=>a[d]),u=P(h.footer.socialClass).join(" ");s.length&&(o+='<div class="footer-social">',s.forEach(d=>{const{label:w,svg:v}=t[d];o+=`<a href="${a[d]}" target="_blank" rel="noopener noreferrer" aria-label="${w}" class="footer-social-link${u?` ${r(u)}`:""}">${v}</a>`}),o+="</div>")}o+="</div>",C.html(o),D(C.get(0),h.footer?.class);const p=[...f(n.primary,[]),...f(n.legal,[])];C.get(0).querySelectorAll(".footer-nav a").forEach((s,u)=>{const d=p[u];if(!d)return;d.colour&&j(s,d.colour);const w=B(d.badge);w&&s.appendChild(w),R(d.url,location.pathname)&&(s.classList.add("is-active"),s.setAttribute("aria-current","page"))}),O(C.get(0).querySelector(".footer-nav--primary"),{highlight:n.primaryHighlight}),O(C.get(0).querySelector(".footer-nav--legal"),{highlight:n.legalHighlight}),D(C.get(0).querySelector(".footer-nav--primary"),n.primaryClass),D(C.get(0).querySelector(".footer-nav--legal"),n.legalClass);const b=h.footer?.showMotionToggle!==!1,c=S.get("reduced_motion"),y=c!==null?!!c:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),i=C.get(0).querySelector(".footer-inner");if(b&&i){const s=document.createElement("input");s.type="checkbox",s.className="form-switch-input",s.id="dm-motion-switch",s.checked=y,s.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const u=document.createElement("span");u.className="form-switch-label",u.textContent="Reduce motion";const d=document.createElement("label");d.className="form-switch footer-motion-switch",d.title="Reduce motion",d.appendChild(s),d.appendChild(u),i.appendChild(d)}}if($("#site-sidebar").length){const a=document.querySelector(".site-content"),t=l=>!l.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),o=l=>a?[...a.querySelectorAll(l)].filter(t):[],n=o("h2").length?o("h2"):o("h3"),e=new Set([...document.querySelectorAll("[id]")].map(l=>l.id)),r=[];for(const l of n){if(!l.id){const f=(l.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let p=f;for(let m=2;e.has(p);m++)p=`${f}-${m}`;e.add(p),l.id=p}r.push({text:l.textContent.trim(),url:`#${l.id}`,section:l.id})}r.length?Domma.elements.sidebar("#site-sidebar",{items:r,fixed:!1,push:!1,collapsible:!1,variant:"theme",scrollSpy:!0}):document.querySelector(".site-main.with-sidebar")?.classList.add("no-sidebar-items")}Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const g=$(".page-body");if(g.length){g.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),g.find(".tabs").each(function(){Domma.elements.tabs(this)}),g.find(".carousel").each(function(){const a={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(a.animationDuration=t)}this.dataset.animationEasing&&(a.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=a),this._dmCarousel=Domma.elements.carousel(this,a)}),g.find(".dm-countdown").each(function(){const a={autoStart:!0},t=String(this.dataset.format||"").trim(),o=String(this.dataset.to||"").trim(),n=/^(\d{4})-(\d{2})-(\d{2})$/.exec(o),e=n?new Date(+n[1],+n[2]-1,+n[3]).getTime():o?new Date(o).getTime():NaN;Number.isFinite(e)?a.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(a.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const r=/^dd:/i.test(t);a.format=r?"hh:mm:ss":t||(a.duration>=36e5?"hh:mm:ss":"mm:ss");const l=this,f=m=>String(m).padStart(2,"0"),p=m=>{const b=Math.max(0,Math.floor(m/1e3)),c=l.querySelector(".dm-timer-time");c&&(c.textContent=`${f(Math.floor(b/86400))}:${f(Math.floor(b%86400/3600))}:${f(Math.floor(b%3600/60))}:${f(b%60)}`)};r&&(a.onTick=p),Domma.elements.timer(this,a),r&&p(a.duration||0)}),g.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),g.find(".dm-progression").each(function(){const a=Array.from(this.querySelectorAll(".dm-progression-item")).map(n=>{const e={title:n.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:n.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return n.dataset.date&&(e.date=n.dataset.date),n.dataset.status&&(e.status=n.dataset.status),n.dataset.entryId&&(e._entryId=n.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",o=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...a.length?{items:a}:{}});a.length&&(this._dmCtx={instance:o,items:a})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(a=>{const t=a.dataset.revealMode||"stagger",o=a.dataset.revealAnimation||"slide-up",n=parseInt(a.dataset.revealDuration,10)||400,e=parseInt(a.dataset.revealStagger,10)||60,r=parseInt(a.dataset.revealDelay,10)||0,l=a.dataset.revealDirection==="rtl",f=Array.from(a.children),p={"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)"};f.forEach((m,b)=>{m.style.opacity="0",m.style.transform=p[o]||"",m.style.transition=`opacity ${n}ms ease, transform ${n}ms ease`;const c=l?f.length-1-b:b;m.style.transitionDelay=t==="stagger"?`${r+c*e}ms`:`${r}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(b=>{b.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});f.forEach(b=>m.observe(b))}))}),g.find(".card[data-collapsible]").each(function(){const a=this.querySelector(".card-header");a&&a.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),g.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const a=this.dataset.soTarget,t=document.getElementById(a);if(!t)return;const o=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",o.setContent(t),o.open()})})}if(typeof $.setup=="function"){const a=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const o=N(t.dataset.config);Object.assign(a,o)}catch{}}),Object.keys(a).length>0){const t={};for(const[o,n]of Object.entries(a)){const e=n?.events?.click,{confirm:r,toast:l,alert:f,prompt:p,...m}=e||{};r||l||f||p?($(o).on("click",async function(c){if(c.preventDefault(),r&&!await E.confirm(r))return;let y=null;if(!(p&&(y=await E.prompt(p,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),y===null))){if(m.target){const i=$(m.target);m.toggleClass&&i.toggleClass(m.toggleClass),m.addClass&&i.addClass(m.addClass),m.removeClass&&i.removeClass(m.removeClass),y!==null&&(m.setText&&i.text(y),m.setVal&&i.val(y),m.setAttr&&i.attr(m.setAttr,y))}m.href&&(window.location.href=m.href),l&&E.toast(l,{type:m.toastType||"success"}),f&&E.alert(f)}}),Object.keys(m).length&&(t[o]={...n,events:{...n.events,click:m}})):t[o]=n}$.setup(t)}}g.length&&I(g.get(0))}),window.wireCTAButtons=I;function I(x){x.querySelectorAll(".dm-cta-trigger").forEach(h=>{h.__ctaWired||(h.__ctaWired=!0,h.addEventListener("click",async()=>{const A=h.dataset.action,C=h.dataset.entry,_=h.dataset.confirm;let g=S.get("auth_token");if(!g){E.toast("Please log in to perform this action.",{type:"warning"});return}if(_&&!await E.confirm(_))return;const a=Array.from(h.childNodes).map(o=>o.cloneNode(!0));h.disabled=!0,h.textContent="Running\u2026";const t=o=>fetch(`/api/actions/${A}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(h.dataset.scope?{entryId:C,scope:h.dataset.scope}:{entryId:C})});try{let o=await t(g);if(o.status===401){const e=S.get("auth_refresh_token");if(e){const r=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(r.ok){const{token:l}=await r.json();S.set("auth_token",l),g=l,o=await t(g)}}}const n=await o.json().catch(()=>({}));if(!o.ok)throw new Error(n.error||n.message||`Error ${o.status}`);E.toast(n.message||"Action completed.",{type:"success"})}catch(o){E.toast(o.message||"Action failed.",{type:"error"})}finally{h.disabled=!1,h.textContent="",a.forEach(o=>h.appendChild(o)),Domma.icons.scan(h)}}))})}(function(){const h=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!h.length)return;const A=S.get("auth_token");function C(g,a){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const o=document.createElement("p");if(a){o.appendChild(document.createTextNode("Please "));const n=document.createElement("a");n.href="/login",n.textContent="sign in",o.appendChild(n),o.appendChild(document.createTextNode(" to view your entries."))}else o.textContent=g;return t.appendChild(o),t}function _(g,a){const t=document.createElement("template");t.innerHTML=a||"",g.replaceWith(t.content)}h.forEach(async g=>{const a=g.dataset.collectionAttrs;if(!a)return;if(!A){g.replaceChildren(C("",!0));return}const t=o=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({attrs:a})});try{let o=A,n=await t(o);if(n.status===401){const r=S.get("auth_refresh_token");if(r){const l=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:r})});if(l.ok){const{token:f}=await l.json();S.set("auth_token",f),o=f,n=await t(o)}}}if(!n.ok){const{error:r}=await n.json().catch(()=>({}));g.replaceChildren(C(r||"Unable to load entries.",!1));return}const{html:e}=await n.json();_(g,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{g.replaceChildren(C("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),I(document.body)},100)})(),(function(){const h=document.querySelectorAll("[data-collection-table]");!h.length||typeof T>"u"||!T.create||h.forEach(A=>{let C;try{C=N(A.dataset.payload)}catch{return}const{columns:_,rows:g,search:a,sortable:t,exportable:o,pageSize:n,empty:e,ctaConfig:r,slug:l,exportCfg:f}=C;if(!_?.length)return;if(r){const b=_.findIndex(c=>c.key==="_cta");b!==-1&&(_[b]={key:"_cta",title:"",render:(c,y)=>{const i=document.createElement("button");if(i.className=`btn btn-${r.style||"primary"} dm-cta-trigger`,i.dataset.action=r.action||"",r.scope&&(i.dataset.scope=r.scope),i.dataset.entry=y._entryId||"",r.confirm&&(i.dataset.confirm=r.confirm),r.icon){const s=document.createElement("span");s.dataset.icon=r.icon,i.appendChild(s),i.appendChild(document.createTextNode(" "))}return i.appendChild(document.createTextNode(r.label||"Run")),i}})}const p="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=p,A.replaceChildren(m),T.create("#"+p,{data:g,columns:_,search:a,sortable:t,exportable:o,pageSize:n,emptyMessage:e}),r&&I(m),A._dmTable={columns:_,rows:g,slug:l,exportCfg:f,render(b){T.create("#"+p,{data:b,columns:_,search:a,sortable:t,exportable:o,pageSize:n,emptyMessage:e}),r&&I(m)}}})})(),(function(){const h=document.querySelectorAll("[data-form-inline]");if(!h.length||typeof F>"u")return;function A(t){const o=t&&t.logic;return!!(o&&(o.visibility||o.requirement))}function C(t,o){const n={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const r=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),l=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":r?"chooser":e.type,f={...e.formConfig||{}};f.span==="full"&&o&&(f.span=o);const p={type:l,required:A(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&&(p.minLength=e.minLength),e.maxLength!==void 0&&(p.maxLength=e.maxLength),e.min!==void 0&&(p.min=e.min),e.max!==void 0&&(p.max=e.max),r&&(e.variant&&(p.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(p.multiple=!0),e.density&&(p.density=e.density),e.columns&&(p.columns=e.columns),e.accent&&(p.accent=e.accent),e.accentStyle&&(p.accentStyle=e.accentStyle),e.glow&&(p.glow=!0),e.glowColour&&(p.glowColour=e.glowColour),e.shadow&&(p.shadow=e.shadow),e.shadowColour&&(p.shadowColour=e.shadowColour)),n[e.name]=p}),n}function _(t){const o={};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&&(o[n.name]=typeof e=="object"?e.value:e)}}),o}function g(t,o){(o||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const e=t.querySelector(`[name="${n.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function a(t,o,n){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=o,e.style.cssText=n?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}h.forEach(t=>{let o;try{o=N(t.dataset.formInline)}catch{return}const n=o.fields||[],e=o.settings||{},r=Number(e.columns)===3?3:2,l=e.layout||"grid",f=n.some(i=>i.type==="page-break"),p=async i=>{if(t.dataset.triggerBlocked==="true"){const s=t._formLogicRuntime,u=s&&s.submitBlock?s.submitBlock().reasons:[];a(t,u.join(" ")||"This form cannot be submitted yet.",!0);const d=new Error("Blocked by a form trigger");throw d.formSubmitFailed=!0,d}try{const s=t.querySelector(".fb-form-honeypot"),u=s?.querySelector('input[type="text"]')||null,d=s?.querySelector('[name="_t"]')||null,w=Object.assign({},i);delete w._t,s?.dataset.hpName&&delete w[s.dataset.hpName],u!==null&&(w._hp=u.value),d!==null&&(w._t=d.value);const v=await H.post(`/api/forms/submit/${o.slug}`,w);if(v&&v.error){a(t,v.error,!0);const q=new Error(v.error);throw q.formSubmitFailed=!0,q}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);a(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(s){throw s.formSubmitFailed||a(t,s.message||"Submission failed. Please try again.",!0),s}},m=Date.now();function b(i){const s=i.querySelector("form");if(!s||s.querySelector(".fb-form-honeypot"))return;const u=document.createElement("div");u.className="fb-form-honeypot",u.setAttribute("aria-hidden","true");const d=document.createElement("input");d.name=s.querySelector('[name="website"]')?"_website":"website",u.dataset.hpName=d.name,d.type="text",d.tabIndex=-1,d.autocomplete="url",d.placeholder="https://",u.appendChild(d);const w=document.createElement("input");w.name="_t",w.type="hidden",w.value=m,u.appendChild(w),s.appendChild(u)}function c(i){if(!window.FormLogicEngine||!n.some(u=>u.logic||Array.isArray(u.triggers)&&u.triggers.length))return null;const s=new window.FormLogicEngine.FormLogicRuntime(o,t,i?{baseValues:i}:void 0);if(s.init(),t._formLogicRuntime=s,t._formLogicObserved)return s;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const u=new MutationObserver(function(d){for(const w of d)for(const v of w.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),u.disconnect();return}});u.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=u}return s}let y=!1;if(t.addEventListener("dm-form-end",i=>{const s=i.detail?.validation;if(s&&!s.valid){W(t,s.missing),J(s);return}y||(y=!0,p(i.detail?.values||{}).catch(()=>{}).finally(()=>{y=!1}))}),f&&F.wizard){const i=ee(n,o.title),s=i.map(k=>({title:k.title,description:k.description,fields:C(k.fields,r)})),u=i.map(k=>k.fields);let d=0,w=null,v=null;const q=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const z=L.validateFields(t,u[d]||[]);z.valid||(k.preventDefault(),k.stopImmediatePropagation(),W(t,z.missing),J(z))},M=()=>{const k=u[d]||n;ae(t,e),X(t,e,k),g(t,k),V(t,k),e.honeypot!==!1&&b(t),w&&w.destroy(),w=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",q,!0))};v=F.wizard(t,{schema:{steps:s},layout:l,columns:r,finishText:e.submitText||"Finish",onSubmit:p,onStepChange:k=>{d=k,setTimeout(M,0)}}),t.addEventListener("dm-form-trigger",k=>{if(k.detail?.type!=="goto-step"||!v?.goToStep)return;const L=Number(k.detail.action.step);!Number.isFinite(L)||L<0||L>=s.length||L!==d&&v.goToStep(L)}),Promise.resolve(v).then(M)}else if(F.render){const i=F.render(t,C(n,r),_(n),{submitText:e.submitText||"Submit",layout:l,columns:r,onSubmit:p});Promise.resolve(i).then(function(){te(t,e,l),X(t,e,n),g(t,n),V(t,n),e.honeypot!==!1&&b(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
1
+ import{decodeBase64Json as N}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as O,applyColour as j,applyPill as Y,applyFloat as G,applyHighlight as B,applyItemHighlight as U,itemHighlightAttrs as K,isCurrentItem as R,menuAlign as Q,applyClasses as D,cssClasses as P}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{initFloatingMenus as Z}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as V,markInvalidFields as W,showValidationPopup as J}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as ee}from"/public/js/form-steps.mjs";import{applyFormClasses as X,applySubmitButtons as te,applyWizardButtons as ae}from"/public/js/form-submit.mjs";$(()=>{const x=window.__CMS_NAV__||{},g=window.__CMS_SITE__||{};if(g.autoTheme?.enabled){let t=function(e){const r=(e||"07:00").split(":");return+r[0]*60+(+r[1]||0)},n=function(){const e=new Date,r=e.getHours()*60+e.getMinutes();return r>=t(o.dayStart)&&r<t(o.nightStart)?o.dayTheme:o.nightTheme},s=function(e){const r=o.apply&&o.apply[e]||{theme:e,custom:""};Domma.theme.set(r.theme);for(const d of[...document.body.classList])d.startsWith("dm-custom-")&&document.body.classList.remove(d);r.custom&&document.body.classList.add(r.custom)};const o=g.autoTheme;s(n()),setInterval(()=>s(n()),6e4)}const A=$("#site-navbar");if(A.length&&x.brand){let n=function(c,f=0){return Array.isArray(c)?c.filter(i=>!(i&&(i.type==="spacer"||i.type==="theme-switcher"))).filter(i=>!(i&&i.type==="separator"&&f===0)).map(i=>i&&i.type==="separator"?{divider:!0}:Array.isArray(i?.items)?{...i,items:n(i.items,f+1)}:i):c},s=function(c){return Array.isArray(c)?c.filter(f=>!(f&&(f.type==="separator"||f.type==="spacer"||f.type==="theme-switcher"))):[]};const o={...x.brand},t=o.size&&o.size!=="md"?` navbar-brand-${o.size}`:"";if(o.logo||o.icon||o.tagline){let c="";o.logo?c+=`<img src="${o.logo}" class="navbar-brand-logo" alt="${o.text||""}">`:o.icon&&(c+=`<span data-icon="${o.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),o.text&&(c+=`<span class="navbar-brand-text${t}">${o.text}</span>`),o.tagline&&(c+=`<small class="navbar-brand-tagline">${o.tagline}</small>`),o.html=c}else t&&o.text&&(o.html=`<span class="navbar-brand-text${t}">${o.text}</span>`);const e=x.position==="floating",r=x.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:o,items:n(x.items||[]),variant:x.variant||"dark",position:e?"static":x.position||"sticky",collapsible:!0,appearOnHover:!!x.appearOnHover}),Domma.icons.scan("#site-navbar");const d=A.get(0);d.classList.add(`dm-nav-align-${Q(x)||"centre"}`),r&&A.get(0).classList.add("dm-nav-vertical",x.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),B(d,x),D(d,x.class),e&&(G(A.get(0),x),Z(A.get(0).parentNode||document));const h=d.querySelector(".navbar-toggle"),p=d.querySelector(".navbar-collapse");if(h&&p){let c=null;const f=()=>{p.classList.contains("show")&&h.click()},i=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},a=()=>{c||(c=document.createElement("div"),c.className="dm-navbar-backdrop",c.addEventListener("click",f),document.body.appendChild(c),document.body.classList.add("dm-drawer-open"))};h.addEventListener("click",()=>{requestAnimationFrame(()=>{p.classList.contains("show")?a():i()})}),p.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(i)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&p.classList.contains("show")&&f()})}const m=d.querySelector(".navbar-nav");if(m){const c=Array.from(m.children);let f=0;for(const i of x.items||[])if(!(i&&i.type==="separator")){if(i&&i.type==="spacer"){const a=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(i.size)?i.size:"md";a.className=`dm-menu-spacer dm-menu-spacer--${l}`,a.setAttribute("aria-hidden","true"),m.insertBefore(a,c[f]||null);continue}if(i&&i.type==="theme-switcher"){const a=document.createElement("li");a.className="dm-menu-theme-switcher";const l=document.createElement("span");l.dataset.themeSwitcher="menu",l.dataset.position="inline",a.appendChild(l),m.insertBefore(a,c[f]||null);continue}f++}window.CMSThemeSwitcher?.scan(m)}const b=s(x.items||[]);d.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const f=b[parseInt(c.dataset.index,10)];if(!f)return;const i=c.dataset.subindex!=null,a=i&&Array.isArray(f.items)?f.items[parseInt(c.dataset.subindex,10)]:f;if(!a)return;a.colour&&j(c,a.colour),a.pill&&!i&&Y(c,a.pill),U(c,a),D(c.closest("li"),a.class);const l=O(a.badge);l&&c.appendChild(l),R(a.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const w=$("#site-footer");if(w.length){let e=function(a){return String(a??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},r=function(a){return e(a).replace(/'/g,"&#39;")},d=function(a){if(a&&a.type==="separator")return'<li class="footer-sep"><hr></li>';if(a&&a.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(a.size)?a.size:"md"}" aria-hidden="true"></li>`;if(a&&a.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const l=r(a.url||"#"),u=e(a.text||""),C=Array.isArray(a.items)&&a.items.length?`<ul>${a.items.map(d).join("")}</ul>`:"",v=K(a),q=[v.hover&&` data-menu-item-hover="${r(v.hover)}"`,v.active&&` data-menu-item-active="${r(v.active)}"`].filter(Boolean).join(""),M=v.accent?` style="--dm-menu-highlight:${r(v.accent)}"`:"",k=P(a.class).join(" ");return`<li${k?` class="${r(k)}"`:""}><a href="${l}"${q}${M}>${u}</a>${C}</li>`},h=function(a,l){return(a||[]).forEach(u=>{u&&(u.type==="separator"||u.type==="spacer"||u.type==="theme-switcher")||(l.push(u),Array.isArray(u.items)&&u.items.length&&h(u.items,l))}),l};const o=g.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 n='<div class="footer-inner container">';const s=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(s.copyright&&(n+=`<p>${e(s.copyright)}</p>`),s.primary.length&&(n+=`<nav class="footer-nav footer-nav--primary"><ul>${s.primary.map(d).join("")}</ul></nav>`),s.legal.length&&(n+=`<nav class="footer-nav footer-nav--legal"><ul>${s.legal.map(d).join("")}</ul></nav>`),g.footer){const a=Object.keys(t).filter(u=>o[u]),l=P(g.footer.socialClass).join(" ");a.length&&(n+='<div class="footer-social">',a.forEach(u=>{const{label:C,svg:v}=t[u];n+=`<a href="${o[u]}" target="_blank" rel="noopener noreferrer" aria-label="${C}" class="footer-social-link${l?` ${r(l)}`:""}">${v}</a>`}),n+="</div>")}n+="</div>",w.html(n),window.CMSThemeSwitcher?.scan(w.get(0)),D(w.get(0),g.footer?.class);const p=[...h(s.primary,[]),...h(s.legal,[])];w.get(0).querySelectorAll(".footer-nav a").forEach((a,l)=>{const u=p[l];if(!u)return;u.colour&&j(a,u.colour);const C=O(u.badge);C&&a.appendChild(C),R(u.url,location.pathname)&&(a.classList.add("is-active"),a.setAttribute("aria-current","page"))}),B(w.get(0).querySelector(".footer-nav--primary"),{highlight:s.primaryHighlight}),B(w.get(0).querySelector(".footer-nav--legal"),{highlight:s.legalHighlight}),D(w.get(0).querySelector(".footer-nav--primary"),s.primaryClass),D(w.get(0).querySelector(".footer-nav--legal"),s.legalClass);const b=g.footer?.showMotionToggle!==!1,c=S.get("reduced_motion"),f=c!==null?!!c:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),i=w.get(0).querySelector(".footer-inner");if(b&&i){const a=document.createElement("input");a.type="checkbox",a.className="form-switch-input",a.id="dm-motion-switch",a.checked=f,a.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const l=document.createElement("span");l.className="form-switch-label",l.textContent="Reduce motion";const u=document.createElement("label");u.className="form-switch footer-motion-switch",u.title="Reduce motion",u.appendChild(a),u.appendChild(l),i.appendChild(u)}}if($("#site-sidebar").length){const o=document.querySelector(".site-content"),t=d=>!d.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),n=d=>o?[...o.querySelectorAll(d)].filter(t):[],s=n("h2").length?n("h2"):n("h3"),e=new Set([...document.querySelectorAll("[id]")].map(d=>d.id)),r=[];for(const d of s){if(!d.id){const h=(d.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let p=h;for(let m=2;e.has(p);m++)p=`${h}-${m}`;e.add(p),d.id=p}r.push({text:d.textContent.trim(),url:`#${d.id}`,section:d.id})}r.length?Domma.elements.sidebar("#site-sidebar",{items:r,fixed:!1,push:!1,collapsible:!1,variant:"theme",scrollSpy:!0,position:document.querySelector(".site-main.sidebar-right")?"right":"left"}):document.querySelector(".site-main.with-sidebar")?.classList.add("no-sidebar-items")}Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const y=$(".page-body");if(y.length){y.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),y.find(".tabs").each(function(){Domma.elements.tabs(this)}),y.find(".carousel").each(function(){const o={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(o.animationDuration=t)}this.dataset.animationEasing&&(o.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=o),this._dmCarousel=Domma.elements.carousel(this,o)}),y.find(".dm-countdown").each(function(){const o={autoStart:!0},t=String(this.dataset.format||"").trim(),n=String(this.dataset.to||"").trim(),s=/^(\d{4})-(\d{2})-(\d{2})$/.exec(n),e=s?new Date(+s[1],+s[2]-1,+s[3]).getTime():n?new Date(n).getTime():NaN;Number.isFinite(e)?o.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(o.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const r=/^dd:/i.test(t);o.format=r?"hh:mm:ss":t||(o.duration>=36e5?"hh:mm:ss":"mm:ss");const d=this,h=m=>String(m).padStart(2,"0"),p=m=>{const b=Math.max(0,Math.floor(m/1e3)),c=d.querySelector(".dm-timer-time");c&&(c.textContent=`${h(Math.floor(b/86400))}:${h(Math.floor(b%86400/3600))}:${h(Math.floor(b%3600/60))}:${h(b%60)}`)};r&&(o.onTick=p),Domma.elements.timer(this,o),r&&p(o.duration||0)}),y.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),y.find(".dm-progression").each(function(){const o=Array.from(this.querySelectorAll(".dm-progression-item")).map(s=>{const e={title:s.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:s.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return s.dataset.date&&(e.date=s.dataset.date),s.dataset.status&&(e.status=s.dataset.status),s.dataset.entryId&&(e._entryId=s.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",n=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...o.length?{items:o}:{}});o.length&&(this._dmCtx={instance:n,items:o})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(o=>{const t=o.dataset.revealMode||"stagger",n=o.dataset.revealAnimation||"slide-up",s=parseInt(o.dataset.revealDuration,10)||400,e=parseInt(o.dataset.revealStagger,10)||60,r=parseInt(o.dataset.revealDelay,10)||0,d=o.dataset.revealDirection==="rtl",h=Array.from(o.children),p={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};h.forEach((m,b)=>{m.style.opacity="0",m.style.transform=p[n]||"",m.style.transition=`opacity ${s}ms ease, transform ${s}ms ease`;const c=d?h.length-1-b:b;m.style.transitionDelay=t==="stagger"?`${r+c*e}ms`:`${r}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(b=>{b.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});h.forEach(b=>m.observe(b))}))}),y.find(".card[data-collapsible]").each(function(){const o=this.querySelector(".card-header");o&&o.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),y.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const o=this.dataset.soTarget,t=document.getElementById(o);if(!t)return;const n=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",n.setContent(t),n.open()})})}if(typeof $.setup=="function"){const o=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const n=N(t.dataset.config);Object.assign(o,n)}catch{}}),Object.keys(o).length>0){const t={};for(const[n,s]of Object.entries(o)){const e=s?.events?.click,{confirm:r,toast:d,alert:h,prompt:p,...m}=e||{};r||d||h||p?($(n).on("click",async function(c){if(c.preventDefault(),r&&!await E.confirm(r))return;let f=null;if(!(p&&(f=await E.prompt(p,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),f===null))){if(m.target){const i=$(m.target);m.toggleClass&&i.toggleClass(m.toggleClass),m.addClass&&i.addClass(m.addClass),m.removeClass&&i.removeClass(m.removeClass),f!==null&&(m.setText&&i.text(f),m.setVal&&i.val(f),m.setAttr&&i.attr(m.setAttr,f))}m.href&&(window.location.href=m.href),d&&E.toast(d,{type:m.toastType||"success"}),h&&E.alert(h)}}),Object.keys(m).length&&(t[n]={...s,events:{...s.events,click:m}})):t[n]=s}$.setup(t)}}y.length&&I(y.get(0))}),window.wireCTAButtons=I;function I(x){x.querySelectorAll(".dm-cta-trigger").forEach(g=>{g.__ctaWired||(g.__ctaWired=!0,g.addEventListener("click",async()=>{const A=g.dataset.action,w=g.dataset.entry,_=g.dataset.confirm;let y=S.get("auth_token");if(!y){E.toast("Please log in to perform this action.",{type:"warning"});return}if(_&&!await E.confirm(_))return;const o=Array.from(g.childNodes).map(n=>n.cloneNode(!0));g.disabled=!0,g.textContent="Running\u2026";const t=n=>fetch(`/api/actions/${A}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify(g.dataset.scope?{entryId:w,scope:g.dataset.scope}:{entryId:w})});try{let n=await t(y);if(n.status===401){const e=S.get("auth_refresh_token");if(e){const r=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(r.ok){const{token:d}=await r.json();S.set("auth_token",d),y=d,n=await t(y)}}}const s=await n.json().catch(()=>({}));if(!n.ok)throw new Error(s.error||s.message||`Error ${n.status}`);E.toast(s.message||"Action completed.",{type:"success"})}catch(n){E.toast(n.message||"Action failed.",{type:"error"})}finally{g.disabled=!1,g.textContent="",o.forEach(n=>g.appendChild(n)),Domma.icons.scan(g)}}))})}(function(){const g=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!g.length)return;const A=S.get("auth_token");function w(y,o){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const n=document.createElement("p");if(o){n.appendChild(document.createTextNode("Please "));const s=document.createElement("a");s.href="/login",s.textContent="sign in",n.appendChild(s),n.appendChild(document.createTextNode(" to view your entries."))}else n.textContent=y;return t.appendChild(n),t}function _(y,o){const t=document.createElement("template");t.innerHTML=o||"",y.replaceWith(t.content)}g.forEach(async y=>{const o=y.dataset.collectionAttrs;if(!o)return;if(!A){y.replaceChildren(w("",!0));return}const t=n=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({attrs:o})});try{let n=A,s=await t(n);if(s.status===401){const r=S.get("auth_refresh_token");if(r){const d=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:r})});if(d.ok){const{token:h}=await d.json();S.set("auth_token",h),n=h,s=await t(n)}}}if(!s.ok){const{error:r}=await s.json().catch(()=>({}));y.replaceChildren(w(r||"Unable to load entries.",!1));return}const{html:e}=await s.json();_(y,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{y.replaceChildren(w("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),I(document.body)},100)})(),(function(){const g=document.querySelectorAll("[data-collection-table]");!g.length||typeof T>"u"||!T.create||g.forEach(A=>{let w;try{w=N(A.dataset.payload)}catch{return}const{columns:_,rows:y,search:o,sortable:t,exportable:n,pageSize:s,empty:e,ctaConfig:r,slug:d,exportCfg:h}=w;if(!_?.length)return;if(r){const b=_.findIndex(c=>c.key==="_cta");b!==-1&&(_[b]={key:"_cta",title:"",render:(c,f)=>{const i=document.createElement("button");if(i.className=`btn btn-${r.style||"primary"} dm-cta-trigger`,i.dataset.action=r.action||"",r.scope&&(i.dataset.scope=r.scope),i.dataset.entry=f._entryId||"",r.confirm&&(i.dataset.confirm=r.confirm),r.icon){const a=document.createElement("span");a.dataset.icon=r.icon,i.appendChild(a),i.appendChild(document.createTextNode(" "))}return i.appendChild(document.createTextNode(r.label||"Run")),i}})}const p="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=p,A.replaceChildren(m),T.create("#"+p,{data:y,columns:_,search:o,sortable:t,exportable:n,pageSize:s,emptyMessage:e}),r&&I(m),A._dmTable={columns:_,rows:y,slug:d,exportCfg:h,render(b){T.create("#"+p,{data:b,columns:_,search:o,sortable:t,exportable:n,pageSize:s,emptyMessage:e}),r&&I(m)}}})})(),(function(){const g=document.querySelectorAll("[data-form-inline]");if(!g.length||typeof F>"u")return;function A(t){const n=t&&t.logic;return!!(n&&(n.visibility||n.requirement))}function w(t,n){const s={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const r=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),d=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":r?"chooser":e.type,h={...e.formConfig||{}};h.span==="full"&&n&&(h.span=n);const p={type:d,required:A(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...h}};e.minLength!==void 0&&(p.minLength=e.minLength),e.maxLength!==void 0&&(p.maxLength=e.maxLength),e.min!==void 0&&(p.min=e.min),e.max!==void 0&&(p.max=e.max),r&&(e.variant&&(p.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(p.multiple=!0),e.density&&(p.density=e.density),e.columns&&(p.columns=e.columns),e.accent&&(p.accent=e.accent),e.accentStyle&&(p.accentStyle=e.accentStyle),e.glow&&(p.glow=!0),e.glowColour&&(p.glowColour=e.glowColour),e.shadow&&(p.shadow=e.shadow),e.shadowColour&&(p.shadowColour=e.shadowColour)),s[e.name]=p}),s}function _(t){const n={};return(t||[]).forEach(s=>{if(!(!s.name||s.type==="page-break"||s.type==="spacer")&&(s.type==="select"||s.type==="multiselect")&&s.required){const e=(s.options||[])[0];e&&(n[s.name]=typeof e=="object"?e.value:e)}}),n}function y(t,n){(n||[]).forEach(s=>{if(s.type!=="date"||!s.name)return;const e=t.querySelector(`[name="${s.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function o(t,n,s){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=n,e.style.cssText=s?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}g.forEach(t=>{let n;try{n=N(t.dataset.formInline)}catch{return}const s=n.fields||[],e=n.settings||{},r=Number(e.columns)===3?3:2,d=e.layout||"grid",h=s.some(i=>i.type==="page-break"),p=async i=>{if(t.dataset.triggerBlocked==="true"){const a=t._formLogicRuntime,l=a&&a.submitBlock?a.submitBlock().reasons:[];o(t,l.join(" ")||"This form cannot be submitted yet.",!0);const u=new Error("Blocked by a form trigger");throw u.formSubmitFailed=!0,u}try{const a=t.querySelector(".fb-form-honeypot"),l=a?.querySelector('input[type="text"]')||null,u=a?.querySelector('[name="_t"]')||null,C=Object.assign({},i);delete C._t,a?.dataset.hpName&&delete C[a.dataset.hpName],l!==null&&(C._hp=l.value),u!==null&&(C._t=u.value);const v=await H.post(`/api/forms/submit/${n.slug}`,C);if(v&&v.error){o(t,v.error,!0);const q=new Error(v.error);throw q.formSubmitFailed=!0,q}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);o(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(a){throw a.formSubmitFailed||o(t,a.message||"Submission failed. Please try again.",!0),a}},m=Date.now();function b(i){const a=i.querySelector("form");if(!a||a.querySelector(".fb-form-honeypot"))return;const l=document.createElement("div");l.className="fb-form-honeypot",l.setAttribute("aria-hidden","true");const u=document.createElement("input");u.name=a.querySelector('[name="website"]')?"_website":"website",l.dataset.hpName=u.name,u.type="text",u.tabIndex=-1,u.autocomplete="url",u.placeholder="https://",l.appendChild(u);const C=document.createElement("input");C.name="_t",C.type="hidden",C.value=m,l.appendChild(C),a.appendChild(l)}function c(i){if(!window.FormLogicEngine||!s.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const a=new window.FormLogicEngine.FormLogicRuntime(n,t,i?{baseValues:i}:void 0);if(a.init(),t._formLogicRuntime=a,t._formLogicObserved)return a;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(u){for(const C of u)for(const v of C.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),l.disconnect();return}});l.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=l}return a}let f=!1;if(t.addEventListener("dm-form-end",i=>{const a=i.detail?.validation;if(a&&!a.valid){W(t,a.missing),J(a);return}f||(f=!0,p(i.detail?.values||{}).catch(()=>{}).finally(()=>{f=!1}))}),h&&F.wizard){const i=ee(s,n.title),a=i.map(k=>({title:k.title,description:k.description,fields:w(k.fields,r)})),l=i.map(k=>k.fields);let u=0,C=null,v=null;const q=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const z=L.validateFields(t,l[u]||[]);z.valid||(k.preventDefault(),k.stopImmediatePropagation(),W(t,z.missing),J(z))},M=()=>{const k=l[u]||s;ae(t,e),X(t,e,k),y(t,k),V(t,k),e.honeypot!==!1&&b(t),C&&C.destroy(),C=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",q,!0))};v=F.wizard(t,{schema:{steps:a},layout:d,columns:r,finishText:e.submitText||"Finish",onSubmit:p,onStepChange:k=>{u=k,setTimeout(M,0)}}),t.addEventListener("dm-form-trigger",k=>{if(k.detail?.type!=="goto-step"||!v?.goToStep)return;const L=Number(k.detail.action.step);!Number.isFinite(L)||L<0||L>=a.length||L!==u&&v.goToStep(L)}),Promise.resolve(v).then(M)}else if(F.render){const i=F.render(t,w(s,r),_(s),{submitText:e.submitText||"Submit",layout:d,columns:r,onSubmit:p});Promise.resolve(i).then(function(){te(t,e,d),X(t,e,s),y(t,s),V(t,s),e.honeypot!==!1&&b(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
@@ -1 +1 @@
1
- (function(){"use strict";var a=window.__CMS_THEME_SWITCHER__;if(!a||!Array.isArray(a.themes)||!a.themes.length)return;var i=a.position||"right-center",m=i==="left-center"||i==="bottom-left"||i==="top-left",u=i==="bottom-left"||i==="bottom-right",l=i==="top-left"||i==="top-right",c=a.offsetX!=null?a.offsetX:32,f=a.offsetY!=null?a.offsetY:32,n=document.createElement("div");n.className="dm-theme-switcher"+(m?" dm-ts-left":"")+(l?" dm-ts-top":""),n.id="dm-theme-switcher",n.setAttribute("role","navigation"),n.setAttribute("aria-label","Theme switcher");var o=document.createElement("button");o.className="dm-ts-trigger",o.setAttribute("data-tooltip","Switch theme"),o.setAttribute("aria-haspopup","true"),o.setAttribute("aria-expanded","false");var p=360/a.themes.length;o.style.background="conic-gradient("+a.themes.map(function(e,t){return(e.from||"#888")+" "+(t*p).toFixed(2)+"deg "+((t+1)*p).toFixed(2)+"deg"}).join(", ")+")";var s=document.createElement("div");s.className="dm-ts-options",s.setAttribute("role","menu");var h=a.themes.map(function(e){var t=document.createElement("button");return t.className="dm-ts-dot",t.dataset.theme=e.id,t.setAttribute("data-tooltip",e.label),t.setAttribute("aria-label",e.label),t.setAttribute("role","menuitem"),t.style.background="linear-gradient(135deg, "+(e.from||"#888")+", "+(e.to||e.from||"#888")+")",s.appendChild(t),t});n.appendChild(o),n.appendChild(s),Object.assign(n.style,{right:m?"auto":c+"px",left:m?c+"px":"auto",top:l?f+"px":u?"auto":"50vh",bottom:u?f+"px":"auto",transform:l||u?"none":"translateY(-50%)"});function b(){document.body.appendChild(n)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",b):b();function g(e,t){typeof Domma<"u"&&Domma.theme?e(Domma.theme):t>0&&setTimeout(function(){g(e,t-1)},100)}g(function(e){function t(){var r=e.get();h.forEach(function(d){d.classList.toggle("active",d.dataset.theme===r)})}h.forEach(function(r){r.addEventListener("click",function(){e.set(r.dataset.theme),document.body.className=document.body.className.split(" ").filter(function(d){return d.indexOf("dm-custom-")!==0}).join(" "),t()})}),e.onChange(t),t(),o.addEventListener("click",function(){var r=o.getAttribute("aria-expanded")==="true";o.setAttribute("aria-expanded",String(!r))})},30)})();
1
+ (function(){"use strict";var o=window.__CMS_THEME_SWITCHER__;if(!o||!Array.isArray(o.themes)||!o.themes.length)return;var E=["top-left","top-right","left-center","right-center","bottom-left","bottom-right"],h=[],u=null;function S(t){if(!t)return o.themes;var e=String(t).split(",").map(function(n){return n.trim()}).filter(Boolean),a=o.themes.filter(function(n){return e.indexOf(n.id)!==-1});return a.length?a:o.themes}function b(t){var e=t.themes||o.themes,a=t.position==="inline",n=E.indexOf(t.position)!==-1?t.position:"right-center",d=n==="left-center"||n==="bottom-left"||n==="top-left",m=n==="bottom-left"||n==="bottom-right",l=n==="top-left"||n==="top-right",y=t.offsetX!=null?t.offsetX:32,x=t.offsetY!=null?t.offsetY:32,f=document.createElement("div");f.className="dm-theme-switcher"+(a?" dm-ts-inline dm-ts-left dm-ts-top":(d?" dm-ts-left":"")+(l?" dm-ts-top":"")),f.setAttribute("role","navigation"),f.setAttribute("aria-label","Theme switcher");var r=document.createElement("button");r.type="button",r.className="dm-ts-trigger",r.setAttribute("data-tooltip","Switch theme"),r.setAttribute("aria-label","Switch theme"),r.setAttribute("aria-haspopup","true"),r.setAttribute("aria-expanded","false");var w=360/e.length;r.style.background="conic-gradient("+e.map(function(s,i){return(s.from||"#888")+" "+(i*w).toFixed(2)+"deg "+((i+1)*w).toFixed(2)+"deg"}).join(", ")+")",r.addEventListener("click",function(){var s=r.getAttribute("aria-expanded")==="true";r.setAttribute("aria-expanded",String(!s))});var p=document.createElement("div");return p.className="dm-ts-options",p.setAttribute("role","menu"),e.forEach(function(s){var i=document.createElement("button");i.type="button",i.className="dm-ts-dot",i.dataset.theme=s.id,i.setAttribute("data-tooltip",s.label),i.setAttribute("aria-label",s.label),i.setAttribute("role","menuitem"),i.style.background="linear-gradient(135deg, "+(s.from||"#888")+", "+(s.to||s.from||"#888")+")",i.addEventListener("click",function(){C(i.dataset.theme)}),p.appendChild(i),h.push(i)}),f.appendChild(r),f.appendChild(p),a||Object.assign(f.style,{right:d?"auto":y+"px",left:d?y+"px":"auto",top:l?x+"px":m?"auto":"50vh",bottom:m?x+"px":"auto",transform:l||m?"none":"translateY(-50%)"}),c(),f}function v(t){var e=(t||document).querySelectorAll("[data-theme-switcher]:not([data-ts-mounted])");Array.prototype.forEach.call(e,function(a){a.setAttribute("data-ts-mounted","");var n=function(m){var l=parseInt(m,10);return isFinite(l)?l:null},d=b({position:a.dataset.position||"inline",offsetX:n(a.dataset.offsetX),offsetY:n(a.dataset.offsetY),themes:S(a.dataset.themes)});d.classList.contains("dm-ts-inline")?a.appendChild(d):document.body.appendChild(d)})}function C(t){u&&(u.set(t),document.body.className=document.body.className.split(" ").filter(function(e){return e.indexOf("dm-custom-")!==0}).join(" "),c())}function c(){if(u){var t=u.get();h.forEach(function(e){e.classList.toggle("active",e.dataset.theme===t)})}}function g(t,e){typeof Domma<"u"&&Domma.theme?t(Domma.theme):e>0&&setTimeout(function(){g(t,e-1)},100)}g(function(t){u=t,t.onChange(c),c()},30),window.CMSThemeSwitcher={scan:v};function A(){o.floating!==!1&&document.body.appendChild(b({position:o.position,offsetX:o.offsetX,offsetY:o.offsetY})),v(document)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",A):A()})();
@@ -76,6 +76,7 @@ function sanitisePreset(data) {
76
76
  navbar: data.navbar !== false,
77
77
  footer: data.footer !== false,
78
78
  sidebar: data.sidebar === true,
79
+ sidebarSide: data.sidebarSide === 'right' ? 'right' : 'left',
79
80
  width: VALID_WIDTHS.has(data.width) ? data.width : 'normal',
80
81
  bgColor: data.bgColor && BG_COLOR_RE.test(data.bgColor) ? data.bgColor : '',
81
82
  bgImage: typeof data.bgImage === 'string' ? data.bgImage.trim() : '',
@@ -3596,6 +3596,53 @@ function processSpacerBlocks(markdown) {
3596
3596
  ));
3597
3597
  }
3598
3598
 
3599
+ /**
3600
+ * [theme-switcher] - the site's theme dots, placed by the page.
3601
+ *
3602
+ * Syntax:
3603
+ * [theme-switcher /] inline, where the tag stands
3604
+ * [theme-switcher position="bottom-left" offset-x="24" offset-y="24" /]
3605
+ * [theme-switcher themes="charcoal-dark,charcoal-light" /]
3606
+ *
3607
+ * Supported attributes:
3608
+ * position - inline (default) | top-left | top-right | left-center |
3609
+ * right-center | bottom-left | bottom-right (pinned to the window)
3610
+ * offset-x, offset-y - distance from the window's edges when pinned (0-400 px, default 32)
3611
+ * themes - a comma list narrowing the themes chosen under Appearance >
3612
+ * Theme switcher (the site's list when absent or none match)
3613
+ *
3614
+ * Leaves a slot that public/js/theme-switcher.js mounts. The renderer loads
3615
+ * that script when the slot is present, with the floating switcher off or on,
3616
+ * and a page with the tag shows it instead of the floating one.
3617
+ *
3618
+ * @param {string} markdown
3619
+ * @returns {string}
3620
+ */
3621
+ export const THEME_SWITCHER_POSITIONS = ['inline', 'top-left', 'top-right', 'left-center', 'right-center', 'bottom-left', 'bottom-right'];
3622
+
3623
+ function processThemeSwitcherBlocks(markdown) {
3624
+ const {scrubbed, restore} = scrubCodeRegions(markdown);
3625
+ return restore(scrubbed.replace(
3626
+ /\[theme-switcher([^\]]*?)\/?\]/gi,
3627
+ (_, attrStr) => {
3628
+ const attrs = parseShortcodeAttrs(attrStr || '');
3629
+ const position = THEME_SWITCHER_POSITIONS.includes(attrs.position) ? attrs.position : 'inline';
3630
+ const offset = (v) => {
3631
+ const n = parseInt(v, 10);
3632
+ return Number.isFinite(n) ? Math.min(400, Math.max(0, n)) : null;
3633
+ };
3634
+ const themes = String(attrs.themes || '').split(',').map(t => t.trim()).filter(t => /^[a-z0-9-]+$/.test(t)).join(',');
3635
+ const data = [`data-theme-switcher="page"`, `data-position="${position}"`];
3636
+ if (position !== 'inline') {
3637
+ if (offset(attrs['offset-x']) !== null) data.push(`data-offset-x="${offset(attrs['offset-x'])}"`);
3638
+ if (offset(attrs['offset-y']) !== null) data.push(`data-offset-y="${offset(attrs['offset-y'])}"`);
3639
+ }
3640
+ if (themes) data.push(`data-themes="${themes}"`);
3641
+ return `<span class="dm-theme-switcher-slot" ${data.join(' ')}></span>`;
3642
+ }
3643
+ ));
3644
+ }
3645
+
3599
3646
  /**
3600
3647
  * Pre-process [center]...[/center] shortcodes before running through marked.
3601
3648
  *
@@ -4423,7 +4470,8 @@ export async function parseMarkdown(raw, opts = {}) {
4423
4470
  const withTimeline = processTimelineBlocks(withCountdown);
4424
4471
  const withListGroup = processListGroupBlocks(withTimeline);
4425
4472
  const withSpacer = processSpacerBlocks(withListGroup);
4426
- const withCenter = processCenterBlocks(withSpacer);
4473
+ const withSwitcher = processThemeSwitcherBlocks(withSpacer);
4474
+ const withCenter = processCenterBlocks(withSwitcher);
4427
4475
  const withIcon = processIconBlocks(withCenter);
4428
4476
  const withDemo = processDemoBlocks(withIcon);
4429
4477
  const withEmbed = processEmbedBlocks(withDemo);
@@ -47,6 +47,10 @@ export function renderMenuItemsAsUl(items, currentPath = '') {
47
47
  if (it && it.type === 'spacer') {
48
48
  return `<li class="dm-menu-spacer dm-menu-spacer--${esc(spacerSize(it))}" aria-hidden="true"></li>`;
49
49
  }
50
+ // The site's theme dots, mounted by theme-switcher.js.
51
+ if (it && it.type === 'theme-switcher') {
52
+ return '<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';
53
+ }
50
54
  const href = esc(it.url || '#');
51
55
  const text = esc(it.text || '');
52
56
  const child = Array.isArray(it.items) && it.items.length ? renderMenuItemsAsUl(it.items, currentPath) : '';
@@ -248,6 +248,21 @@ export function spacerSize(item) {
248
248
  return SPACER_SIZES.has(item?.size) ? item.size : SPACER_DEFAULT_SIZE;
249
249
  }
250
250
 
251
+ // ---------------------------------------------------------------------------
252
+ // Theme switcher items - `{type: 'theme-switcher'}`, the site's theme dots
253
+ // placed among a menu's links. Like a spacer it has no text or url; it shows
254
+ // the themes chosen under Appearance > Theme switcher, whether or not the
255
+ // floating switcher itself is on.
256
+ // ---------------------------------------------------------------------------
257
+
258
+ /** Items that hold no link: they are drawn, not navigated. */
259
+ export const isStructuralItem = (it) => !!it && (it.type === 'separator' || it.type === 'spacer' || it.type === 'theme-switcher');
260
+
261
+ /** True when a menu (at any depth) carries a theme switcher item. */
262
+ export function hasThemeSwitcherItem(items) {
263
+ return (items || []).some(it => it && (it.type === 'theme-switcher' || hasThemeSwitcherItem(it.items)));
264
+ }
265
+
251
266
  export const ORIENTATIONS = new Set(['horizontal', 'vertical']);
252
267
  export const SIDES = new Set(['left', 'right']);
253
268
 
@@ -315,7 +330,7 @@ export async function resolveMenuDecorations(items, opts = {}) {
315
330
 
316
331
  async function walk(list) {
317
332
  return Promise.all((list || []).map(async (it) => {
318
- if (!it || it.type === 'separator' || it.type === 'spacer') return it;
333
+ if (!it || isStructuralItem(it)) return it;
319
334
  const next = {...it};
320
335
  if (it.badge && it.badge.countFrom) {
321
336
  try {
@@ -751,6 +766,9 @@ export function validateMenu(menu) {
751
766
  // Renderers translate them into <hr> / structural breaks.
752
767
  if (item && item.type === 'separator') return;
753
768
 
769
+ // A theme switcher has nothing to point at either.
770
+ if (item && item.type === 'theme-switcher') return;
771
+
754
772
  // Spacers are blank room, likewise with nothing to point at.
755
773
  if (item && item.type === 'spacer') {
756
774
  if (item.size != null && !SPACER_SIZES.has(item.size)) {
@@ -8,7 +8,7 @@ import {fileURLToPath} from 'url';
8
8
  import {getConfig} from '../config.js';
9
9
  import {getInjectionSnippets} from './plugins.js';
10
10
  import {applyTransforms} from './hooks.js';
11
- import {resolveLocation, resolveMenuDecorations, resolveOverlaysForPage} from './menus.js';
11
+ import {hasThemeSwitcherItem, resolveLocation, resolveMenuDecorations, resolveOverlaysForPage} from './menus.js';
12
12
  import {buildMenuNav} from './menuRender.js';
13
13
  import {getProjectForPage} from './projects.js';
14
14
  import {resolveContextMenusForPage} from './contextMenus.js';
@@ -77,7 +77,7 @@ function buildSearchAssets() {
77
77
  };
78
78
  }
79
79
 
80
- const THEME_SWITCHER_ASSET_V = '20260925-ts';
80
+ const THEME_SWITCHER_ASSET_V = '20261011-ts-inline';
81
81
  const ANALYTICS_ASSET_V = '20260922-analytics';
82
82
 
83
83
  /**
@@ -112,11 +112,23 @@ function buildAnalyticsTag() {
112
112
  * Both render paths need this, the same standing trap buildThemeView() and
113
113
  * buildSearchAssets() carry.
114
114
  *
115
- * @returns {{headTag: string, bodyTag: string}} Empty strings when it is off
115
+ * A switcher is also placed by a `{type: 'theme-switcher'}` menu item or the
116
+ * `[theme-switcher]` tag, which need the script and the theme list even with
117
+ * the floating disc off - so the page's html and its menus are passed in. A
118
+ * page with the tag shows that one instead of the floating disc.
119
+ *
120
+ * @param {object} themeCfg
121
+ * @param {{html?: string, menus?: Array<Array>}} [page] The page's rendered
122
+ * html (body and overlay menus) and the item lists of its navbar and footers
123
+ * @returns {{headTag: string, bodyTag: string}} Empty strings when nothing needs it
116
124
  */
117
- function buildThemeSwitcherAssets(themeCfg) {
118
- const sw = themeCfg?.switcher;
119
- if (!sw || sw.enabled !== true) return {headTag: '', bodyTag: ''};
125
+ function buildThemeSwitcherAssets(themeCfg, page = {}) {
126
+ const sw = themeCfg?.switcher || {};
127
+ const html = page.html || '';
128
+ const pageTag = html.includes('data-theme-switcher="page"');
129
+ const inMenu = html.includes('data-theme-switcher="menu"') || (page.menus || []).some(hasThemeSwitcherItem);
130
+ const floating = sw.enabled === true && !pageTag;
131
+ if (!floating && !pageTag && !inMenu) return {headTag: '', bodyTag: ''};
120
132
 
121
133
  let ids;
122
134
  try {
@@ -140,6 +152,7 @@ function buildThemeSwitcherAssets(themeCfg) {
140
152
  });
141
153
 
142
154
  const payload = {
155
+ floating,
143
156
  position: sw.position || 'right-center',
144
157
  offsetX: sw.offsetX ?? 32,
145
158
  offsetY: sw.offsetY ?? 32,
@@ -321,7 +334,10 @@ export async function renderPage(page, opts = {}) {
321
334
 
322
335
  const themeView = await buildThemeView(page);
323
336
  const searchAssets = buildSearchAssets();
324
- const switcherAssets = buildThemeSwitcherAssets(themeView.cfg);
337
+ const switcherAssets = buildThemeSwitcherAssets(themeView.cfg, {
338
+ html: `${page.html || ''}${overlayMenus}`,
339
+ menus: [navItemsDecorated, footerPrimaryDecorated, footerLegalDecorated]
340
+ });
325
341
  const {fontLink, fontStyleTag, autoTheme, activeTheme, dommaTheme, customThemeClass} = themeView;
326
342
 
327
343
  const {navbarFontLink, navbarStyleTag} = buildNavbarStyleTag(navigation);
@@ -391,6 +407,7 @@ export async function renderPage(page, opts = {}) {
391
407
  showNavbar: preset.navbar !== false,
392
408
  showFooter: preset.footer !== false,
393
409
  showSidebar: preset.sidebar === true || page.sidebar === true,
410
+ sidebarRight: (page.sidebarSide || preset.sidebarSide) === 'right',
394
411
  navJson: JSON.stringify(filterHiddenNavItems(navigation)).replace(/<\/script>/gi, '<\\/script>'),
395
412
  footerScript: footerJson ? `window.__CMS_FOOTER__ = ${footerJson};` : '',
396
413
  ctxMenusScript: ctxMenusScript,
@@ -1042,7 +1059,10 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
1042
1059
  // other is the standing trap in this file.
1043
1060
  const themeView = await buildThemeView({});
1044
1061
  const searchAssets = buildSearchAssets();
1045
- const switcherAssets = buildThemeSwitcherAssets(themeView.cfg);
1062
+ const switcherAssets = buildThemeSwitcherAssets(themeView.cfg, {
1063
+ html: `${renderedFragment || ''}${overlayMenus}`,
1064
+ menus: [navItemsDecorated, footerPrimaryDecorated, footerLegalDecorated]
1065
+ });
1046
1066
  const {fontLink, fontStyleTag, activeTheme, dommaTheme, customThemeClass} = themeView;
1047
1067
  const {navbarFontLink, navbarStyleTag} = buildNavbarStyleTag(navigation);
1048
1068
 
@@ -25,7 +25,7 @@
25
25
  <link rel="stylesheet" href="/dist/domma/themes/domma-themes.css">
26
26
 
27
27
  <!-- Site CSS -->
28
- <link rel="stylesheet" href="/public/css/site.css?v=20261010-with-sidebar">
28
+ <link rel="stylesheet" href="/public/css/site.css?v=20261011-sidebar-right">
29
29
  <link rel="stylesheet" href="/public/css/forms.css?v=20260927-submit-btn-css">
30
30
  <!-- Menu item hover / current-page effects. Loaded after site.css so a
31
31
  menu's own highlight wins over the blanket link styling there. -->
@@ -46,7 +46,7 @@
46
46
  <nav id="site-navbar" class="{{navbarClass}}"></nav>
47
47
  {{/if}}
48
48
 
49
- <main class="site-main {{#if showSidebar}}with-sidebar{{/if}}">
49
+ <main class="site-main {{#if showSidebar}}with-sidebar{{/if}} {{#if sidebarRight}}sidebar-right{{/if}}">
50
50
  {{#if showSidebar}}
51
51
  <aside id="site-sidebar" class="site-sidebar"></aside>
52
52
  {{/if}}
@@ -137,7 +137,7 @@
137
137
  </script>
138
138
 
139
139
  <!-- Site initialisation -->
140
- <script src="/public/js/site.js?v=20261010-with-sidebar" type="module"></script>
140
+ <script src="/public/js/site.js?v=20261011-theme-switcher-item" type="module"></script>
141
141
  <script src="/public/js/collection-context.js?v=20261010-utf8-payloads" type="module"></script>
142
142
  {{ctxMenusModule}}
143
143