maverick-wave 5.2.0 → 5.4.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.
@@ -1 +1 @@
1
- !function(){"use strict";function e(e,t){e&&(e.classList.toggle("mw-active",t),t||e.classList.remove("active"))}function t(e){return!!e&&(e.classList.contains("mw-active")||e.classList.contains("active"))}function n(){const e=Array.from(document.querySelectorAll(".color-swatch")),t=e.map(e=>function(e){if(!e||"transparent"===e)return"#000000";const t=e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0"),n=e.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\)/);if(n){const e="#"+t(255*n[1])+t(255*n[2])+t(255*n[3]),a=void 0===n[4]?1:parseFloat(n[4]);return(a<1?`${e} / ${a}`:e).toUpperCase()}const a=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(!a)return e;const o="#"+t(a[1])+t(a[2])+t(a[3]),r=void 0===a[4]?1:parseFloat(a[4]);return(r<1?`${o} / ${r}`:o).toUpperCase()}(window.getComputedStyle(e).backgroundColor));e.forEach((e,n)=>{const a=e.parentElement.querySelector(".mw-text-muted");a&&(a.textContent=t[n])})}function a(e){const t=e.querySelector(".mw-tabs-nav-item.mw-active, .mw-tabs-nav-item.active");t?(e.style.setProperty("--mw-tabs-marker-x",t.offsetLeft+"px"),e.style.setProperty("--mw-tabs-marker-w",t.offsetWidth),e.style.setProperty("--mw-tabs-marker-y",t.offsetTop+"px"),e.style.setProperty("--mw-tabs-marker-h",t.offsetHeight),e.setAttribute("data-mw-tabs-marker","")):e.removeAttribute("data-mw-tabs-marker")}function o(e){const t=e.getAttribute("data-tab");return t?document.getElementById(t):null}function r(e){const n=t(e);e.setAttribute("aria-selected",String(n)),e.tabIndex=n?0:-1}function c(t,n){t.forEach(t=>{const a=t===n;e(t,a),e(o(t),a),r(t)});const c=n.closest(".mw-tabs-nav");c&&a(c)}function s(e){e&&("DIALOG"===e.tagName?e.showModal():e.classList.add("mw-modal-open"))}function l(e){const t=Array.from(e.querySelectorAll(".mw-kanban-column")),n=e.querySelector(".mw-kanban-composer"),a=e.querySelector(".mw-kanban-card-template"),o=e.dataset.kanbanPrefix||"MW",r=n.querySelector(".mw-kanban-composer-title"),c=n.querySelector(".mw-kanban-composer-text"),s=n.querySelector(".mw-kanban-composer-priority"),l=n.querySelector(".mw-kanban-composer-assignee");let i=null;function d(){t.forEach(function(e,n){const a=e.querySelectorAll(".mw-kanban-card"),o=e.querySelector(".mw-kanban-count");o&&(o.textContent=a.length),e.querySelectorAll("[data-kanban-move]").forEach(function(e){const a=n+parseInt(e.dataset.kanbanMove,10);e.disabled=a<0||a>=t.length})})}function u(e,t){const n=e.querySelector(t);return n?n.textContent.replace(/\s+/g," ").trim():""}function m(e,t){w(),i=t||null,r.value=t?u(t,".mw-kanban-card-title"):"",c.value=t?u(t,".mw-kanban-card-text"):"",s.value=t?function(e){const t=e.querySelector(".mw-card-ribbon");if(!t)return"";const n=Array.from(t.classList).find(function(e){return 0===e.indexOf("mw-card-addon-")});return n?n.replace("mw-card-addon-",""):""}(t):"",l.value=t?function(e){const t=e.querySelector(".mw-avatar-initials");return t?t.textContent.trim():""}(t):"",t?(t.classList.add("mw-kanban-editing"),t.before(n)):e.querySelector(".mw-kanban-column-body").prepend(n),n.classList.add("mw-active"),r.focus()}function w(){n.classList.remove("mw-active"),i&&i.classList.remove("mw-kanban-editing"),i=null}function f(){const t=r.value.trim();if(!t)return void r.focus();const u=i||a.content.firstElementChild.cloneNode(!0);if(u.querySelector(".mw-kanban-card-title").textContent=t,u.querySelector(".mw-kanban-card-text").textContent=c.value.trim(),function(e,t){const n=e.querySelector(".mw-card-ribbon");if(n&&n.remove(),!t||!t.value)return;const a=document.createElement("div");a.className="mw-card-ribbon mw-card-addon-"+t.value,a.textContent=t.textContent,e.prepend(a)}(u,s.selectedOptions[0]),function(e,t){const n=e.querySelector(".mw-kanban-card-actions"),a=n.querySelector(".mw-avatar");if(!t)return void(a&&a.remove());const o=a||document.createElement("div");o.className="mw-avatar mw-avatar-xs mw-avatar-initials",o.textContent=t,a||n.prepend(o)}(u,l.value),!i){const t=function(){const t=Array.from(e.querySelectorAll(".mw-kanban-card-id")).map(function(e){return parseInt(e.textContent.split("-").pop(),10)||0});return o+"-"+(Math.max(0,...t)+1)}();u.classList.add("mw-kanban-card-in"),u.querySelector(".mw-kanban-card-id").textContent=t,u.querySelectorAll("[aria-label]").forEach(function(e){e.setAttribute("aria-label",e.getAttribute("aria-label").replace(/[A-Z]+-\d+/,t))}),n.before(u)}w(),d()}const g=["mw-kanban-card-moved-forward","mw-kanban-card-moved-back"];e.addEventListener("click",function(e){const n=e.target.closest("[data-kanban-move]");if(n){if(function(e,n){const a=e.closest(".mw-kanban-column"),o=t[t.indexOf(a)+n];o&&(o.querySelector(".mw-kanban-column-body").appendChild(e),e.classList.remove.apply(e.classList,g),e.offsetWidth,e.classList.add(n>0?g[0]:g[1]),d())}(n.closest(".mw-kanban-card"),parseInt(n.dataset.kanbanMove,10)),n.disabled){const e=n.parentElement.querySelector("[data-kanban-move]:not(:disabled)");e&&e.focus()}return}const a=e.target.closest(".mw-kanban-edit");if(a){const e=a.closest(".mw-kanban-card");return void m(e.closest(".mw-kanban-column"),e)}const o=e.target.closest(".mw-kanban-delete");if(o){const e=o.closest(".mw-kanban-card");return e===i&&w(),e.remove(),void d()}const r=e.target.closest(".mw-kanban-add");r?m(r.closest(".mw-kanban-column"),null):e.target.closest(".mw-kanban-composer-cancel")&&w()}),n.addEventListener("submit",function(e){e.preventDefault(),f()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&w()}),d()}function i(e){const t=e.querySelector(".mw-calendar-grid"),n=e.querySelector(".mw-calendar-title");if(!t)return;const a="week"===e.dataset.calendar,o=function(e){if(!e)return{};try{return JSON.parse(e)}catch(e){return{}}}(e.dataset.calendarMarkers),r=e.dataset.calendarLocale||document.documentElement.lang||void 0,c=new Date;c.setHours(0,0,0,0);let s=e.dataset.calendarDate?new Date(e.dataset.calendarDate+"T00:00:00"):new Date(c),l=e.dataset.calendarSelected||"";function i(e){const t=new Date(e);return t.setDate(t.getDate()-(t.getDay()+6)%7),t}function d(e){return e.getFullYear()+"-"+String(e.getMonth()+1).padStart(2,"0")+"-"+String(e.getDate()).padStart(2,"0")}function u(){if(!a)return s.toLocaleDateString(r,{month:"long",year:"numeric"});const e=i(s),t=new Date(e);t.setDate(t.getDate()+6);const n=e.toLocaleDateString(r,{day:"numeric",month:e.getMonth()===t.getMonth()?void 0:"short"}),o=t.toLocaleDateString(r,{day:"numeric",month:"short",year:"numeric"});return"Week "+function(e){const t=i(e);t.setDate(t.getDate()+3);const n=i(new Date(t.getFullYear(),0,4));return n.setDate(n.getDate()+3),1+Math.round((t-n)/6048e5)}(e)+" · "+n+" - "+o}function m(e){const t=e.getDay();return 0===t||6===t}function w(e,t){const n=d(e),s=document.createElement("button");s.type="button",s.className="mw-calendar-day",s.tabIndex=-1,s.dataset.calendarDay=n,s.setAttribute("aria-pressed",n===l?"true":"false"),s.setAttribute("aria-label",e.toLocaleDateString(r,{weekday:"long",day:"numeric",month:"long",year:"numeric"})),m(e)&&s.classList.add("mw-calendar-weekend"),a||e.getMonth()===t||s.classList.add("mw-calendar-adjacent"),n===d(c)&&(s.classList.add("mw-calendar-today"),s.setAttribute("aria-current","date")),n===l&&s.classList.add("mw-selected");const i=document.createElement("span");i.className="mw-calendar-date",i.textContent=e.getDate(),s.appendChild(i);const u=[].concat(o[n]||[]);if(u.length){const e=document.createElement("span");e.className="mw-calendar-dots",u.forEach(function(t){const n=document.createElement("span");n.className=t?"mw-calendar-dot mw-calendar-dot-"+t:"mw-calendar-dot",e.appendChild(n)}),s.appendChild(e)}return s}function f(){const e=s.getMonth(),o=a?7:42,c=i(a?s:new Date(s.getFullYear(),e,1));t.innerHTML="",function(){const e=i(new Date);for(let n=0;n<7;n++){const n=document.createElement("div");n.className="mw-calendar-weekday",m(e)&&n.classList.add("mw-calendar-weekend"),n.setAttribute("aria-hidden","true"),n.textContent=e.toLocaleDateString(r,{weekday:"short"}),t.appendChild(n),e.setDate(e.getDate()+1)}}();for(let n=0;n<o;n++)t.appendChild(w(c,e)),c.setDate(c.getDate()+1);n&&(n.textContent=u()),function(){const e=t.querySelector(".mw-selected")||t.querySelector(".mw-calendar-today")||t.querySelector(".mw-calendar-day:not(.mw-calendar-adjacent)")||t.querySelector(".mw-calendar-day");e&&(e.tabIndex=0)}()}e.addEventListener("click",function(n){const o=n.target.closest("[data-calendar-nav]");if(o)return r=parseInt(o.dataset.calendarNav,10),a?s.setDate(s.getDate()+7*r):s=new Date(s.getFullYear(),s.getMonth()+r,1),void f();var r;const c=n.target.closest(".mw-calendar-day");var i;c&&!c.disabled&&(i=c.dataset.calendarDay,l=i===l?"":i,t.querySelectorAll(".mw-calendar-day").forEach(function(e){const t=e.dataset.calendarDay===l;e.classList.toggle("mw-selected",t),e.setAttribute("aria-pressed",t?"true":"false")}),e.dispatchEvent(new CustomEvent("mw-calendar-select",{bubbles:!0,detail:{date:l}})))}),t.addEventListener("keydown",function(e){const n={ArrowLeft:-1,ArrowRight:1,ArrowUp:-7,ArrowDown:7}[e.key];if(!n)return;const a=e.target.closest(".mw-calendar-day");if(!a)return;e.preventDefault();const o=new Date(a.dataset.calendarDay+"T00:00:00");o.setDate(o.getDate()+n),function(e){const n=d(e);let a=t.querySelector('[data-calendar-day="'+n+'"]');a||(s=new Date(e),f(),a=t.querySelector('[data-calendar-day="'+n+'"]')),a&&(t.querySelectorAll(".mw-calendar-day").forEach(function(e){e.tabIndex=-1}),a.tabIndex=0,a.focus())}(o)}),f()}document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll(".mw-gallery").forEach(e=>{const t=e.closest(".mw-gallery-container")||e.parentElement;t&&function(e,t){const n=t.querySelector(".mw-gallery-track");if(!n||!n.children.length)return;const a=n.children,o=e.querySelector(".mw-gallery-dots"),r=e.querySelector(".mw-gallery-desc"),c=t.querySelector(".mw-gallery-navi-prev"),s=t.querySelector(".mw-gallery-navi-next");let l=0;function i(e){const t=a.length;l=(e+t)%t,n.style.transform=`translateX(-${100*l}%)`,o&&o.querySelectorAll(".mw-gallery-dot").forEach((e,t)=>{e.classList.toggle("mw-active",t===l)}),r&&(r.textContent=a[l].dataset.desc||"")}if(o)for(let e=0;e<a.length;e++){const t=document.createElement("button");t.type="button",t.className="mw-gallery-dot"+(0===e?" mw-active":""),t.setAttribute("aria-label","Go to slide "+(e+1)),t.addEventListener("click",()=>i(e)),o.appendChild(t)}c&&c.addEventListener("click",()=>i(l-1)),s&&s.addEventListener("click",()=>i(l+1));let d=0;n.addEventListener("touchstart",e=>d=e.touches[0].clientX),n.addEventListener("touchend",e=>{const t=e.changedTouches[0].clientX-d;t>50&&i(l-1),t<-50&&i(l+1)}),i(0)}(t,e)}),function(){const t=document.querySelector(".mw-theme-toggle");if(!t)return;const a=document.body,o=document.documentElement,r=t.querySelector(".mw-theme-toggle-slider i"),c=getComputedStyle(document.documentElement).getPropertyValue("--mw-internal-theme-mode").trim()||"switchable";if("switchable"!==c)return console.log(`Theme mode fixed to: ${c}. Disabling toggle.`),r&&(r.className="light"===c?"fas fa-sun":"fas fa-moon"),e(t,"light"===c),t.style.opacity="0.4",t.style.pointerEvents="none",t.style.cursor="default",t.setAttribute("aria-disabled","true"),localStorage.removeItem("mw-theme"),void("dark"===c&&a.classList.remove("mw-theme-light"));let s="light"===localStorage.getItem("mw-theme");const l=n=>{o.classList.add("mw-theme-switching"),a.classList.toggle("mw-theme-light",n),o.offsetHeight,o.classList.remove("mw-theme-switching"),e(t,n),r&&(r.className=n?"fas fa-sun":"fas fa-moon")};l(s),t.addEventListener("click",()=>{s=!s,l(s),localStorage.setItem("mw-theme",s?"light":"dark"),n()})}(),n(),document.querySelectorAll(".mw-accordion-header").forEach(n=>{const a="BUTTON"===n.tagName;a&&n.setAttribute("aria-expanded",String(t(n))),n.addEventListener("click",function(){const n=!t(this);e(this,n),e(this.nextElementSibling,n),a&&this.setAttribute("aria-expanded",String(n))})}),function(){const e=document.querySelector(".mw-menu-btn"),t=document.querySelector(".mw-navbar");if(!e||!t)return;const n="BUTTON"===e.tagName;function a(a){e.classList.toggle("open",a),t.classList.toggle("open",a),n&&e.setAttribute("aria-expanded",String(a))}function o(e){e.preventDefault(),e.stopPropagation(),a(!t.classList.contains("open"))}e.addEventListener("click",o),e.addEventListener("touchstart",o,{passive:!1}),document.addEventListener("click",function(n){t.classList.contains("open")&&(t.contains(n.target)||e.contains(n.target)||a(!1))}),document.addEventListener("keydown",function(n){"Escape"===n.key&&t.classList.contains("open")&&(a(!1),e.focus())})}(),function(){const e=document.querySelectorAll(".mw-progress-fill");if(!e.length)return;const t=CSS.supports("animation-timeline","view()"),n=e=>e.dataset.value?e.dataset.value+"%":e.style.width,a=[];if(e.forEach(e=>{const o=n(e);o&&(e.style.setProperty("--mw-progress-value",o),t?e.classList.add("mw-progress-driven"):a.push(e))}),t)return;const o=new IntersectionObserver((e,t)=>{e.forEach(e=>{e.isIntersecting&&(e.target.style.width=n(e.target),t.unobserve(e.target))})},{root:null,threshold:.2});a.forEach(e=>o.observe(e))}(),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){const t=this.getAttribute("href");if("#"===t)return;if(!document.querySelector(t))return;const n=document.querySelector(".mw-menu-btn"),a=document.querySelector(".mw-navbar");n&&a&&(n.classList.remove("open"),a.classList.remove("open"))})}),function(){const t=document.querySelectorAll("section[id]"),n=document.querySelectorAll(".mw-navbar-link");if(0===t.length||0===n.length)return;function a(){const e=parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop);return(Number.isNaN(e)?0:e)+2}window.addEventListener("scroll",function(e,t){let n;return function(){const a=this,o=arguments;clearTimeout(n),n=setTimeout(()=>e.apply(a,o),t)}}(function(){let o="";const r=a();t.forEach(e=>{const t=e.offsetTop-r,n=e.clientHeight;scrollY>=t&&scrollY<t+n&&(o=e.getAttribute("id"))}),n.forEach(t=>{e(t,!1);const n=t.getAttribute("href");if(n){const a=n.indexOf("#");if(-1!==a){n.substring(a+1)===o&&e(t,!0)}}})},100))}(),document.querySelectorAll(".mw-tabs-nav").forEach(e=>{const t=Array.from(e.querySelectorAll(".mw-tabs-nav-item"));if(!t.length)return;const n=!!e.closest(".mw-tabs-vertical");e.setAttribute("role","tablist"),n&&e.setAttribute("aria-orientation","vertical"),t.forEach((e,a)=>{const s=o(e);e.setAttribute("role","tab"),e.id||(e.id=(s?s.id:"mw-tab-"+a)+"-tab"),s&&(e.setAttribute("aria-controls",s.id),s.setAttribute("role","tabpanel"),s.setAttribute("aria-labelledby",e.id)),r(e),e.addEventListener("click",()=>c(t,e)),e.addEventListener("keydown",e=>{const o=function(e,t,n,a){const o=t?"ArrowUp":"ArrowLeft",r=t?"ArrowDown":"ArrowRight";return e.key===o?(a-1+n)%n:e.key===r?(a+1)%n:"Home"===e.key?0:"End"===e.key?n-1:null}(e,n,t.length,a);null!==o&&(e.preventDefault(),c(t,t[o]),t[o].focus())})}),a(e);const s=new ResizeObserver(()=>a(e));s.observe(e),t.forEach(e=>s.observe(e))}),document.querySelectorAll(".mw-alert-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-alert");e&&(e.classList.add("mw-alert-closing"),setTimeout(()=>{e.classList.add("mw-alert-closed")},300))})}),function(){const e=document.querySelector(".mw-localhost-indicator-activated"),t=document.querySelector(".mw-header");if(e){if("localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname||window.location.hostname.includes("192.168.")){const e=document.createElement("div");e.className="mw-localhost-indicator-pulse",t.prepend(e)}}}(),document.querySelectorAll(".mw-slider-container").forEach(e=>{const t=e.querySelector(".mw-slider"),n=e.querySelector(".mw-slider-value");if(!t||!n)return;const a=()=>{const e=Number(t.value),a=Number(t.max)||100,o=Math.round(e/a*100);t.style.setProperty("--value",o+"%"),n.classList.contains("mw-slider-numeric")?n.setAttribute("data-value",e):n.setAttribute("data-value",o)};t.addEventListener("input",a),a()}),document.addEventListener("click",e=>{const t=e.target.closest(".mw-modal-close");if(t){const e=t.closest("dialog.mw-modal");if(e)return void e.close();const n=t.closest(".mw-modal-overlay");return void(n&&n.classList.remove("mw-modal-open"))}const n=e.target.closest("[data-mw-modal]");var a;n?s(document.getElementById(n.dataset.mwModal)):e.target.matches("dialog.mw-modal[open]")&&(!("closedBy"in(a=e.target))||null===a.getAttribute("closedby"))&&e.target.close()}),function(){const e=document.getElementById("login-button");e&&e.addEventListener("click",function(){const e=this.querySelector("i");e.classList.contains("fa-lock")?(e.classList.remove("fa-lock"),e.classList.add("fa-lock-open")):(e.classList.remove("fa-lock-open"),e.classList.add("fa-lock"))})}(),document.querySelectorAll(".mw-image-slider").forEach(t=>{const n=t.querySelectorAll(".mw-image-slider-overlay-image"),a=t.querySelectorAll("button[data-index]");if(!n.length||!a.length)return;let o=0;function r(){n.forEach(t=>{e(t,parseInt(t.dataset.index)===o)}),a.forEach(t=>{e(t,parseInt(t.dataset.index)===o)})}function c(e){o=e,r()}a.forEach(e=>{e.addEventListener("click",()=>{c(parseInt(e.dataset.index))})}),r()}),document.querySelectorAll(".mw-item-list-checkbox, .mw-item-list-checkbox-scroll").forEach(e=>{e.querySelectorAll("li").forEach(e=>{const t=e.querySelector('input[type="checkbox"]'),n=e.querySelector(".mw-checkbox");t&&n&&(t.checked&&e.classList.add("mw-selected"),e.addEventListener("click",function(e){e.target!==t&&e.target.closest(".mw-checkbox")!==n&&toggleCheckbox(this)}),t.addEventListener("change",function(){const e=this.closest("li");this.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:this.checked,item:e}}))}),n.addEventListener("click",function(e){setTimeout(()=>{const e=this.closest("li");this.querySelector('input[type="checkbox"]').checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected")},0)}))})}),document.addEventListener("checkboxToggle",function(e){console.log("Checkbox toggled:",e.detail.checked,e.detail.item)}),document.querySelectorAll(".mw-kanban").forEach(l),document.querySelectorAll("[data-calendar]").forEach(i),function(){function e(e){document.querySelectorAll(".mw-dropdown[open]").forEach(t=>{t!==e&&t.removeAttribute("open")})}document.addEventListener("click",function(t){const n=t.target.closest(".mw-dropdown");e(n),n&&t.target.closest(".mw-dropdown-item")&&n.removeAttribute("open")}),document.addEventListener("keydown",function(e){if("Escape"!==e.key)return;const t=document.querySelector(".mw-dropdown[open]");if(!t)return;t.removeAttribute("open");const n=t.querySelector("summary");n&&n.focus()})}(),document.querySelectorAll(".mw-lang-switch").forEach(t=>{const n=t.querySelectorAll("[data-mw-lang]"),a=t.querySelector("summary"),o=t.querySelector("summary .mw-flag"),r=t.querySelector("summary .mw-lang-switch-code");n.forEach(c=>{c.addEventListener("click",function(){const s=c.dataset.mwLang,l=c.querySelector(".mw-lang-switch-name"),i=l?l.textContent.trim():s;n.forEach(t=>{e(t,t===c),t===c?t.setAttribute("aria-current","true"):t.removeAttribute("aria-current")}),r&&(r.textContent=s);const d=c.querySelector(".mw-flag");o&&d&&(o.className=d.className),a&&a.setAttribute("aria-label","Language: "+i),t.dispatchEvent(new CustomEvent("mw-language-change",{bubbles:!0,detail:{lang:s,name:i}}))})})})}),window.toggleCheckbox=function(e){const t=e.querySelector('input[type="checkbox"]');if(!t)return;const n=t.checked;t.checked=!n,t.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:t.checked,item:e}}))},window.mwOpenModal=e=>s(document.getElementById(e)),window.mwCloseModal=e=>{var t;(t=document.getElementById(e))&&("DIALOG"===t.tagName?t.close():t.classList.remove("mw-modal-open"))}}();
1
+ !function(){"use strict";function e(e,t){e&&(e.classList.toggle("mw-active",t),t||e.classList.remove("active"))}function t(e){return!!e&&(e.classList.contains("mw-active")||e.classList.contains("active"))}function n(){const e=Array.from(document.querySelectorAll(".color-swatch")),t=e.map(e=>function(e){if(!e||"transparent"===e)return"#000000";const t=e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0"),n=e.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\)/);if(n){const e="#"+t(255*n[1])+t(255*n[2])+t(255*n[3]),a=void 0===n[4]?1:parseFloat(n[4]);return(a<1?`${e} / ${a}`:e).toUpperCase()}const a=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(!a)return e;const o="#"+t(a[1])+t(a[2])+t(a[3]),r=void 0===a[4]?1:parseFloat(a[4]);return(r<1?`${o} / ${r}`:o).toUpperCase()}(window.getComputedStyle(e).backgroundColor));e.forEach((e,n)=>{const a=e.parentElement.querySelector(".mw-text-muted");a&&(a.textContent=t[n])})}function a(){const e=parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop);return Number.isNaN(e)?0:e}document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll(".mw-gallery").forEach(e=>{const t=e.closest(".mw-gallery-container")||e.parentElement;t&&function(e,t){const n=t.querySelector(".mw-gallery-track");if(!n||!n.children.length)return;const a=n.children,o=e.querySelector(".mw-gallery-dots"),r=e.querySelector(".mw-gallery-desc"),c=t.querySelector(".mw-gallery-navi-prev"),s=t.querySelector(".mw-gallery-navi-next");let l=0;function i(e){const t=a.length;l=(e+t)%t,n.style.transform=`translateX(-${100*l}%)`,o&&o.querySelectorAll(".mw-gallery-dot").forEach((e,t)=>{e.classList.toggle("mw-active",t===l)}),r&&(r.textContent=a[l].dataset.desc||"")}if(o)for(let e=0;e<a.length;e++){const t=document.createElement("button");t.type="button",t.className="mw-gallery-dot"+(0===e?" mw-active":""),t.setAttribute("aria-label","Go to slide "+(e+1)),t.addEventListener("click",()=>i(e)),o.appendChild(t)}c&&c.addEventListener("click",()=>i(l-1)),s&&s.addEventListener("click",()=>i(l+1));let d=0;n.addEventListener("touchstart",e=>d=e.touches[0].clientX),n.addEventListener("touchend",e=>{const t=e.changedTouches[0].clientX-d;t>50&&i(l-1),t<-50&&i(l+1)}),i(0)}(t,e)}),function(){const t=document.querySelector(".mw-theme-toggle");if(!t)return;const a=document.body,o=document.documentElement,r=t.querySelector(".mw-theme-toggle-slider i"),c=getComputedStyle(document.documentElement).getPropertyValue("--mw-internal-theme-mode").trim()||"switchable";if("switchable"!==c)return console.log(`Theme mode fixed to: ${c}. Disabling toggle.`),r&&(r.className="light"===c?"fas fa-sun":"fas fa-moon"),e(t,"light"===c),t.style.opacity="0.4",t.style.pointerEvents="none",t.style.cursor="default",t.setAttribute("aria-disabled","true"),localStorage.removeItem("mw-theme"),void("dark"===c&&a.classList.remove("mw-theme-light"));let s="light"===localStorage.getItem("mw-theme");const l=n=>{o.classList.add("mw-theme-switching"),a.classList.toggle("mw-theme-light",n),o.offsetHeight,o.classList.remove("mw-theme-switching"),e(t,n),r&&(r.className=n?"fas fa-sun":"fas fa-moon")};l(s),t.addEventListener("click",()=>{s=!s,l(s),localStorage.setItem("mw-theme",s?"light":"dark"),n()})}(),n(),document.querySelectorAll(".mw-accordion-header").forEach(n=>{const a="BUTTON"===n.tagName;a&&n.setAttribute("aria-expanded",String(t(n))),n.addEventListener("click",function(){const n=!t(this);e(this,n),e(this.nextElementSibling,n),a&&this.setAttribute("aria-expanded",String(n))})}),function(){const e=document.querySelector(".mw-menu-btn"),t=document.querySelector(".mw-navbar");if(!e||!t)return;const n="BUTTON"===e.tagName;function a(a){e.classList.toggle("open",a),t.classList.toggle("open",a),n&&e.setAttribute("aria-expanded",String(a))}function o(e){e.preventDefault(),e.stopPropagation(),a(!t.classList.contains("open"))}e.addEventListener("click",o),e.addEventListener("touchstart",o,{passive:!1}),document.addEventListener("click",function(n){t.classList.contains("open")&&(t.contains(n.target)||e.contains(n.target)||a(!1))}),document.addEventListener("keydown",function(n){"Escape"===n.key&&t.classList.contains("open")&&(a(!1),e.focus())})}(),function(){const e=document.querySelectorAll(".mw-progress-fill");if(!e.length)return;const t=CSS.supports("animation-timeline","view()"),n=e=>e.dataset.value?e.dataset.value+"%":e.style.width,a=[];if(e.forEach(e=>{const o=n(e);o&&(e.style.setProperty("--mw-progress-value",o),t?e.classList.add("mw-progress-driven"):a.push(e))}),t)return;const o=new IntersectionObserver((e,t)=>{e.forEach(e=>{e.isIntersecting&&(e.target.style.width=n(e.target),t.unobserve(e.target))})},{root:null,threshold:.2});a.forEach(e=>o.observe(e))}(),function(){function e(e){const t=e.style.position,n="sticky"===getComputedStyle(e).position;n&&(e.style.position="static");const a=e.getBoundingClientRect().top+window.scrollY;return n&&(e.style.position=t),a}function t(e){const t=window.scrollY,n=e-t;if(!n)return;const a=Math.min(1400,420+.35*Math.abs(n)),r=performance.now(),c={};function s(e){if(o!==c)return;const l=Math.min(1,(e-r)/a),i=l<.5?4*l*l*l:1-Math.pow(-2*l+2,3)/2;window.scrollTo({top:t+n*i,behavior:"instant"}),l<1?requestAnimationFrame(s):o=null}o=c,requestAnimationFrame(s)}document.querySelectorAll('a[href^="#"]').forEach(n=>{n.addEventListener("click",function(n){const o=this.getAttribute("href");if("#"===o)return;const r=document.querySelector(o);if(!r)return;const c=document.querySelector(".mw-menu-btn"),s=document.querySelector(".mw-navbar");c&&s&&(c.classList.remove("open"),s.classList.remove("open")),n.preventDefault();const l=Math.max(0,e(r)-a());r.hasAttribute("tabindex")||r.setAttribute("tabindex","-1"),r.focus({preventScroll:!0}),window.matchMedia("(prefers-reduced-motion: reduce)").matches?window.scrollTo({top:l,behavior:"instant"}):t(l),history.replaceState(null,"",o)})})}(),function(){const t=document.querySelectorAll("section[id]"),n=document.querySelectorAll(".mw-navbar-link");if(0===t.length||0===n.length)return;window.addEventListener("scroll",function(e,t){let n;return function(){const a=this,o=arguments;clearTimeout(n),n=setTimeout(()=>e.apply(a,o),t)}}(function(){let o="";const r=a()+2;t.forEach(e=>{const t=e.offsetTop-r,n=e.clientHeight;scrollY>=t&&scrollY<t+n&&(o=e.getAttribute("id"))}),n.forEach(t=>{e(t,!1);const n=t.getAttribute("href");if(n){const a=n.indexOf("#");if(-1!==a){n.substring(a+1)===o&&e(t,!0)}}})},100))}(),document.querySelectorAll(".mw-tabs-nav").forEach(e=>{const t=Array.from(e.querySelectorAll(".mw-tabs-nav-item"));if(!t.length)return;const n=!!e.closest(".mw-tabs-vertical");e.setAttribute("role","tablist"),n&&e.setAttribute("aria-orientation","vertical"),t.forEach((e,a)=>{const o=c(e);e.setAttribute("role","tab"),e.id||(e.id=(o?o.id:"mw-tab-"+a)+"-tab"),o&&(e.setAttribute("aria-controls",o.id),o.setAttribute("role","tabpanel"),o.setAttribute("aria-labelledby",e.id)),s(e),e.addEventListener("click",()=>l(t,e)),e.addEventListener("keydown",e=>{const o=function(e,t,n,a){const o=t?"ArrowUp":"ArrowLeft",r=t?"ArrowDown":"ArrowRight";return e.key===o?(a-1+n)%n:e.key===r?(a+1)%n:"Home"===e.key?0:"End"===e.key?n-1:null}(e,n,t.length,a);null!==o&&(e.preventDefault(),l(t,t[o]),t[o].focus())})}),r(e);const a=new ResizeObserver(()=>r(e));a.observe(e),t.forEach(e=>a.observe(e))}),document.querySelectorAll(".mw-alert-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-alert");e&&(e.classList.add("mw-alert-closing"),setTimeout(()=>{e.classList.add("mw-alert-closed")},300))})}),function(){const e=document.querySelector(".mw-localhost-indicator-activated"),t=document.querySelector(".mw-header");if(e){if("localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname||window.location.hostname.includes("192.168.")){const e=document.createElement("div");e.className="mw-localhost-indicator-pulse",t.prepend(e)}}}(),document.querySelectorAll(".mw-slider-container").forEach(e=>{const t=e.querySelector(".mw-slider"),n=e.querySelector(".mw-slider-value");if(!t||!n)return;const a=()=>{const e=Number(t.value),a=Number(t.max)||100,o=Math.round(e/a*100);t.style.setProperty("--value",o+"%"),n.classList.contains("mw-slider-numeric")?n.setAttribute("data-value",e):n.setAttribute("data-value",o)};t.addEventListener("input",a),a()}),document.addEventListener("click",e=>{const t=e.target.closest(".mw-modal-close");if(t){const e=t.closest("dialog.mw-modal");if(e)return void e.close();const n=t.closest(".mw-modal-overlay");return void(n&&n.classList.remove("mw-modal-open"))}const n=e.target.closest("[data-mw-modal]");var a;n?i(document.getElementById(n.dataset.mwModal)):e.target.matches("dialog.mw-modal[open]")&&(!("closedBy"in(a=e.target))||null===a.getAttribute("closedby"))&&e.target.close()}),function(){const e=document.getElementById("login-button");e&&e.addEventListener("click",function(){const e=this.querySelector("i");e.classList.contains("fa-lock")?(e.classList.remove("fa-lock"),e.classList.add("fa-lock-open")):(e.classList.remove("fa-lock-open"),e.classList.add("fa-lock"))})}(),document.querySelectorAll(".mw-image-slider").forEach(t=>{const n=t.querySelectorAll(".mw-image-slider-overlay-image"),a=t.querySelectorAll("button[data-index]");if(!n.length||!a.length)return;let o=0;function r(){n.forEach(t=>{e(t,parseInt(t.dataset.index)===o)}),a.forEach(t=>{e(t,parseInt(t.dataset.index)===o)})}function c(e){o=e,r()}a.forEach(e=>{e.addEventListener("click",()=>{c(parseInt(e.dataset.index))})}),r()}),document.querySelectorAll(".mw-item-list-checkbox, .mw-item-list-checkbox-scroll").forEach(e=>{e.querySelectorAll("li").forEach(e=>{const t=e.querySelector('input[type="checkbox"]'),n=e.querySelector(".mw-checkbox");t&&n&&(t.checked&&e.classList.add("mw-selected"),e.addEventListener("click",function(e){e.target!==t&&e.target.closest(".mw-checkbox")!==n&&toggleCheckbox(this)}),t.addEventListener("change",function(){const e=this.closest("li");this.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:this.checked,item:e}}))}),n.addEventListener("click",function(e){setTimeout(()=>{const e=this.closest("li");this.querySelector('input[type="checkbox"]').checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected")},0)}))})}),document.addEventListener("checkboxToggle",function(e){console.log("Checkbox toggled:",e.detail.checked,e.detail.item)}),document.querySelectorAll(".mw-kanban").forEach(d),document.querySelectorAll("[data-calendar]").forEach(u),function(){function e(e){document.querySelectorAll(".mw-dropdown[open]").forEach(t=>{t!==e&&t.removeAttribute("open")})}document.addEventListener("click",function(t){const n=t.target.closest(".mw-dropdown");e(n),n&&t.target.closest(".mw-dropdown-item")&&n.removeAttribute("open")}),document.addEventListener("keydown",function(e){if("Escape"!==e.key)return;const t=document.querySelector(".mw-dropdown[open]");if(!t)return;t.removeAttribute("open");const n=t.querySelector("summary");n&&n.focus()})}(),document.querySelectorAll(".mw-lang-switch").forEach(t=>{const n=t.querySelectorAll("[data-mw-lang]"),a=t.querySelector("summary"),o=t.querySelector("summary .mw-flag"),r=t.querySelector("summary .mw-lang-switch-code");n.forEach(c=>{c.addEventListener("click",function(){const s=c.dataset.mwLang,l=c.querySelector(".mw-lang-switch-name"),i=l?l.textContent.trim():s;n.forEach(t=>{e(t,t===c),t===c?t.setAttribute("aria-current","true"):t.removeAttribute("aria-current")}),r&&(r.textContent=s);const d=c.querySelector(".mw-flag");o&&d&&(o.className=d.className),a&&a.setAttribute("aria-label","Language: "+i),t.dispatchEvent(new CustomEvent("mw-language-change",{bubbles:!0,detail:{lang:s,name:i}}))})})})}),window.toggleCheckbox=function(e){const t=e.querySelector('input[type="checkbox"]');if(!t)return;const n=t.checked;t.checked=!n,t.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:t.checked,item:e}}))};let o=null;function r(e){const t=e.querySelector(".mw-tabs-nav-item.mw-active, .mw-tabs-nav-item.active");t?(e.style.setProperty("--mw-tabs-marker-x",t.offsetLeft+"px"),e.style.setProperty("--mw-tabs-marker-w",t.offsetWidth),e.style.setProperty("--mw-tabs-marker-y",t.offsetTop+"px"),e.style.setProperty("--mw-tabs-marker-h",t.offsetHeight),e.setAttribute("data-mw-tabs-marker","")):e.removeAttribute("data-mw-tabs-marker")}function c(e){const t=e.getAttribute("data-tab");return t?document.getElementById(t):null}function s(e){const n=t(e);e.setAttribute("aria-selected",String(n)),e.tabIndex=n?0:-1}function l(t,n){t.forEach(t=>{const a=t===n;e(t,a),e(c(t),a),s(t)});const a=n.closest(".mw-tabs-nav");a&&r(a)}function i(e){e&&("DIALOG"===e.tagName?e.showModal():e.classList.add("mw-modal-open"))}function d(e){const t=Array.from(e.querySelectorAll(".mw-kanban-column")),n=e.querySelector(".mw-kanban-composer"),a=e.querySelector(".mw-kanban-card-template"),o=e.dataset.kanbanPrefix||"MW",r=n.querySelector(".mw-kanban-composer-title"),c=n.querySelector(".mw-kanban-composer-text"),s=n.querySelector(".mw-kanban-composer-priority"),l=n.querySelector(".mw-kanban-composer-assignee");let i=null;function d(){t.forEach(function(e,n){const a=e.querySelectorAll(".mw-kanban-card"),o=e.querySelector(".mw-kanban-count");o&&(o.textContent=a.length),e.querySelectorAll("[data-kanban-move]").forEach(function(e){const a=n+parseInt(e.dataset.kanbanMove,10);e.disabled=a<0||a>=t.length})})}function u(e,t){const n=e.querySelector(t);return n?n.textContent.replace(/\s+/g," ").trim():""}function m(e,t){w(),i=t||null,r.value=t?u(t,".mw-kanban-card-title"):"",c.value=t?u(t,".mw-kanban-card-text"):"",s.value=t?function(e){const t=e.querySelector(".mw-card-ribbon");if(!t)return"";const n=Array.from(t.classList).find(function(e){return 0===e.indexOf("mw-card-addon-")});return n?n.replace("mw-card-addon-",""):""}(t):"",l.value=t?function(e){const t=e.querySelector(".mw-avatar-initials");return t?t.textContent.trim():""}(t):"",t?(t.classList.add("mw-kanban-editing"),t.before(n)):e.querySelector(".mw-kanban-column-body").prepend(n),n.classList.add("mw-active"),r.focus()}function w(){n.classList.remove("mw-active"),i&&i.classList.remove("mw-kanban-editing"),i=null}function f(){const t=r.value.trim();if(!t)return void r.focus();const u=i||a.content.firstElementChild.cloneNode(!0);if(u.querySelector(".mw-kanban-card-title").textContent=t,u.querySelector(".mw-kanban-card-text").textContent=c.value.trim(),function(e,t){const n=e.querySelector(".mw-card-ribbon");if(n&&n.remove(),!t||!t.value)return;const a=document.createElement("div");a.className="mw-card-ribbon mw-card-addon-"+t.value,a.textContent=t.textContent,e.prepend(a)}(u,s.selectedOptions[0]),function(e,t){const n=e.querySelector(".mw-kanban-card-actions"),a=n.querySelector(".mw-avatar");if(!t)return void(a&&a.remove());const o=a||document.createElement("div");o.className="mw-avatar mw-avatar-xs mw-avatar-initials",o.textContent=t,a||n.prepend(o)}(u,l.value),!i){const t=function(){const t=Array.from(e.querySelectorAll(".mw-kanban-card-id")).map(function(e){return parseInt(e.textContent.split("-").pop(),10)||0});return o+"-"+(Math.max(0,...t)+1)}();u.classList.add("mw-kanban-card-in"),u.querySelector(".mw-kanban-card-id").textContent=t,u.querySelectorAll("[aria-label]").forEach(function(e){e.setAttribute("aria-label",e.getAttribute("aria-label").replace(/[A-Z]+-\d+/,t))}),n.before(u)}w(),d()}const h=["mw-kanban-card-moved-forward","mw-kanban-card-moved-back"];e.addEventListener("click",function(e){const n=e.target.closest("[data-kanban-move]");if(n){if(function(e,n){const a=e.closest(".mw-kanban-column"),o=t[t.indexOf(a)+n];o&&(o.querySelector(".mw-kanban-column-body").appendChild(e),e.classList.remove.apply(e.classList,h),e.offsetWidth,e.classList.add(n>0?h[0]:h[1]),d())}(n.closest(".mw-kanban-card"),parseInt(n.dataset.kanbanMove,10)),n.disabled){const e=n.parentElement.querySelector("[data-kanban-move]:not(:disabled)");e&&e.focus()}return}const a=e.target.closest(".mw-kanban-edit");if(a){const e=a.closest(".mw-kanban-card");return void m(e.closest(".mw-kanban-column"),e)}const o=e.target.closest(".mw-kanban-delete");if(o){const e=o.closest(".mw-kanban-card");return e===i&&w(),e.remove(),void d()}const r=e.target.closest(".mw-kanban-add");r?m(r.closest(".mw-kanban-column"),null):e.target.closest(".mw-kanban-composer-cancel")&&w()}),n.addEventListener("submit",function(e){e.preventDefault(),f()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&w()}),d()}function u(e){const t=e.querySelector(".mw-calendar-grid"),n=e.querySelector(".mw-calendar-title");if(!t)return;const a="week"===e.dataset.calendar,o=function(e){if(!e)return{};try{return JSON.parse(e)}catch(e){return{}}}(e.dataset.calendarMarkers),r=e.dataset.calendarLocale||document.documentElement.lang||void 0,c=new Date;c.setHours(0,0,0,0);let s=e.dataset.calendarDate?new Date(e.dataset.calendarDate+"T00:00:00"):new Date(c),l=e.dataset.calendarSelected||"";function i(e){const t=new Date(e);return t.setDate(t.getDate()-(t.getDay()+6)%7),t}function d(e){return e.getFullYear()+"-"+String(e.getMonth()+1).padStart(2,"0")+"-"+String(e.getDate()).padStart(2,"0")}function u(){if(!a)return s.toLocaleDateString(r,{month:"long",year:"numeric"});const e=i(s),t=new Date(e);t.setDate(t.getDate()+6);const n=e.toLocaleDateString(r,{day:"numeric",month:e.getMonth()===t.getMonth()?void 0:"short"}),o=t.toLocaleDateString(r,{day:"numeric",month:"short",year:"numeric"});return"Week "+function(e){const t=i(e);t.setDate(t.getDate()+3);const n=i(new Date(t.getFullYear(),0,4));return n.setDate(n.getDate()+3),1+Math.round((t-n)/6048e5)}(e)+" · "+n+" - "+o}function m(e){const t=e.getDay();return 0===t||6===t}function w(e,t){const n=d(e),s=document.createElement("button");s.type="button",s.className="mw-calendar-day",s.tabIndex=-1,s.dataset.calendarDay=n,s.setAttribute("aria-pressed",n===l?"true":"false"),s.setAttribute("aria-label",e.toLocaleDateString(r,{weekday:"long",day:"numeric",month:"long",year:"numeric"})),m(e)&&s.classList.add("mw-calendar-weekend"),a||e.getMonth()===t||s.classList.add("mw-calendar-adjacent"),n===d(c)&&(s.classList.add("mw-calendar-today"),s.setAttribute("aria-current","date")),n===l&&s.classList.add("mw-selected");const i=document.createElement("span");i.className="mw-calendar-date",i.textContent=e.getDate(),s.appendChild(i);const u=[].concat(o[n]||[]);if(u.length){const e=document.createElement("span");e.className="mw-calendar-dots",u.forEach(function(t){const n=document.createElement("span");n.className=t?"mw-calendar-dot mw-calendar-dot-"+t:"mw-calendar-dot",e.appendChild(n)}),s.appendChild(e)}return s}function f(){const e=s.getMonth(),o=a?7:42,c=i(a?s:new Date(s.getFullYear(),e,1));t.innerHTML="",function(){const e=i(new Date);for(let n=0;n<7;n++){const n=document.createElement("div");n.className="mw-calendar-weekday",m(e)&&n.classList.add("mw-calendar-weekend"),n.setAttribute("aria-hidden","true"),n.textContent=e.toLocaleDateString(r,{weekday:"short"}),t.appendChild(n),e.setDate(e.getDate()+1)}}();for(let n=0;n<o;n++)t.appendChild(w(c,e)),c.setDate(c.getDate()+1);n&&(n.textContent=u()),function(){const e=t.querySelector(".mw-selected")||t.querySelector(".mw-calendar-today")||t.querySelector(".mw-calendar-day:not(.mw-calendar-adjacent)")||t.querySelector(".mw-calendar-day");e&&(e.tabIndex=0)}()}e.addEventListener("click",function(n){const o=n.target.closest("[data-calendar-nav]");if(o)return r=parseInt(o.dataset.calendarNav,10),a?s.setDate(s.getDate()+7*r):s=new Date(s.getFullYear(),s.getMonth()+r,1),void f();var r;const c=n.target.closest(".mw-calendar-day");var i;c&&!c.disabled&&(i=c.dataset.calendarDay,l=i===l?"":i,t.querySelectorAll(".mw-calendar-day").forEach(function(e){const t=e.dataset.calendarDay===l;e.classList.toggle("mw-selected",t),e.setAttribute("aria-pressed",t?"true":"false")}),e.dispatchEvent(new CustomEvent("mw-calendar-select",{bubbles:!0,detail:{date:l}})))}),t.addEventListener("keydown",function(e){const n={ArrowLeft:-1,ArrowRight:1,ArrowUp:-7,ArrowDown:7}[e.key];if(!n)return;const a=e.target.closest(".mw-calendar-day");if(!a)return;e.preventDefault();const o=new Date(a.dataset.calendarDay+"T00:00:00");o.setDate(o.getDate()+n),function(e){const n=d(e);let a=t.querySelector('[data-calendar-day="'+n+'"]');a||(s=new Date(e),f(),a=t.querySelector('[data-calendar-day="'+n+'"]')),a&&(t.querySelectorAll(".mw-calendar-day").forEach(function(e){e.tabIndex=-1}),a.tabIndex=0,a.focus())}(o)}),f()}["wheel","touchstart"].forEach(e=>{window.addEventListener(e,()=>o=null,{passive:!0})}),window.mwOpenModal=e=>i(document.getElementById(e)),window.mwCloseModal=e=>{var t;(t=document.getElementById(e))&&("DIALOG"===t.tagName?t.close():t.classList.remove("mw-modal-open"))}}();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "maverick-wave",
3
- "version": "5.2.0",
3
+ "version": "5.4.0",
4
4
  "config": {
5
- "version_short": "5.2"
5
+ "version_short": "5.4"
6
6
  },
7
7
  "description": "A lightweight, modern CSS framework for building responsive websites with elegance and speed.",
8
8
  "main": "src/js/main.js",
package/scripts/verify.js CHANGED
@@ -8,6 +8,7 @@
8
8
  * 3. every mw-* class in the markup exists in the built CSS
9
9
  * 4. the committed root release files exist and are not empty
10
10
  * 5. the CDN version pinned in the docs matches package.json
11
+ * 6. no `animation:` shorthand in a file that uses a scroll timeline
11
12
  *
12
13
  * Sources are scanned rather than hard-coded so a new partial is covered
13
14
  * automatically. Exits 1 on any error; warnings never fail the build.
@@ -26,7 +27,7 @@ const JS = path.join(ROOT, 'src', 'js', 'main.js');
26
27
  // or example file is covered without touching this list.
27
28
  const DOCS = [
28
29
  path.join(ROOT, '.claude', 'commands', 'mw.md'),
29
- ...markdownFiles(path.join(ROOT, '.claude', 'skills')),
30
+ ...filesWithExt(path.join(ROOT, '.claude', 'skills'), '.md'),
30
31
  ];
31
32
 
32
33
  // Tokens read by JavaScript or reserved for consumers, so "unused in CSS" is fine.
@@ -44,12 +45,12 @@ const CLASS_ALLOWLIST = new Set([]);
44
45
  const read = (p) => (fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : null);
45
46
  const all = (str, re) => [...str.matchAll(re)].map((m) => m[1]);
46
47
 
47
- function markdownFiles(dir) {
48
+ function filesWithExt(dir, ext) {
48
49
  if (!fs.existsSync(dir)) return [];
49
50
  return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
50
51
  const full = path.join(dir, entry.name);
51
- if (entry.isDirectory()) return markdownFiles(full);
52
- return entry.name.endsWith('.md') ? [full] : [];
52
+ if (entry.isDirectory()) return filesWithExt(full, ext);
53
+ return entry.name.endsWith(ext) ? [full] : [];
53
54
  });
54
55
  }
55
56
 
@@ -161,6 +162,24 @@ for (const p of [path.join(ROOT, 'README.md'), ...DOCS]) {
161
162
  }
162
163
  }
163
164
 
165
+ // --- 6: scroll timelines and the animation shorthand ------------------------
166
+ // A consumer bundler (esbuild among them) folds the longhands plus
167
+ // animation-timeline into one `animation: ... view()`, which no browser
168
+ // accepts - the declaration is dropped and the element never animates. It only
169
+ // shows up in the consuming project, never in our own build, so the source is
170
+ // what has to be clean: no shorthand in a file that uses a timeline.
171
+ // 5.0.0 and 5.2.0 both shipped empty progress bars this way.
172
+
173
+ for (const f of filesWithExt(path.join(ROOT, 'src', 'scss'), '.scss')) {
174
+ const scss = read(f);
175
+ if (!scss || !scss.includes('animation-timeline')) continue;
176
+ for (const m of scss.match(/^\s*animation:.*/gm) || []) {
177
+ errors.push(
178
+ `${path.relative(ROOT, f)}: \`${m.trim()}\` - a file with a scroll timeline must use animation-* longhands, a bundler folds the shorthand and kills the timeline`
179
+ );
180
+ }
181
+ }
182
+
164
183
  // Informational: framework classes the showcase never demonstrates
165
184
  const undocumented = [...classesInCss].filter(
166
185
  (c) => !classesInMarkup.has(c) && !classesInJs.has(c)
package/src/js/main.js CHANGED
@@ -531,7 +531,65 @@
531
531
  }
532
532
 
533
533
  // ===== Smooth Scrolling =====
534
+ // Where an anchor jump lands: scroll-padding-top, read per run because the
535
+ // ribbon grows on small screens and can be dismissed
536
+ function anchorOffset() {
537
+ const padding = parseFloat(
538
+ getComputedStyle(document.documentElement).scrollPaddingTop
539
+ );
540
+ return Number.isNaN(padding) ? 0 : padding;
541
+ }
542
+
543
+ // Anything the user does with the wheel or a finger outranks a running glide
544
+ let glide = null;
545
+ ['wheel', 'touchstart'].forEach((type) => {
546
+ window.addEventListener(type, () => (glide = null), { passive: true });
547
+ });
548
+
534
549
  function initSmoothScrolling() {
550
+ // A sticky target reports where it is pinned, not where it sits in the flow,
551
+ // and pinned is the top of the screen - so the browser's own jump moved the
552
+ // page by the header offset and stopped there. offsetTop follows it to the
553
+ // pin as well, so the position is taken with the pinning switched off. No
554
+ // paint happens in between, the style is back before the frame ends.
555
+ function documentTop(el) {
556
+ const inline = el.style.position;
557
+ const pinned = getComputedStyle(el).position === 'sticky';
558
+ if (pinned) el.style.position = 'static';
559
+ const y = el.getBoundingClientRect().top + window.scrollY;
560
+ if (pinned) el.style.position = inline;
561
+ return y;
562
+ }
563
+
564
+ function glideTo(targetY) {
565
+ const startY = window.scrollY;
566
+ const distance = targetY - startY;
567
+ if (!distance) return;
568
+
569
+ // Scaled, or a jump to the next section takes as long as one across the
570
+ // whole page; capped, or that one crawls
571
+ const duration = Math.min(1400, 420 + Math.abs(distance) * 0.35);
572
+ const start = performance.now();
573
+ const token = {};
574
+ glide = token;
575
+
576
+ function step(now) {
577
+ if (glide !== token) return;
578
+ const t = Math.min(1, (now - start) / duration);
579
+ const eased = t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
580
+ // 'instant', or the smooth scroll-behavior in the stylesheet animates
581
+ // every single step of this animation on top of it
582
+ window.scrollTo({
583
+ top: startY + distance * eased,
584
+ behavior: 'instant',
585
+ });
586
+ if (t < 1) requestAnimationFrame(step);
587
+ else glide = null;
588
+ }
589
+
590
+ requestAnimationFrame(step);
591
+ }
592
+
535
593
  document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
536
594
  anchor.addEventListener('click', function (e) {
537
595
  const targetId = this.getAttribute('href');
@@ -546,6 +604,28 @@
546
604
  menuBtn.classList.remove('open');
547
605
  nav.classList.remove('open');
548
606
  }
607
+
608
+ e.preventDefault();
609
+ const target = Math.max(0, documentTop(targetElement) - anchorOffset());
610
+
611
+ // The browser moves focus on an anchor jump of its own; preventDefault
612
+ // takes that away, and a skip link that only scrolls leaves the next Tab
613
+ // back where it started. -1 keeps the target out of the tab order.
614
+ if (!targetElement.hasAttribute('tabindex')) {
615
+ targetElement.setAttribute('tabindex', '-1');
616
+ }
617
+ targetElement.focus({ preventScroll: true });
618
+
619
+ if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
620
+ window.scrollTo({ top: target, behavior: 'instant' });
621
+ } else {
622
+ glideTo(target);
623
+ }
624
+
625
+ // replaceState and not the default hash change: the glide is the
626
+ // navigation, and a history entry per section link buries the page the
627
+ // user arrived from
628
+ history.replaceState(null, '', targetId);
549
629
  });
550
630
  });
551
631
  }
@@ -557,21 +637,12 @@
557
637
 
558
638
  if (sections.length === 0 || navLinks.length === 0) return;
559
639
 
560
- // Measured against scroll-padding-top, the same value an anchor jump lands on,
561
- // and read per run - the ribbon grows on small screens and can be dismissed
562
- function scrollOffset() {
563
- const padding = parseFloat(
564
- getComputedStyle(document.documentElement).scrollPaddingTop
565
- );
566
- // +2 absorbs subpixel rounding between the jump and the scroll position.
567
- return (Number.isNaN(padding) ? 0 : padding) + 2;
568
- }
569
-
570
640
  window.addEventListener(
571
641
  'scroll',
572
642
  debounce(function () {
573
643
  let current = '';
574
- const offset = scrollOffset();
644
+ // +2 absorbs subpixel rounding between the jump and the scroll position
645
+ const offset = anchorOffset() + 2;
575
646
 
576
647
  sections.forEach((section) => {
577
648
  const sectionTop = section.offsetTop - offset;
@@ -1,3 +1,5 @@
1
+ <div class="mw-parallax-media"></div>
2
+
1
3
  <div class="mw-hero">
2
4
  <div class="mw-home mw-home-content-fade">
3
5
  <div class="mw-home-text">
@@ -0,0 +1,114 @@
1
+ <h3 class="mw-section-subtitle">Parallax</h3>
2
+ <p class="mw-text-muted mw-text-measure mw-mb-6">
3
+ Two ways to play a picture against the scroll, both on the browser's scroll
4
+ timeline - no listener, and no
5
+ <code>background-attachment: fixed</code>, which iOS ignores. The image lives
6
+ in its own <code>mw-parallax-media</code> layer, as an
7
+ <code>&lt;img&gt;</code> or as a div with a background image. Where scroll
8
+ timelines are missing, or with <code>prefers-reduced-motion</code>, the
9
+ picture stands still and nothing else changes.
10
+ </p>
11
+
12
+ <h4 class="mw-text-medium mw-mb-2">
13
+ Drift - <code>mw-parallax</code>, the picture moves slower than the page
14
+ </h4>
15
+ <p class="mw-text-muted mw-text-measure mw-mb-6">
16
+ How far it travels is <code>--mw-parallax-depth</code> (<code>10vh</code> by
17
+ default); the layer overhangs the block by exactly that much, so no edge is
18
+ ever uncovered. <code>mw-parallax-dimmed</code> turns the picture down and the
19
+ text light.
20
+ </p>
21
+
22
+ <div class="mw-grid-1 mw-gap-6 mw-mb-6">
23
+ <div class="mw-parallax mw-parallax-dimmed">
24
+ <img
25
+ class="mw-parallax-media"
26
+ src="images/slider-field.svg"
27
+ alt=""
28
+ loading="lazy"
29
+ />
30
+ <div class="mw-parallax-content mw-text-center">
31
+ <h3>Scroll past me</h3>
32
+ <p class="mw-mb-0">The field moves slower than the page does.</p>
33
+ </div>
34
+ </div>
35
+
36
+ <div class="mw-parallax" style="--mw-parallax-depth: 20vh">
37
+ <img
38
+ class="mw-parallax-media"
39
+ src="images/gallery-mountain.svg"
40
+ alt="Mountain range"
41
+ loading="lazy"
42
+ />
43
+ </div>
44
+ </div>
45
+
46
+ <h4 class="mw-text-medium mw-mb-2">
47
+ Reveal - <code>mw-parallax-sticky</code>, the picture stays and the page rides
48
+ over it
49
+ </h4>
50
+ <p class="mw-text-muted mw-text-measure mw-mb-6">
51
+ The home section of this page does it: the block pins itself to the top of the
52
+ screen and everything after it slides up over the picture. It goes on whatever
53
+ element the page content is a <strong>sibling</strong> of - the section around
54
+ a hero, not the hero itself - because that is what sticky and the sibling
55
+ selector need. Everything after it gets the page background and a layer above,
56
+ or the pinned picture shows through. Pair it with
57
+ <code>mw-header-reveal</code> on the header and the page opens on the picture
58
+ alone: the bar stays away for the first 130px of scroll and has ridden in by
59
+ 420px.
60
+ </p>
61
+ <p class="mw-text-muted mw-text-measure mw-mb-6">
62
+ Add <code>mw-parallax-rise</code> next to it and the picture lifts by
63
+ <code>12vh</code> while the text stays where it is - a pinned block does not
64
+ travel through the viewport, so that layer runs on the document's own scroll
65
+ instead. <code>--mw-parallax-depth</code> is the dial, here as everywhere.
66
+ </p>
67
+
68
+ <h4 class="mw-text-medium mw-mb-2">
69
+ Pattern - <code>mw-parallax-pattern</code>, a second layer that makes the
70
+ movement visible
71
+ </h4>
72
+ <p class="mw-text-muted mw-text-measure mw-mb-6">
73
+ The travel is vertical, so only an edge across it - a rule, a grid, a hatch -
74
+ ever shows it. A gradient has none and slides without looking like it moves.
75
+ Add a second <code>mw-parallax-media</code> carrying
76
+ <code>mw-parallax-pattern</code>: it travels a third of the distance, and it
77
+ is the difference between the two layers that reads as depth. In a hero the
78
+ pattern comes from <code>$mw-hero-pattern</code>, the way the picture comes
79
+ from <code>$mw-hero-image</code>; anywhere else set
80
+ <code>--mw-parallax-pattern-image</code> on it.
81
+ </p>
82
+
83
+ <div class="mw-parallax mw-parallax-dimmed mw-mb-6">
84
+ <div class="mw-parallax-media parallax-demo-ground"></div>
85
+ <div class="mw-parallax-media mw-parallax-pattern parallax-demo-lines"></div>
86
+ <div class="mw-parallax-content mw-text-center">
87
+ <h3>The grid drifts, the gradient holds</h3>
88
+ <p class="mw-mb-0">
89
+ Both layers move. Only the one with edges tells you so.
90
+ </p>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="mw-code-block">
95
+ <div class="mw-code-block-header">
96
+ <span class="mw-code-block-filename">index.html</span>
97
+ <span class="mw-code-block-language">HTML</span>
98
+ </div>
99
+ <div class="mw-code-container">
100
+ <pre><code>&lt;header class="mw-header mw-header-reveal"&gt;...&lt;/header&gt;
101
+
102
+ &lt;main class="mw-main"&gt;
103
+ &lt;section class="mw-section mw-parallax-sticky mw-parallax-rise"&gt;
104
+ &lt;div class="mw-container mw-parallax"&gt;
105
+ &lt;div class="mw-parallax-media"&gt;&lt;/div&gt;
106
+ &lt;div class="mw-parallax-media mw-parallax-pattern"&gt;&lt;/div&gt;
107
+ &lt;div class="mw-hero"&gt;...&lt;/div&gt;
108
+ &lt;/div&gt;
109
+ &lt;/section&gt;
110
+
111
+ &lt;section class="mw-section"&gt;...&lt;/section&gt;
112
+ &lt;/main&gt;</code></pre>
113
+ </div>
114
+ </div>
@@ -4,6 +4,10 @@ $mw-theme-mode: 'switchable' !default; // 'dark', 'light', or 'switchable'
4
4
 
5
5
  $mw-hero-image: url('https://images.unsplash.com/photo-1591638462868-19cfad9c49d1?q=80&w=1300&auto=format&fit=crop') !default;
6
6
 
7
+ // A second, flatter layer over the image - see mw-parallax-pattern. Fine lines
8
+ // or a grid, because a gradient has no edge across the travel to show it moving.
9
+ $mw-hero-pattern: none !default;
10
+
7
11
  // Fixed to the light end rather than theme-bound: the photo does not change with
8
12
  // the theme, so its ink must not either. Use --mw-light-text-color on a bright one.
9
13
  $mw-hero-text-color: var(--mw-dark-text-color) !default;
@@ -85,6 +85,7 @@
85
85
 
86
86
  // hero background image and the ink that sits on it
87
87
  --mw-hero-background: #{$mw-hero-image};
88
+ --mw-hero-pattern: #{$mw-hero-pattern};
88
89
  --mw-hero-text-color: #{$mw-hero-text-color};
89
90
 
90
91
  // header height
@@ -90,7 +90,11 @@
90
90
  }
91
91
 
92
92
  @media (prefers-reduced-motion: no-preference) {
93
- animation: mw-progress-fill linear both;
93
+ // Longhands and never the shorthand, which esbuild collapses into one
94
+ // `animation:` that cannot carry a timeline.
95
+ animation-name: mw-progress-fill;
96
+ animation-timing-function: linear;
97
+ animation-fill-mode: both;
94
98
  animation-timeline: view();
95
99
  // Starts once the bar is properly on screen and finishes well
96
100
  // before it reaches the middle, so it is full when it is read.
@@ -0,0 +1,100 @@
1
+ @layer mw.layout {
2
+ // For a page that opens on a full-bleed picture and wants nothing on top of
3
+ // it: the bar starts above the screen and rides in over the first stretch of
4
+ // scroll. Inside the @supports, so a browser without scroll timelines gets a
5
+ // normal header rather than none at all.
6
+ //
7
+ // Its own file, and not next to .mw-header: that one uses the `animation`
8
+ // shorthand, which a consumer bundler folds together with a timeline into a
9
+ // declaration no browser accepts.
10
+ @supports (animation-timeline: scroll()) {
11
+ @media (prefers-reduced-motion: no-preference) {
12
+ .mw-header-reveal {
13
+ animation-name: mw-header-reveal;
14
+ animation-timing-function: var(--mw-ease-out);
15
+ animation-fill-mode: both;
16
+ animation-timeline: scroll(root);
17
+ animation-range: 0 420px;
18
+ }
19
+
20
+ // The ribbon is glued under the bar, so it has to leave and arrive with
21
+ // it - left behind it would hang alone at the top of an otherwise clean
22
+ // hero. No class of its own: a ribbon on a page with a revealing header
23
+ // has no other sensible behaviour.
24
+ body:has(.mw-header-reveal)
25
+ .mw-announcement:not(.mw-announcement-static) {
26
+ animation-name: mw-announcement-reveal;
27
+ animation-timing-function: var(--mw-ease-out);
28
+ animation-fill-mode: both;
29
+ animation-timeline: scroll(root);
30
+ animation-range: 0 420px;
31
+ }
32
+ }
33
+ }
34
+
35
+ // Both cover the height of the pair, or the shorter traveller arrives first
36
+ // and the two come in as two things instead of one block. Without a ribbon
37
+ // that height is just the bar's.
38
+ .mw-header-reveal {
39
+ --mw-header-reveal-offset: var(--mw-header-height);
40
+ }
41
+
42
+ body:has(.mw-announcement:not(.mw-announcement-static)) .mw-header-reveal {
43
+ --mw-header-reveal-offset: calc(
44
+ var(--mw-header-height) + var(--mw-announcement-height)
45
+ );
46
+ }
47
+
48
+ // A keyboard reaches the chrome long before the first scroll does, and a focus
49
+ // ring on something that is off screen is WCAG 2.4.11 - so focus brings it
50
+ // back, either half of the pair pulling in the other. `!important` is the one
51
+ // author declaration that outranks a running animation; dropping
52
+ // `animation-name` instead leaves the element stuck on its last value, because
53
+ // a restarted scroll timeline only catches up on the next scroll.
54
+ body:has(.mw-header-reveal:focus-within, .mw-announcement:focus-within) {
55
+ .mw-header-reveal {
56
+ top: 0 !important;
57
+ opacity: 1 !important;
58
+ }
59
+
60
+ .mw-announcement:not(.mw-announcement-static) {
61
+ transform: none !important;
62
+ opacity: 1 !important;
63
+ }
64
+ }
65
+
66
+ // `top` and not a transform: the off-canvas drawer inside the bar is
67
+ // position: fixed, and a transform on the header would make it the drawer's
68
+ // containing block - at every value, the resting one included.
69
+ // The wait sits in the keyframes and not in the range, because a range that
70
+ // starts past 0 leaves the bar in its resting state below that point - so the
71
+ // header would be visible for exactly the stretch it should stay away for.
72
+ @keyframes mw-header-reveal {
73
+ 0%,
74
+ 30% {
75
+ top: calc(-1 * var(--mw-header-reveal-offset));
76
+ opacity: 0;
77
+ }
78
+
79
+ 100% {
80
+ top: 0;
81
+ opacity: 1;
82
+ }
83
+ }
84
+
85
+ // The ribbon holds nothing fixed, so it can use the cheaper transform
86
+ @keyframes mw-announcement-reveal {
87
+ 0%,
88
+ 30% {
89
+ transform: translateY(
90
+ calc(-1 * (var(--mw-header-height) + var(--mw-announcement-height)))
91
+ );
92
+ opacity: 0;
93
+ }
94
+
95
+ 100% {
96
+ transform: translateY(0);
97
+ opacity: 1;
98
+ }
99
+ }
100
+ }
@@ -1,7 +1,11 @@
1
1
  @forward 'footer';
2
2
  @forward 'grid';
3
3
  @forward 'header';
4
+ @forward 'header-reveal';
4
5
  @forward 'home';
5
6
  @forward 'main';
6
7
  @forward 'page-header';
7
8
  @forward 'section';
9
+
10
+ // Last on purpose: mw-parallax-sticky has to beat the `position: relative`
11
+ @forward 'parallax';
@@ -41,12 +41,27 @@
41
41
  transition: var(--mw-transition);
42
42
  }
43
43
 
44
- // ...so the content has to sit above it
45
- > * {
44
+ // ...so the content has to sit above it - except the parallax layer,
45
+ // which is the one thing that belongs underneath
46
+ > *:not(.mw-parallax-media) {
46
47
  position: relative;
47
48
  z-index: z-index('card');
48
49
  }
49
50
 
51
+ // Add `mw-parallax` here and a `.mw-parallax-media` child and the picture
52
+ // becomes its own layer, free to drift or to stay pinned. It reads the
53
+ // same token, so the image is still configured in one place - and a
54
+ // second media element carrying `mw-parallax-pattern` takes the other.
55
+ &:has(> .mw-parallax-media) {
56
+ background-image: none;
57
+
58
+ --mw-parallax-pattern-image: var(--mw-hero-pattern);
59
+
60
+ > .mw-parallax-media:not(.mw-parallax-pattern) {
61
+ background-image: var(--mw-hero-background);
62
+ }
63
+ }
64
+
50
65
  // The same shadow the scroll cue already carries: the light theme lifts
51
66
  // the photo to brightness(1.1) and pale ink alone stops holding its edge
52
67
  h1,