maverick-wave 4.28.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/.claude/settings.local.json +29 -1
  2. package/.claude/skills/mw-maverick-wave/SKILL.md +39 -24
  3. package/.claude/skills/mw-maverick-wave/examples/angular-services.md +16 -4
  4. package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +13 -4
  5. package/.claude/skills/mw-maverick-wave/references/components.md +42 -5
  6. package/.claude/skills/mw-maverick-wave/references/forms.md +14 -2
  7. package/.claude/skills/mw-maverick-wave/references/javascript.md +17 -4
  8. package/.claude/skills/mw-maverick-wave/references/layout.md +53 -19
  9. package/.claude/skills/mw-maverick-wave/references/theming.md +38 -1
  10. package/.impeccable/config.local.json +5 -0
  11. package/.impeccable/hook.cache.json +75 -0
  12. package/CHANGELOG.md +17 -0
  13. package/CLAUDE.md +5 -5
  14. package/README.md +48 -4
  15. package/index.html +19 -38
  16. package/maverick-wave.min.css +14 -12
  17. package/maverick-wave.min.js +1 -1
  18. package/package.json +2 -2
  19. package/scripts/verify.js +27 -2
  20. package/src/js/main.js +223 -83
  21. package/src/partials/accordions-container.html +6 -10
  22. package/src/partials/alerts-container.html +6 -6
  23. package/src/partials/announcement-container.html +5 -5
  24. package/src/partials/avatars-container.html +85 -17
  25. package/src/partials/badges-container.html +6 -6
  26. package/src/partials/blog-posts-container.html +11 -12
  27. package/src/partials/buttons-container.html +3 -3
  28. package/src/partials/cards-container.html +26 -9
  29. package/src/partials/code-container.html +5 -5
  30. package/src/partials/content-slider-container.html +5 -4
  31. package/src/partials/divider-container.html +7 -7
  32. package/src/partials/dropdown-container.html +2 -2
  33. package/src/partials/empty-state-container.html +5 -5
  34. package/src/partials/footer-container.html +21 -18
  35. package/src/partials/form-elements-container.html +14 -14
  36. package/src/partials/gallery-container.html +16 -8
  37. package/src/partials/get-started-container.html +4 -8
  38. package/src/partials/header-container.html +18 -7
  39. package/src/partials/home-container.html +10 -20
  40. package/src/partials/input-group-container.html +11 -2
  41. package/src/partials/kbd-container.html +1 -1
  42. package/src/partials/login-container.html +5 -1
  43. package/src/partials/media-container.html +2 -2
  44. package/src/partials/modals-container.html +22 -32
  45. package/src/partials/pricing-container.html +9 -9
  46. package/src/partials/skeleton-container.html +6 -6
  47. package/src/partials/stepper-container.html +2 -2
  48. package/src/partials/tables-container.html +12 -12
  49. package/src/partials/tabs-container.html +17 -27
  50. package/src/partials/tags-container.html +23 -17
  51. package/src/partials/techstack-bucket-container.html +13 -0
  52. package/src/partials/tiles-container.html +26 -9
  53. package/src/partials/typography-container.html +7 -6
  54. package/src/partials/utilities-container.html +35 -15
  55. package/src/scss/_layers.scss +10 -0
  56. package/src/scss/abstracts/_index.scss +6 -0
  57. package/src/scss/abstracts/_mixins.scss +61 -153
  58. package/src/scss/abstracts/_variables.scss +123 -319
  59. package/src/scss/base/_base.scss +170 -190
  60. package/src/scss/base/_reset.scss +106 -104
  61. package/src/scss/base/_typography.scss +153 -151
  62. package/src/scss/components/_accordions.scss +97 -97
  63. package/src/scss/components/_alerts.scss +71 -70
  64. package/src/scss/components/_announcement.scss +71 -70
  65. package/src/scss/components/_avatars.scss +130 -142
  66. package/src/scss/components/_badge.scss +131 -132
  67. package/src/scss/components/_blog-post.scss +223 -220
  68. package/src/scss/components/_breadcrumbs.scss +93 -92
  69. package/src/scss/components/_button-bar.scss +102 -110
  70. package/src/scss/components/_buttons.scss +319 -324
  71. package/src/scss/components/_calendar.scss +251 -252
  72. package/src/scss/components/_cards.scss +359 -386
  73. package/src/scss/components/_code.scss +190 -194
  74. package/src/scss/components/_coming-soon.scss +77 -75
  75. package/src/scss/components/_content-slider.scss +90 -89
  76. package/src/scss/components/_divider.scss +55 -53
  77. package/src/scss/components/_dropdown.scss +179 -185
  78. package/src/scss/components/_empty-state.scss +57 -57
  79. package/src/scss/components/_flag.scss +294 -278
  80. package/src/scss/components/_gallery.scss +131 -133
  81. package/src/scss/components/_info.scss +151 -167
  82. package/src/scss/components/_kanban.scss +332 -341
  83. package/src/scss/components/_kbd.scss +40 -38
  84. package/src/scss/components/_lang-switch.scss +89 -97
  85. package/src/scss/components/_links.scss +21 -28
  86. package/src/scss/components/_lists.scss +510 -514
  87. package/src/scss/components/_localhost-indicator.scss +26 -24
  88. package/src/scss/components/_media.scss +22 -20
  89. package/src/scss/components/_meta-info.scss +35 -33
  90. package/src/scss/components/_modals.scss +277 -186
  91. package/src/scss/components/_pagination.scss +81 -87
  92. package/src/scss/components/_panels.scss +99 -97
  93. package/src/scss/components/_pricing.scss +183 -241
  94. package/src/scss/components/_progress.scss +122 -89
  95. package/src/scss/components/_prose.scss +35 -33
  96. package/src/scss/components/_ratings.scss +40 -38
  97. package/src/scss/components/_segmented.scss +82 -84
  98. package/src/scss/components/_skeleton.scss +66 -72
  99. package/src/scss/components/_spinners.scss +155 -159
  100. package/src/scss/components/_stepper.scss +116 -116
  101. package/src/scss/components/_tables.scss +155 -148
  102. package/src/scss/components/_tabs.scss +232 -141
  103. package/src/scss/components/_tags.scss +109 -107
  104. package/src/scss/components/_techstack-bucket.scss +123 -122
  105. package/src/scss/components/_testimonial.scss +72 -70
  106. package/src/scss/components/_theme-toggle.scss +53 -51
  107. package/src/scss/components/_tiles.scss +174 -174
  108. package/src/scss/components/_timelines.scss +282 -280
  109. package/src/scss/components/_toasts.scss +66 -72
  110. package/src/scss/form-elements/_checkbox.scss +117 -132
  111. package/src/scss/form-elements/_form.scss +149 -115
  112. package/src/scss/form-elements/_input-group.scss +99 -103
  113. package/src/scss/form-elements/_input.scss +74 -74
  114. package/src/scss/form-elements/_login.scss +48 -48
  115. package/src/scss/form-elements/_prefilled.scss +53 -51
  116. package/src/scss/form-elements/_radio.scss +95 -107
  117. package/src/scss/form-elements/_select.scss +42 -42
  118. package/src/scss/form-elements/_slider.scss +117 -132
  119. package/src/scss/form-elements/_textarea.scss +68 -54
  120. package/src/scss/form-elements/_toggle.scss +127 -140
  121. package/src/scss/layout/_footer.scss +172 -171
  122. package/src/scss/layout/_grid.scss +268 -302
  123. package/src/scss/layout/_header.scss +426 -427
  124. package/src/scss/layout/_home.scss +28 -27
  125. package/src/scss/layout/_main.scss +275 -238
  126. package/src/scss/layout/_page-header.scss +38 -36
  127. package/src/scss/layout/_section.scss +150 -124
  128. package/src/scss/main.scss +1 -1
  129. package/src/scss/utilities/_accessibility.scss +46 -45
  130. package/src/scss/utilities/_aspect.scss +22 -20
  131. package/src/scss/utilities/_corner.scss +23 -5
  132. package/src/scss/utilities/_display.scss +76 -70
  133. package/src/scss/utilities/_elevation.scss +13 -11
  134. package/src/scss/utilities/_flex.scss +83 -85
  135. package/src/scss/utilities/_reveal.scss +40 -63
  136. package/src/scss/utilities/_spacing.scss +63 -64
  137. package/src/scss/utilities/_text.scss +139 -141
  138. package/src/scss/utilities/_touch-targets.scss +130 -147
@@ -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(){document.querySelectorAll(".color-swatch").forEach(e=>{const t=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 c="#"+t(a[1])+t(a[2])+t(a[3]),o=void 0===a[4]?1:parseFloat(a[4]);return(o<1?`${c} / ${o}`:c).toUpperCase()}(window.getComputedStyle(e).backgroundColor),n=e.parentElement.querySelector(".mw-text-muted");n&&(n.textContent=t)})}function a(e){const t=Array.from(e.querySelectorAll(".mw-kanban-column")),n=e.querySelector(".mw-kanban-composer"),a=e.querySelector(".mw-kanban-card-template"),c=e.dataset.kanbanPrefix||"MW",o=n.querySelector(".mw-kanban-composer-title"),r=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"),c=e.querySelector(".mw-kanban-count");c&&(c.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){f(),i=t||null,o.value=t?u(t,".mw-kanban-card-title"):"",r.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"),o.focus()}function f(){n.classList.remove("mw-active"),i&&i.classList.remove("mw-kanban-editing"),i=null}function w(){const t=o.value.trim();if(!t)return void o.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=r.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 c=a||document.createElement("div");c.className="mw-avatar mw-avatar-xs mw-avatar-initials",c.textContent=t,a||n.prepend(c)}(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 c+"-"+(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)}f(),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"),c=t[t.indexOf(a)+n];c&&(c.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 c=e.target.closest(".mw-kanban-delete");if(c){const e=c.closest(".mw-kanban-card");return e===i&&f(),e.remove(),void d()}const o=e.target.closest(".mw-kanban-add");o?m(o.closest(".mw-kanban-column"),null):e.target.closest(".mw-kanban-composer-cancel")&&f()}),n.addEventListener("submit",function(e){e.preventDefault(),w()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&f()}),d()}function c(e){const t=e.querySelector(".mw-calendar-grid"),n=e.querySelector(".mw-calendar-title");if(!t)return;const a="week"===e.dataset.calendar,c=function(e){if(!e)return{};try{return JSON.parse(e)}catch(e){return{}}}(e.dataset.calendarMarkers),o=e.dataset.calendarLocale||document.documentElement.lang||void 0,r=new Date;r.setHours(0,0,0,0);let s=e.dataset.calendarDate?new Date(e.dataset.calendarDate+"T00:00:00"):new Date(r),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(o,{month:"long",year:"numeric"});const e=i(s),t=new Date(e);t.setDate(t.getDate()+6);const n=e.toLocaleDateString(o,{day:"numeric",month:e.getMonth()===t.getMonth()?void 0:"short"}),c=t.toLocaleDateString(o,{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+" - "+c}function m(e){const t=e.getDay();return 0===t||6===t}function f(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(o,{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(r)&&(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(c[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 w(){const e=s.getMonth(),c=a?7:42,r=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(o,{weekday:"short"}),t.appendChild(n),e.setDate(e.getDate()+1)}}();for(let n=0;n<c;n++)t.appendChild(f(r,e)),r.setDate(r.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 c=n.target.closest("[data-calendar-nav]");if(c)return o=parseInt(c.dataset.calendarNav,10),a?s.setDate(s.getDate()+7*o):s=new Date(s.getFullYear(),s.getMonth()+o,1),void w();var o;const r=n.target.closest(".mw-calendar-day");var i;r&&!r.disabled&&(i=r.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 c=new Date(a.dataset.calendarDay+"T00:00:00");c.setDate(c.getDate()+n),function(e){const n=d(e);let a=t.querySelector('[data-calendar-day="'+n+'"]');a||(s=new Date(e),w(),a=t.querySelector('[data-calendar-day="'+n+'"]')),a&&(t.querySelectorAll(".mw-calendar-day").forEach(function(e){e.tabIndex=-1}),a.tabIndex=0,a.focus())}(c)}),w()}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,c=e.querySelector(".mw-gallery-dots"),o=e.querySelector(".mw-gallery-desc"),r=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}%)`,c&&c.querySelectorAll(".mw-gallery-dot").forEach((e,t)=>{e.classList.toggle("mw-active",t===l)}),o&&(o.textContent=a[l].dataset.desc||"")}if(c)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)),c.appendChild(t)}r&&r.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,c=t.querySelector(".mw-theme-toggle-slider i"),o=getComputedStyle(document.documentElement).getPropertyValue("--mw-internal-theme-mode").trim()||"switchable";if("switchable"!==o)return console.log(`Theme mode fixed to: ${o}. Disabling toggle.`),c&&(c.className="light"===o?"fas fa-sun":"fas fa-moon"),e(t,"light"===o),t.style.opacity="0.4",t.style.pointerEvents="none",t.style.cursor="default",t.setAttribute("aria-disabled","true"),localStorage.removeItem("mw-theme"),void("dark"===o&&a.classList.remove("mw-theme-light"));let r="light"===localStorage.getItem("mw-theme");const s=n=>{a.classList.toggle("mw-theme-light",n),e(t,n),c&&(c.className=n?"fas fa-sun":"fas fa-moon")};s(r),t.addEventListener("click",()=>{r=!r,s(r),localStorage.setItem("mw-theme",r?"light":"dark"),setTimeout(n,400)})}(),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;function n(){e.classList.remove("open"),t.classList.remove("open")}function a(n){n.preventDefault(),n.stopPropagation(),e.classList.toggle("open"),t.classList.toggle("open")}e.addEventListener("click",a),e.addEventListener("touchstart",a,{passive:!1}),document.addEventListener("click",function(a){t.classList.contains("open")&&(t.contains(a.target)||e.contains(a.target)||n())}),document.addEventListener("keydown",function(e){"Escape"===e.key&&n()})}(),function(){const e=document.querySelectorAll(".mw-progress-fill");if(!e.length)return;const t=new IntersectionObserver((e,t)=>{e.forEach(e=>{if(!e.isIntersecting)return;const n=e.target,a=n.dataset.value||0;n.style.width=a+"%",t.unobserve(n)})},{root:null,threshold:.2});e.forEach(e=>t.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,c=arguments;clearTimeout(n),n=setTimeout(()=>e.apply(a,c),t)}}(function(){let c="";const o=a();t.forEach(e=>{const t=e.offsetTop-o,n=e.clientHeight;scrollY>=t&&scrollY<t+n&&(c=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)===c&&e(t,!0)}}})},100))}(),document.querySelectorAll(".mw-tabs-nav-item").forEach(t=>{t.addEventListener("click",function(){const t=this.closest(".mw-tabs");if(!t)return;t.querySelectorAll(".mw-tabs-nav-item").forEach(t=>{e(t,!1)}),e(this,!0);const n=this.getAttribute("data-tab");n&&(t.querySelectorAll(".mw-tabs-panel").forEach(t=>{e(t,!1)}),e(document.getElementById(n),!0))})}),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,c=Math.round(e/a*100);t.style.setProperty("--value",c+"%"),n.classList.contains("mw-slider-numeric")?n.setAttribute("data-value",e):n.setAttribute("data-value",c)};t.addEventListener("input",a),a()}),document.querySelectorAll(".mw-modal-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-modal-overlay");e&&e.classList.remove("mw-modal-open")})}),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 c=0;function o(){n.forEach(t=>{e(t,parseInt(t.dataset.index)===c)}),a.forEach(t=>{e(t,parseInt(t.dataset.index)===c)})}function r(e){c=e,o()}a.forEach(e=>{e.addEventListener("click",()=>{r(parseInt(e.dataset.index))})}),o()}),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(a),document.querySelectorAll("[data-calendar]").forEach(c),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"),c=t.querySelector("summary .mw-flag"),o=t.querySelector("summary .mw-lang-switch-code");n.forEach(r=>{r.addEventListener("click",function(){const s=r.dataset.mwLang,l=r.querySelector(".mw-lang-switch-name"),i=l?l.textContent.trim():s;n.forEach(t=>{e(t,t===r),t===r?t.setAttribute("aria-current","true"):t.removeAttribute("aria-current")}),o&&(o.textContent=s);const d=r.querySelector(".mw-flag");c&&d&&(c.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}}))}}();
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"))}}();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "maverick-wave",
3
- "version": "4.28.0",
3
+ "version": "5.1.0",
4
4
  "config": {
5
- "version_short": "4.28"
5
+ "version_short": "5.1"
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
@@ -7,6 +7,7 @@
7
7
  * 2. every --mw-* definition is used somewhere
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
+ * 5. the CDN version pinned in the docs matches package.json
10
11
  *
11
12
  * Sources are scanned rather than hard-coded so a new partial is covered
12
13
  * automatically. Exits 1 on any error; warnings never fail the build.
@@ -72,9 +73,12 @@ const docs = DOCS.map(read).filter(Boolean).map(stripFrontmatter).join('\n');
72
73
  // --- 1 + 2: custom properties ---------------------------------------------
73
74
 
74
75
  const tokensDefined = new Set(all(css, /(--mw-[a-z0-9-]+)\s*:/g));
76
+ // `\s*` after the paren: a long declaration wrapped by Prettier keeps its
77
+ // newline inside var() all the way through the minifier, and a token used only
78
+ // there would otherwise read as unused.
75
79
  const tokensUsed = new Set([
76
- ...all(css, /var\((--mw-[a-z0-9-]+)/g),
77
- ...all(html, /var\((--mw-[a-z0-9-]+)/g),
80
+ ...all(css, /var\(\s*(--mw-[a-z0-9-]+)/g),
81
+ ...all(html, /var\(\s*(--mw-[a-z0-9-]+)/g),
78
82
  ...all(js, /(--mw-[a-z0-9-]+)/g),
79
83
  ]);
80
84
 
@@ -136,6 +140,27 @@ for (const f of ['maverick-wave.min.css', 'maverick-wave.min.js']) {
136
140
  }
137
141
  }
138
142
 
143
+ // --- 5: pinned CDN version -------------------------------------------------
144
+ // Every jsDelivr snippet in the docs pins a version, which is the right advice
145
+ // and the reason it goes stale: 5.0.0 shipped with six snippets still on 4.28.0.
146
+
147
+ const { version } = require(path.join(ROOT, 'package.json'));
148
+
149
+ for (const p of [path.join(ROOT, 'README.md'), ...DOCS]) {
150
+ const md = read(p);
151
+ if (!md) continue;
152
+ const stale = new Set(
153
+ all(md, /maverick-wave@([0-9]+\.[0-9]+\.[0-9]+)/g).filter(
154
+ (v) => v !== version
155
+ )
156
+ );
157
+ for (const v of stale) {
158
+ errors.push(
159
+ `stale CDN pin in ${path.relative(ROOT, p)}: maverick-wave@${v} - package.json is ${version}`
160
+ );
161
+ }
162
+ }
163
+
139
164
  // Informational: framework classes the showcase never demonstrates
140
165
  const undocumented = [...classesInCss].filter(
141
166
  (c) => !classesInMarkup.has(c) && !classesInJs.has(c)
package/src/js/main.js CHANGED
@@ -1,10 +1,8 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
- // State classes: `mw-active` is the documented spelling, plain `active` is
5
- // the one older markup uses. Both are styled, so turning a state *off* has
6
- // to clear both - otherwise a stale `active` from the HTML would keep a
7
- // second tab lit.
4
+ // Both spellings are styled, so turning a state off has to clear both or a
5
+ // stale `active` in the HTML keeps a second tab lit
8
6
  function setActive(el, on) {
9
7
  if (!el) return;
10
8
  el.classList.toggle('mw-active', on);
@@ -43,15 +41,8 @@
43
41
  initLangSwitches();
44
42
  });
45
43
 
46
- // ===== Dropdowns =====
47
- //
48
- // The menu is a <details>, so opening, closing, the keyboard and the state a
49
- // screen reader reads out are all the browser's job already. Two things it
50
- // does not do, because no markup can express them: close when the click lands
51
- // somewhere else, and close on Escape.
52
- //
53
- // Delegated to the document rather than bound per dropdown, so a menu added
54
- // to the page later works without being initialised.
44
+ // The menu is a <details>, so only two things are left: close on an outside
45
+ // click and close on Escape. Delegated, so a menu added later works too.
55
46
  function initDropdowns() {
56
47
  function closeAll(except) {
57
48
  document.querySelectorAll('.mw-dropdown[open]').forEach((dropdown) => {
@@ -89,14 +80,8 @@
89
80
  });
90
81
  }
91
82
 
92
- // ===== Language Switcher =====
93
- //
94
- // The menu itself is a dropdown and needs nothing here. This only keeps the
95
- // trigger in step with the choice and then announces it - which language is
96
- // actually loaded is the application's business, not the framework's, and
97
- // that decision usually lives in the URL or on the server rather than in
98
- // localStorage. Listen for it:
99
- //
83
+ // Keeps the trigger in step with the choice and announces it - which language
84
+ // actually loads is the application's business, usually the URL or the server:
100
85
  // document.addEventListener('mw-language-change', (e) => e.detail.lang)
101
86
  function initLangSwitches() {
102
87
  document.querySelectorAll('.mw-lang-switch').forEach((languageSwitch) => {
@@ -320,6 +305,7 @@
320
305
  if (!themeToggle) return;
321
306
 
322
307
  const body = document.body;
308
+ const root = document.documentElement;
323
309
  const icon = themeToggle.querySelector('.mw-theme-toggle-slider i');
324
310
 
325
311
  const computedStyle = getComputedStyle(document.documentElement);
@@ -358,8 +344,12 @@
358
344
 
359
345
  // Function to apply theme styles and icon
360
346
  const applyTheme = (lightMode) => {
361
- // Use toggle's second argument for cleaner class switching
347
+ // The forced reflow is the point: the new colours land while transitions are off
348
+ root.classList.add('mw-theme-switching');
362
349
  body.classList.toggle('mw-theme-light', lightMode);
350
+ void root.offsetHeight;
351
+ root.classList.remove('mw-theme-switching');
352
+
363
353
  setActive(themeToggle, lightMode);
364
354
  if (icon) {
365
355
  icon.className = lightMode ? 'fas fa-sun' : 'fas fa-moon';
@@ -375,8 +365,8 @@
375
365
  applyTheme(isLight);
376
366
  localStorage.setItem('mw-theme', isLight ? 'light' : 'dark'); // Save
377
367
 
378
- // update color swatches
379
- setTimeout(updateColorSwatchHexValues, 400);
368
+ // No transition left to wait out, so the swatches can read the new values now
369
+ updateColorSwatchHexValues();
380
370
  });
381
371
  }
382
372
 
@@ -386,14 +376,20 @@
386
376
  }
387
377
 
388
378
  function updateColorSwatchHexValues() {
389
- const colorSwatches = document.querySelectorAll('.color-swatch');
390
- colorSwatches.forEach((swatch) => {
391
- const bgColor = window.getComputedStyle(swatch).backgroundColor;
392
- const hex = rgbToHex(bgColor);
379
+ const colorSwatches = Array.from(
380
+ document.querySelectorAll('.color-swatch')
381
+ );
382
+
383
+ // All reads before the first write - a write between two reads forces a recalc
384
+ const hexValues = colorSwatches.map((swatch) =>
385
+ rgbToHex(window.getComputedStyle(swatch).backgroundColor)
386
+ );
387
+
388
+ colorSwatches.forEach((swatch, index) => {
393
389
  const hexTextElement =
394
390
  swatch.parentElement.querySelector('.mw-text-muted');
395
391
  if (hexTextElement) {
396
- hexTextElement.textContent = hex;
392
+ hexTextElement.textContent = hexValues[index];
397
393
  }
398
394
  });
399
395
  }
@@ -457,16 +453,19 @@
457
453
 
458
454
  if (!menuBtn || !navbar) return;
459
455
 
460
- function closeMenu() {
461
- menuBtn.classList.remove('open');
462
- navbar.classList.remove('open');
456
+ // aria-expanded only on a real control - on a <div> it claims a state for nothing
457
+ const announces = menuBtn.tagName === 'BUTTON';
458
+
459
+ function setOpen(open) {
460
+ menuBtn.classList.toggle('open', open);
461
+ navbar.classList.toggle('open', open);
462
+ if (announces) menuBtn.setAttribute('aria-expanded', String(open));
463
463
  }
464
464
 
465
465
  function toggleMenu(e) {
466
466
  e.preventDefault();
467
467
  e.stopPropagation();
468
- menuBtn.classList.toggle('open');
469
- navbar.classList.toggle('open');
468
+ setOpen(!navbar.classList.contains('open'));
470
469
  }
471
470
 
472
471
  // Add multiple event listeners for better iOS compatibility
@@ -477,38 +476,58 @@
477
476
  document.addEventListener('click', function (e) {
478
477
  if (!navbar.classList.contains('open')) return;
479
478
  if (navbar.contains(e.target) || menuBtn.contains(e.target)) return;
480
- closeMenu();
479
+ setOpen(false);
481
480
  });
482
481
 
482
+ // Or Escape strands the keyboard user in a drawer that is no longer there
483
483
  document.addEventListener('keydown', function (e) {
484
- if (e.key === 'Escape') closeMenu();
484
+ if (e.key !== 'Escape') return;
485
+ if (!navbar.classList.contains('open')) return;
486
+ setOpen(false);
487
+ menuBtn.focus();
485
488
  });
486
489
  }
487
490
 
488
491
  // ===== Progress Bars =====
492
+
493
+ // The fill is driven from CSS where the browser can do it (_progress.scss), so
494
+ // this only hands the target width over and switches the animation on
489
495
  function initProgressBars() {
490
496
  const fills = document.querySelectorAll('.mw-progress-fill');
491
497
  if (!fills.length) return;
492
498
 
499
+ const scrollDriven = CSS.supports('animation-timeline', 'view()');
500
+
501
+ // Two spellings in the wild: data-value="75" and style="width: 75%".
502
+ const targetWidth = (bar) =>
503
+ bar.dataset.value ? bar.dataset.value + '%' : bar.style.width;
504
+
505
+ const driven = [];
506
+ fills.forEach((bar) => {
507
+ const target = targetWidth(bar);
508
+ if (!target) return;
509
+ bar.style.setProperty('--mw-progress-value', target);
510
+ if (scrollDriven) bar.classList.add('mw-progress-driven');
511
+ else driven.push(bar);
512
+ });
513
+
514
+ if (scrollDriven) return;
515
+
516
+ // Fallback: set the width once, when the bar comes into view, and let the
517
+ // transition in _progress.scss animate it. Only bars whose target is known -
518
+ // a bar already carrying its width in the markup is left alone.
493
519
  const obs = new IntersectionObserver(
494
520
  (entries, observer) => {
495
521
  entries.forEach((entry) => {
496
522
  if (!entry.isIntersecting) return;
497
- const bar = entry.target;
498
- const pct = bar.dataset.value || 0;
499
- // trigger the CSS transition
500
- bar.style.width = pct + '%';
501
- // stop observing this one
502
- observer.unobserve(bar);
523
+ entry.target.style.width = targetWidth(entry.target);
524
+ observer.unobserve(entry.target);
503
525
  });
504
526
  },
505
- {
506
- root: null,
507
- threshold: 0.2,
508
- }
527
+ { root: null, threshold: 0.2 }
509
528
  );
510
529
 
511
- fills.forEach((bar) => obs.observe(bar));
530
+ driven.forEach((bar) => obs.observe(bar));
512
531
  }
513
532
 
514
533
  // ===== Smooth Scrolling =====
@@ -538,10 +557,8 @@
538
557
 
539
558
  if (sections.length === 0 || navLinks.length === 0) return;
540
559
 
541
- // An anchor jump lands on scroll-padding-top, so the spy has to measure
542
- // against the same value - a hardcoded one marks the section before the
543
- // target as soon as an announcement ribbon raises the padding. Read per
544
- // run: the ribbon grows on small screens and can be dismissed at runtime.
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
545
562
  function scrollOffset() {
546
563
  const padding = parseFloat(
547
564
  getComputedStyle(document.documentElement).scrollPaddingTop
@@ -583,35 +600,109 @@
583
600
  );
584
601
  }
585
602
 
586
- // ===== Tabs =====
603
+ // The strip draws the marker, this only hands over position and length as custom
604
+ // properties. Both axes every time - which pair the bar uses is the stylesheet's
605
+ // decision, at a breakpoint this file knows nothing of. The attribute switches
606
+ // the bar on and is set after the first measurement, so a page without script
607
+ // keeps the plain border and still looks finished.
608
+ function measureTabsMarker(nav) {
609
+ const active = nav.querySelector(
610
+ '.mw-tabs-nav-item.mw-active, .mw-tabs-nav-item.active'
611
+ );
612
+ if (!active) {
613
+ nav.removeAttribute('data-mw-tabs-marker');
614
+ return;
615
+ }
616
+
617
+ // Unitless for the scale factors: the bar is 1px long and scaled up.
618
+ nav.style.setProperty('--mw-tabs-marker-x', active.offsetLeft + 'px');
619
+ nav.style.setProperty('--mw-tabs-marker-w', active.offsetWidth);
620
+ nav.style.setProperty('--mw-tabs-marker-y', active.offsetTop + 'px');
621
+ nav.style.setProperty('--mw-tabs-marker-h', active.offsetHeight);
622
+ nav.setAttribute('data-mw-tabs-marker', '');
623
+ }
624
+
625
+ // Set here and not in the markup, so a page that already ships .mw-tabs gets the
626
+ // tablist semantics by loading the script
587
627
  function initTabs() {
588
- const tabNavItems = document.querySelectorAll('.mw-tabs-nav-item');
628
+ document.querySelectorAll('.mw-tabs-nav').forEach((nav) => {
629
+ const items = Array.from(nav.querySelectorAll('.mw-tabs-nav-item'));
630
+ if (!items.length) return;
589
631
 
590
- tabNavItems.forEach((item) => {
591
- item.addEventListener('click', function () {
592
- const tabsContainer = this.closest('.mw-tabs');
593
- if (!tabsContainer) return;
632
+ const vertical = !!nav.closest('.mw-tabs-vertical');
594
633
 
595
- tabsContainer
596
- .querySelectorAll('.mw-tabs-nav-item')
597
- .forEach((navItem) => {
598
- setActive(navItem, false);
599
- });
634
+ nav.setAttribute('role', 'tablist');
635
+ if (vertical) nav.setAttribute('aria-orientation', 'vertical');
600
636
 
601
- setActive(this, true);
637
+ items.forEach((item, index) => {
638
+ const panel = tabPanelOf(item);
602
639
 
603
- const tabId = this.getAttribute('data-tab');
604
- if (!tabId) return;
640
+ item.setAttribute('role', 'tab');
641
+ if (!item.id) item.id = (panel ? panel.id : 'mw-tab-' + index) + '-tab';
605
642
 
606
- tabsContainer.querySelectorAll('.mw-tabs-panel').forEach((panel) => {
607
- setActive(panel, false);
608
- });
643
+ if (panel) {
644
+ item.setAttribute('aria-controls', panel.id);
645
+ panel.setAttribute('role', 'tabpanel');
646
+ panel.setAttribute('aria-labelledby', item.id);
647
+ }
609
648
 
610
- setActive(document.getElementById(tabId), true);
649
+ syncTabState(item);
650
+
651
+ item.addEventListener('click', () => selectTab(items, item));
652
+
653
+ item.addEventListener('keydown', (event) => {
654
+ const target = tabKeyTarget(event, vertical, items.length, index);
655
+ if (target === null) return;
656
+ event.preventDefault();
657
+ selectTab(items, items[target]);
658
+ items[target].focus();
659
+ });
611
660
  });
661
+
662
+ measureTabsMarker(nav);
663
+
664
+ // The items are watched too: a web font arriving moves the label the bar is
665
+ // parked under without the strip itself changing size
666
+ const observer = new ResizeObserver(() => measureTabsMarker(nav));
667
+ observer.observe(nav);
668
+ items.forEach((item) => observer.observe(item));
612
669
  });
613
670
  }
614
671
 
672
+ function tabPanelOf(item) {
673
+ const id = item.getAttribute('data-tab');
674
+ return id ? document.getElementById(id) : null;
675
+ }
676
+
677
+ function syncTabState(item) {
678
+ const on = isActive(item);
679
+ item.setAttribute('aria-selected', String(on));
680
+ item.tabIndex = on ? 0 : -1;
681
+ }
682
+
683
+ function selectTab(items, item) {
684
+ items.forEach((other) => {
685
+ const on = other === item;
686
+ setActive(other, on);
687
+ setActive(tabPanelOf(other), on);
688
+ syncTabState(other);
689
+ });
690
+
691
+ const nav = item.closest('.mw-tabs-nav');
692
+ if (nav) measureTabsMarker(nav);
693
+ }
694
+
695
+ function tabKeyTarget(event, vertical, count, index) {
696
+ const back = vertical ? 'ArrowUp' : 'ArrowLeft';
697
+ const forward = vertical ? 'ArrowDown' : 'ArrowRight';
698
+
699
+ if (event.key === back) return (index - 1 + count) % count;
700
+ if (event.key === forward) return (index + 1) % count;
701
+ if (event.key === 'Home') return 0;
702
+ if (event.key === 'End') return count - 1;
703
+ return null;
704
+ }
705
+
615
706
  // ===== Alerts =====
616
707
  function initAlerts() {
617
708
  const alertCloseButtons = document.querySelectorAll('.mw-alert-close');
@@ -691,17 +782,71 @@
691
782
  }
692
783
 
693
784
  // ===== Modals =====
785
+
786
+ // Two shapes: the older `mw-modal-overlay` div toggled by class, and `<dialog>`,
787
+ // where focus trap, Escape and the inert background are the browser's job.
788
+ // Delegated, so a modal added later works too.
694
789
  function initModals() {
695
- document.querySelectorAll('.mw-modal-close').forEach((button) => {
696
- button.addEventListener('click', function () {
697
- const modal = this.closest('.mw-modal-overlay');
698
- if (modal) {
699
- modal.classList.remove('mw-modal-open');
790
+ document.addEventListener('click', (e) => {
791
+ const closer = e.target.closest('.mw-modal-close');
792
+ if (closer) {
793
+ const dialog = closer.closest('dialog.mw-modal');
794
+ if (dialog) {
795
+ dialog.close();
796
+ return;
700
797
  }
701
- });
798
+ const overlay = closer.closest('.mw-modal-overlay');
799
+ if (overlay) overlay.classList.remove('mw-modal-open');
800
+ return;
801
+ }
802
+
803
+ const opener = e.target.closest('[data-mw-modal]');
804
+ if (opener) {
805
+ openModal(document.getElementById(opener.dataset.mwModal));
806
+ return;
807
+ }
808
+
809
+ // Light dismiss for a dialog the browser does not dismiss itself. A click
810
+ // that lands on the dialog element is a click on the backdrop - the
811
+ // content sits in .mw-modal-header/body/footer inside it.
812
+ if (
813
+ e.target.matches('dialog.mw-modal[open]') &&
814
+ !dismissesItself(e.target)
815
+ ) {
816
+ e.target.close();
817
+ }
702
818
  });
703
819
  }
704
820
 
821
+ // True when `closedby` is on the element *and* understood, which is the only
822
+ // case where the browser closes the dialog on a backdrop click by itself.
823
+ function dismissesItself(dialog) {
824
+ return 'closedBy' in dialog && dialog.getAttribute('closedby') !== null;
825
+ }
826
+
827
+ // Opens either shape. Exposed, because which modal opens when is the
828
+ // application's decision and not something markup can express on its own.
829
+ function openModal(modal) {
830
+ if (!modal) return;
831
+ if (modal.tagName === 'DIALOG') {
832
+ modal.showModal();
833
+ } else {
834
+ modal.classList.add('mw-modal-open');
835
+ }
836
+ }
837
+
838
+ function closeModal(modal) {
839
+ if (!modal) return;
840
+ if (modal.tagName === 'DIALOG') {
841
+ modal.close();
842
+ } else {
843
+ modal.classList.remove('mw-modal-open');
844
+ }
845
+ }
846
+
847
+ window.mwOpenModal = (id) => openModal(document.getElementById(id));
848
+ window.mwCloseModal = (id) => closeModal(document.getElementById(id));
849
+
705
850
  // ===== Login Button =====
706
851
  function initHeaderLoginButton() {
707
852
  const loginButton = document.getElementById('login-button');
@@ -926,14 +1071,9 @@
926
1071
 
927
1072
  target.querySelector('.mw-kanban-column-body').appendChild(card);
928
1073
 
929
- // The card lands in a lane somewhere else on the board, so it says so on
930
- // arrival and comes in from the side it was pushed from. Re-parenting it
931
- // alone made it blink into the other column with no motion at all.
932
- //
933
- // Both classes come off first and the reflow is forced in between: an
934
- // element that already carries the class it is being given again keeps
935
- // the finished animation and plays nothing, so a second push in the same
936
- // direction would be the silent one.
1074
+ // Re-parenting alone makes the card blink into the other column, so it comes
1075
+ // in from the side it was pushed from. Both classes come off first with a
1076
+ // forced reflow between, or a second push in the same direction is silent.
937
1077
  card.classList.remove.apply(card.classList, MOVE_CLASSES);
938
1078
  void card.offsetWidth;
939
1079
  card.classList.add(offset > 0 ? MOVE_CLASSES[0] : MOVE_CLASSES[1]);
@@ -45,9 +45,9 @@
45
45
  your project's needs:
46
46
  </p>
47
47
 
48
- <h5 class="mw-mt-4 mw-mb-2">
48
+ <h4 class="mw-mt-4 mw-mb-2">
49
49
  1. Using CSS Variables (Recommended for CDN/CSS Users)
50
- </h5>
50
+ </h4>
51
51
  <p>
52
52
  If you're using the pre-compiled CSS file (via CDN or download), you
53
53
  can override MaverickWave's default styles by redefining its CSS
@@ -69,9 +69,9 @@
69
69
  }</code></pre>
70
70
  <p>This method is flexible and doesn't require a Sass build process.</p>
71
71
 
72
- <h5 class="mw-mt-4 mw-mb-2">
72
+ <h4 class="mw-mt-4 mw-mb-2">
73
73
  2. Using SCSS Variables (Requires Sass Build Process)
74
- </h5>
74
+ </h4>
75
75
  <p>
76
76
  If you integrate MaverickWave's SCSS source files into your project,
77
77
  pass your overrides through <code>@use ... with (...)</code>. A plain
@@ -91,13 +91,9 @@
91
91
  <code>main</code> - see the "Get Started" section.
92
92
  </p>
93
93
  <p class="mw-mt-4">
94
- <button
95
- type="button"
96
- onclick="location.href = '#get-started'"
97
- class="mw-link"
98
- >
94
+ <a href="#get-started" class="mw-link">
99
95
  See the "Get Started" section
100
- </button>
96
+ </a>
101
97
  for more detailed integration examples for both methods.
102
98
  </p>
103
99
  </div>