maverick-wave 4.24.0 → 4.26.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 (26) hide show
  1. package/.claude/skills/{maverick-wave → mw-maverick-wave}/SKILL.md +12 -12
  2. package/.claude/skills/{maverick-wave → mw-maverick-wave}/examples/static-landing-page.md +196 -45
  3. package/.claude/skills/{maverick-wave → mw-maverick-wave}/references/components.md +9 -0
  4. package/.claude/skills/{maverick-wave → mw-maverick-wave}/references/layout.md +42 -1
  5. package/CHANGELOG.md +13 -0
  6. package/README.md +3 -3
  7. package/index.html +7 -0
  8. package/maverick-wave.min.css +1 -1
  9. package/maverick-wave.min.js +1 -1
  10. package/package.json +2 -2
  11. package/scripts/verify.js +4 -1
  12. package/src/js/main.js +14 -1
  13. package/src/partials/documentation-container.html +27 -0
  14. package/src/partials/highlights-container.html +69 -0
  15. package/src/partials/home-container.html +1 -1
  16. package/src/partials/testimonials-container.html +7 -1
  17. package/src/scss/abstracts/_mixins.scss +13 -0
  18. package/src/scss/components/_testimonial.scss +22 -0
  19. package/src/scss/layout/_grid.scss +53 -0
  20. package/src/scss/utilities/_reveal.scss +40 -9
  21. /package/.claude/skills/{maverick-wave → mw-maverick-wave}/examples/angular-form.md +0 -0
  22. /package/.claude/skills/{maverick-wave → mw-maverick-wave}/examples/angular-list-page.md +0 -0
  23. /package/.claude/skills/{maverick-wave → mw-maverick-wave}/examples/angular-services.md +0 -0
  24. /package/.claude/skills/{maverick-wave → mw-maverick-wave}/references/forms.md +0 -0
  25. /package/.claude/skills/{maverick-wave → mw-maverick-wave}/references/javascript.md +0 -0
  26. /package/.claude/skills/{maverick-wave → mw-maverick-wave}/references/theming.md +0 -0
@@ -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;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 a="";t.forEach(e=>{const t=e.offsetTop-100,n=e.clientHeight;scrollY>=t&&scrollY<t+n&&(a=e.getAttribute("id"))}),n.forEach(t=>{e(t,!1);const n=t.getAttribute("href");if(n){const c=n.indexOf("#");if(-1!==c){n.substring(c+1)===a&&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()})}()}),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(){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()})}()}),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}}))}}();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "maverick-wave",
3
- "version": "4.24.0",
3
+ "version": "4.26.0",
4
4
  "config": {
5
- "version_short": "4.24"
5
+ "version_short": "4.26"
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
@@ -64,7 +64,10 @@ if (!css || !html) {
64
64
  process.exit(1);
65
65
  }
66
66
  const js = read(JS) || '';
67
- const docs = DOCS.map(read).filter(Boolean).join('\n');
67
+ // The YAML frontmatter of a skill is metadata, not documentation - its
68
+ // `name: mw-maverick-wave` would otherwise be reported as a missing class.
69
+ const stripFrontmatter = (md) => md.replace(/^---\n[\s\S]*?\n---\n/, '');
70
+ const docs = DOCS.map(read).filter(Boolean).map(stripFrontmatter).join('\n');
68
71
 
69
72
  // --- 1 + 2: custom properties ---------------------------------------------
70
73
 
package/src/js/main.js CHANGED
@@ -487,13 +487,26 @@
487
487
 
488
488
  if (sections.length === 0 || navLinks.length === 0) return;
489
489
 
490
+ // An anchor jump lands on scroll-padding-top, so the spy has to measure
491
+ // against the same value - a hardcoded one marks the section before the
492
+ // target as soon as an announcement ribbon raises the padding. Read per
493
+ // run: the ribbon grows on small screens and can be dismissed at runtime.
494
+ function scrollOffset() {
495
+ const padding = parseFloat(
496
+ getComputedStyle(document.documentElement).scrollPaddingTop
497
+ );
498
+ // +2 absorbs subpixel rounding between the jump and the scroll position.
499
+ return (Number.isNaN(padding) ? 0 : padding) + 2;
500
+ }
501
+
490
502
  window.addEventListener(
491
503
  'scroll',
492
504
  debounce(function () {
493
505
  let current = '';
506
+ const offset = scrollOffset();
494
507
 
495
508
  sections.forEach((section) => {
496
- const sectionTop = section.offsetTop - 100;
509
+ const sectionTop = section.offsetTop - offset;
497
510
  const sectionHeight = section.clientHeight;
498
511
 
499
512
  if (scrollY >= sectionTop && scrollY < sectionTop + sectionHeight) {
@@ -87,6 +87,15 @@
87
87
  <li>
88
88
  <a href="#tags">Tags</a>
89
89
  </li>
90
+ <li>
91
+ <a href="#badges">Badges</a>
92
+ </li>
93
+ <li>
94
+ <a href="#dropdown">Dropdown</a>
95
+ </li>
96
+ <li>
97
+ <a href="#kbd">Keyboard Keys</a>
98
+ </li>
90
99
  <li>
91
100
  <a href="#ratings">Ratings</a>
92
101
  </li>
@@ -96,6 +105,9 @@
96
105
  <li>
97
106
  <a href="#alerts">Alerts</a>
98
107
  </li>
108
+ <li>
109
+ <a href="#announcement">Announcement</a>
110
+ </li>
99
111
  <li>
100
112
  <a href="#code">Code</a>
101
113
  </li>
@@ -105,6 +117,9 @@
105
117
  <li>
106
118
  <a href="#empty-state">Empty State</a>
107
119
  </li>
120
+ <li>
121
+ <a href="#pricing">Pricing</a>
122
+ </li>
108
123
  </ul>
109
124
  <!-- seperator -->
110
125
  <li>
@@ -117,6 +132,9 @@
117
132
  <li>
118
133
  <a href="#input-group">Input Group</a>
119
134
  </li>
135
+ <li>
136
+ <a href="#segmented">Segmented Control</a>
137
+ </li>
120
138
  <li>
121
139
  <a href="#form-field">Field Pattern</a>
122
140
  </li>
@@ -162,6 +180,15 @@
162
180
  <li>
163
181
  <a href="#content-slider">Content Slider</a>
164
182
  </li>
183
+ <li>
184
+ <a href="#testimonials">Testimonials</a>
185
+ </li>
186
+ <li>
187
+ <a href="#prose">Prose</a>
188
+ </li>
189
+ <li>
190
+ <a href="#media">Media</a>
191
+ </li>
165
192
  <li>
166
193
  <a href="#blog-posts">Blog Posts</a>
167
194
  </li>
@@ -0,0 +1,69 @@
1
+ <h2 class="mw-section-title">Why MaverickWave</h2>
2
+ <p class="mw-section-intro">
3
+ Four decisions the framework has already made for you, so a page looks
4
+ finished on the first build - on a phone as much as on a desk.
5
+ </p>
6
+
7
+ <!-- mw-reveal-stagger: every card rises as it scrolls in, the second and
8
+ third of each row a beat later. One class on the grid, nothing per card -->
9
+ <div class="mw-grid-4 mw-reveal-stagger">
10
+ <div class="mw-card mw-card-stack">
11
+ <div class="mw-card-stack-header">
12
+ <div class="mw-card-stack-icon">
13
+ <i class="fas fa-moon"></i>
14
+ </div>
15
+ <h5 class="mw-card-stack-title">Dark mode, built in</h5>
16
+ </div>
17
+ <div class="mw-card-stack-body">
18
+ <p class="mw-card-stack-text">
19
+ One class on <code>body</code> flips every component. Switchable, or
20
+ fixed to one theme at build time.
21
+ </p>
22
+ </div>
23
+ </div>
24
+
25
+ <div class="mw-card mw-card-stack">
26
+ <div class="mw-card-stack-header">
27
+ <div class="mw-card-stack-icon">
28
+ <i class="fas fa-mobile-screen"></i>
29
+ </div>
30
+ <h5 class="mw-card-stack-title">Mobile first</h5>
31
+ </div>
32
+ <div class="mw-card-stack-body">
33
+ <p class="mw-card-stack-text">
34
+ Touch targets grow on a coarse pointer, modals turn into bottom sheets,
35
+ and nothing scrolls sideways.
36
+ </p>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="mw-card mw-card-stack">
41
+ <div class="mw-card-stack-header">
42
+ <div class="mw-card-stack-icon">
43
+ <i class="fas fa-palette"></i>
44
+ </div>
45
+ <h5 class="mw-card-stack-title">One color, whole palette</h5>
46
+ </div>
47
+ <div class="mw-card-stack-body">
48
+ <p class="mw-card-stack-text">
49
+ Set <code>--mw-primary-color</code> and the hover tones, tints and
50
+ borders follow via <code>color-mix()</code>.
51
+ </p>
52
+ </div>
53
+ </div>
54
+
55
+ <div class="mw-card mw-card-stack">
56
+ <div class="mw-card-stack-header">
57
+ <div class="mw-card-stack-icon">
58
+ <i class="fas fa-bolt"></i>
59
+ </div>
60
+ <h5 class="mw-card-stack-title">No build step</h5>
61
+ </div>
62
+ <div class="mw-card-stack-body">
63
+ <p class="mw-card-stack-text">
64
+ Two files from the CDN and you are done. The SCSS sources are there when
65
+ you want <code>@use</code> level control.
66
+ </p>
67
+ </div>
68
+ </div>
69
+ </div>
@@ -33,7 +33,7 @@
33
33
  </div>
34
34
  </div>
35
35
 
36
- <a class="mw-scroll-hint" href="#get-started">
36
+ <a class="mw-scroll-hint" href="#highlights">
37
37
  More
38
38
  <i class="fas fa-chevron-down"></i>
39
39
  </a>
@@ -5,7 +5,10 @@
5
5
  <code>mw-testimonial-featured</code>; the rest flow in
6
6
  <code>mw-columns-3</code>, the masonry layout for cards of unequal height. The
7
7
  cards below also carry <code>mw-reveal</code> - scroll them into view to see
8
- the entrance.
8
+ the entrance. Three of them are dated: <code>mw-testimonial-date</code> is a
9
+ <code>time</code> element on the right edge of the source line, month and
10
+ year. It is optional on purpose - a dated quote ages, so only show it where
11
+ the voices are kept fresh.
9
12
  </p>
10
13
 
11
14
  <figure class="mw-testimonial mw-testimonial-featured mw-mb-6">
@@ -17,6 +20,7 @@
17
20
  <figcaption class="mw-testimonial-source">
18
21
  Maren K.
19
22
  <span class="mw-testimonial-detail">&middot; Head of Engineering</span>
23
+ <time class="mw-testimonial-date" datetime="2026-06">June 2026</time>
20
24
  </figcaption>
21
25
  </figure>
22
26
 
@@ -40,6 +44,7 @@
40
44
  <figcaption class="mw-testimonial-source">
41
45
  Priya S.
42
46
  <span class="mw-testimonial-detail">&middot; Product Designer</span>
47
+ <time class="mw-testimonial-date" datetime="2026-04">April 2026</time>
43
48
  </figcaption>
44
49
  </figure>
45
50
 
@@ -58,6 +63,7 @@
58
63
  </blockquote>
59
64
  <figcaption class="mw-testimonial-source">
60
65
  Aylin D. <span class="mw-testimonial-detail">&middot; Agency Lead</span>
66
+ <time class="mw-testimonial-date" datetime="2026-08">August 2026</time>
61
67
  </figcaption>
62
68
  </figure>
63
69
 
@@ -340,3 +340,16 @@
340
340
  mask-image: $top, $bottom;
341
341
  }
342
342
  }
343
+
344
+ // The scroll-reveal zone (utilities/_reveal.scss), as the range of the n-th
345
+ // column of a row. Viewport lengths rather than percentages of the block: a
346
+ // two-line counter band and a tall card then rise through the same region of
347
+ // the screen instead of the short one snapping in. The zone starts 8dvh above
348
+ // the bottom edge - right at the edge nobody sees the motion - and ends at
349
+ // 34dvh, still in the lower third, so nothing is moving while someone already
350
+ // reads it. Each further column of a row starts 4dvh later than the one before.
351
+ @mixin reveal-range($column: 1) {
352
+ $shift: 4dvh * ($column - 1);
353
+
354
+ animation-range: entry #{8dvh + $shift} entry #{34dvh + $shift};
355
+ }
@@ -37,7 +37,19 @@
37
37
 
38
38
  // margin-top: auto, so in a grid of equal-height cards every source line sits
39
39
  // on its card's bottom edge instead of floating under quotes of random length.
40
+ //
41
+ // A wrapping flex row rather than inline text, so an optional date can sit on
42
+ // the card's right edge: "who" on the left, "when" on the right, and the two
43
+ // do not run into each other. The column gap stands in for the space the
44
+ // inline flow used to leave between name and detail. When the line runs out
45
+ // of room the date drops to a line of its own and stays right-aligned - its
46
+ // auto margin absorbs whatever is left.
40
47
  .mw-testimonial-source {
48
+ display: flex;
49
+ flex-wrap: wrap;
50
+ align-items: baseline;
51
+ column-gap: spacing('2');
52
+ row-gap: spacing('1');
41
53
  margin-top: auto;
42
54
  padding-top: spacing('5');
43
55
  font-size: font-size('sm');
@@ -50,6 +62,16 @@
50
62
  color: var(--mw-text-muted-color);
51
63
  }
52
64
 
65
+ // When the voice spoke - a <time>, month and year, on the right edge of the
66
+ // source line. Optional on purpose: a dated quote ages, and a wall of voices
67
+ // from three years ago says more about the page than about the product.
68
+ .mw-testimonial-date {
69
+ margin-left: auto;
70
+ font-weight: font-weight('normal');
71
+ color: var(--mw-text-muted-color);
72
+ white-space: nowrap;
73
+ }
74
+
53
75
  // The one voice lifted above the grid - it may speak a size louder.
54
76
  .mw-testimonial-featured {
55
77
  blockquote {
@@ -11,6 +11,33 @@
11
11
  gap: spacing('9');
12
12
  }
13
13
 
14
+ // The scroll-reveal stagger, made to follow the columns. mw-reveal-stagger
15
+ // (utilities/_reveal.scss) shifts the entrance of the second and third child of
16
+ // every three - right for a row of three, but in a mw-grid-4 the fourth card
17
+ // would start over with the first. The grid knows its column count at every
18
+ // breakpoint, so it restates the cycle to match: included once per column
19
+ // count, right next to the grid-template-columns it belongs to. Only the range
20
+ // is set here, through the shared `reveal-range` mixin - the animation and its
21
+ // guards stay in _reveal.scss, and a child without the animation ignores the
22
+ // range. The :nth-child(n) reset carries the
23
+ // same specificity as the cycle rules, so a narrower breakpoint can override
24
+ // the wider one's cycle for every child.
25
+ @mixin _reveal-stagger($cols) {
26
+ &.mw-reveal-stagger > :nth-child(n) {
27
+ @include reveal-range(1);
28
+ }
29
+
30
+ // Guarded: Sass counts `from 2 through 1` downwards and would emit a rule
31
+ // for a second column that a single-column grid does not have.
32
+ @if $cols > 1 {
33
+ @for $i from 2 through $cols {
34
+ &.mw-reveal-stagger > :nth-child(#{$cols}n + #{$i}) {
35
+ @include reveal-range($i);
36
+ }
37
+ }
38
+ }
39
+ }
40
+
14
41
  .mw-grid {
15
42
  @extend %grid-base;
16
43
  }
@@ -29,56 +56,69 @@
29
56
  .mw-grid-2 {
30
57
  @extend %grid-base;
31
58
  grid-template-columns: repeat(2, minmax(0, 1fr));
59
+ @include _reveal-stagger(2);
32
60
 
33
61
  @include media-down('sm') {
34
62
  grid-template-columns: minmax(0, 1fr);
63
+ @include _reveal-stagger(1);
35
64
  }
36
65
  }
37
66
 
38
67
  .mw-grid-3 {
39
68
  @extend %grid-base;
40
69
  grid-template-columns: repeat(3, minmax(0, 1fr));
70
+ @include _reveal-stagger(3);
41
71
 
42
72
  @include media-down('md') {
43
73
  grid-template-columns: repeat(2, minmax(0, 1fr));
74
+ @include _reveal-stagger(2);
44
75
  }
45
76
 
46
77
  @include media-down('sm') {
47
78
  grid-template-columns: minmax(0, 1fr);
79
+ @include _reveal-stagger(1);
48
80
  }
49
81
  }
50
82
 
51
83
  .mw-grid-4 {
52
84
  @extend %grid-base;
53
85
  grid-template-columns: repeat(4, minmax(0, 1fr));
86
+ @include _reveal-stagger(4);
54
87
 
55
88
  @include media-down('lg') {
56
89
  grid-template-columns: repeat(2, minmax(0, 1fr));
90
+ @include _reveal-stagger(2);
57
91
  }
58
92
 
59
93
  @include media-down('sm') {
60
94
  grid-template-columns: minmax(0, 1fr);
95
+ @include _reveal-stagger(1);
61
96
  }
62
97
  }
63
98
 
64
99
  .mw-grid-5 {
65
100
  @extend %grid-base;
66
101
  grid-template-columns: repeat(5, minmax(0, 1fr));
102
+ @include _reveal-stagger(5);
67
103
 
68
104
  @include media-down('lg') {
69
105
  grid-template-columns: repeat(4, minmax(0, 1fr));
106
+ @include _reveal-stagger(4);
70
107
  }
71
108
 
72
109
  @include media-down('md') {
73
110
  grid-template-columns: repeat(3, minmax(0, 1fr));
111
+ @include _reveal-stagger(3);
74
112
  }
75
113
 
76
114
  @include media-down('sm') {
77
115
  grid-template-columns: repeat(2, minmax(0, 1fr));
116
+ @include _reveal-stagger(2);
78
117
  }
79
118
 
80
119
  @include media-down('xs') {
81
120
  grid-template-columns: minmax(0, 1fr);
121
+ @include _reveal-stagger(1);
82
122
  }
83
123
  }
84
124
 
@@ -148,8 +188,10 @@
148
188
  .mw-grid-2-lg {
149
189
  @extend %grid-base-lg;
150
190
  grid-template-columns: repeat(2, minmax(0, 1fr));
191
+ @include _reveal-stagger(2);
151
192
  @include media-down('sm') {
152
193
  grid-template-columns: minmax(0, 1fr);
194
+ @include _reveal-stagger(1);
153
195
  gap: spacing('6');
154
196
  }
155
197
  }
@@ -157,12 +199,15 @@
157
199
  .mw-grid-3-lg {
158
200
  @extend %grid-base-lg;
159
201
  grid-template-columns: repeat(3, minmax(0, 1fr));
202
+ @include _reveal-stagger(3);
160
203
  @include media-down('lg') {
161
204
  grid-template-columns: repeat(2, minmax(0, 1fr));
205
+ @include _reveal-stagger(2);
162
206
  gap: spacing('7');
163
207
  }
164
208
  @include media-down('sm') {
165
209
  grid-template-columns: minmax(0, 1fr);
210
+ @include _reveal-stagger(1);
166
211
  gap: spacing('6');
167
212
  }
168
213
  }
@@ -170,14 +215,17 @@
170
215
  .mw-grid-4-lg {
171
216
  @extend %grid-base-lg;
172
217
  grid-template-columns: repeat(4, minmax(0, 1fr));
218
+ @include _reveal-stagger(4);
173
219
  @include media-down('xl') {
174
220
  grid-template-columns: repeat(2, minmax(0, 1fr));
221
+ @include _reveal-stagger(2);
175
222
  }
176
223
  @include media-down('md') {
177
224
  gap: spacing('7');
178
225
  }
179
226
  @include media-down('sm') {
180
227
  grid-template-columns: minmax(0, 1fr);
228
+ @include _reveal-stagger(1);
181
229
  gap: spacing('6');
182
230
  }
183
231
  }
@@ -185,18 +233,23 @@
185
233
  .mw-grid-5-lg {
186
234
  @extend %grid-base-lg;
187
235
  grid-template-columns: repeat(5, minmax(0, 1fr));
236
+ @include _reveal-stagger(5);
188
237
  @include media-down('xl') {
189
238
  grid-template-columns: repeat(4, minmax(0, 1fr));
239
+ @include _reveal-stagger(4);
190
240
  }
191
241
  @include media-down('lg') {
192
242
  grid-template-columns: repeat(3, minmax(0, 1fr));
243
+ @include _reveal-stagger(3);
193
244
  }
194
245
  @include media-down('md') {
195
246
  grid-template-columns: repeat(2, minmax(0, 1fr));
247
+ @include _reveal-stagger(2);
196
248
  gap: spacing('7');
197
249
  }
198
250
  @include media-down('sm') {
199
251
  grid-template-columns: minmax(0, 1fr);
252
+ @include _reveal-stagger(1);
200
253
  gap: spacing('6');
201
254
  }
202
255
  }
@@ -6,11 +6,22 @@
6
6
  //
7
7
  // Both guards matter. `prefers-reduced-motion` is the obvious one. The
8
8
  // @supports guard is the safety net: a browser without scroll timelines would
9
- // otherwise apply `both` fill on an animation that never runs and leave the
10
- // block invisible forever - guarded, it simply renders in place.
9
+ // otherwise apply the backwards fill on an animation that never runs and
10
+ // leave the block invisible forever - guarded, it simply renders in place.
11
11
  //
12
- // The range ends well before the block reaches the middle of the screen, so
13
- // nothing is still moving while someone already reads it.
12
+ // The zone it plays in is the `reveal-range` mixin in abstracts/_mixins.scss:
13
+ // from 8dvh above the bottom edge to 34dvh, measured in viewport lengths so
14
+ // every block rises through the same region of the screen. Eased out rather
15
+ // than linear against the scroll: the block covers most of its way at once
16
+ // and settles, which reads as arriving instead of being dragged.
17
+ //
18
+ // `backwards`, not `both`: the fill only has to hide the block before its
19
+ // entrance - the last frame is the block's own resting state anyway. A
20
+ // forwards fill would keep that frame applied for good, and an animated
21
+ // `transform` beats every author rule: a card would lose its hover lift, and
22
+ // as a transformed box it stays a stacking context, so a dropdown opened
23
+ // inside it paints under the next card in the row. Without the forwards fill
24
+ // the animation lets go once the entrance is done.
14
25
  //
15
26
  // Longhands on purpose, never the animation shorthand: esbuild's CSS minifier
16
27
  // (Vite's default, so every SCSS consumer) collapses a shorthand plus
@@ -19,12 +30,32 @@
19
30
  // Three longhands next to the timeline give it nothing to merge.
20
31
  @supports (animation-timeline: view()) {
21
32
  @media (prefers-reduced-motion: no-preference) {
22
- .mw-reveal {
33
+ .mw-reveal,
34
+ .mw-reveal-stagger > * {
23
35
  animation-name: mw-reveal;
24
- animation-timing-function: linear;
25
- animation-fill-mode: both;
36
+ animation-timing-function: var(--mw-ease-out);
37
+ animation-fill-mode: backwards;
26
38
  animation-timeline: view();
27
- animation-range: entry 2% entry 62%;
39
+ @include reveal-range(1);
40
+ }
41
+
42
+ // A row of cards crosses the viewport edge on the same scroll step, so
43
+ // mw-reveal on each of them rises as one slab. The stagger container
44
+ // shifts the range of the second and third child of every three - a wave
45
+ // across the row instead of a lift. One class on the grid, because the
46
+ // grid decides the columns per breakpoint and the markup cannot.
47
+ //
48
+ // Cycles of three are only the fallback for a container that is not one of
49
+ // the fixed grids - mw-columns-*, a project's own layout. mw-grid-2 to -5
50
+ // and their -lg variants restate the cycle to their own column count at
51
+ // every breakpoint (layout/_grid.scss), so the fourth card of a four-column
52
+ // row is a beat behind the third, not level with the first.
53
+ .mw-reveal-stagger > :nth-child(3n + 2) {
54
+ @include reveal-range(2);
55
+ }
56
+
57
+ .mw-reveal-stagger > :nth-child(3n + 3) {
58
+ @include reveal-range(3);
28
59
  }
29
60
  }
30
61
  }
@@ -32,7 +63,7 @@
32
63
  @keyframes mw-reveal {
33
64
  from {
34
65
  opacity: 0;
35
- transform: translateY(26px);
66
+ transform: translateY(40px);
36
67
  }
37
68
 
38
69
  to {