Courses Catalog

Search, filter, favorite and add courses to your cart. Data loads from catalog.json.

Tip: use beginner, strategy, or a SKU.

Loading catalog…
Fetching ./catalog.json
'; const y = z3a9q("#jsYear"); if(y) y.textContent = String(new Date().getFullYear()); }catch(e){ u7b3k.headerMount.innerHTML = '
SkoolForge
'; u7b3k.footerMount.innerHTML = ''; const y = z3a9q("#jsYear"); if(y) y.textContent = String(new Date().getFullYear()); } } function l0e7x(){ let s = 0; const start = performance.now(); const tick = ()=>{ const now = performance.now(); s = Math.floor((now - start)/1000); const mm = String(Math.floor(s/60)).padStart(2,"0"); const ss = String(s%60).padStart(2,"0"); u7b3k.sessionTimer.textContent = `${mm}:${ss}`; const goal = 300; const pct = p9d2m((s/goal)*100, 0, 100); u7b3k.sessionBar.style.width = `${pct}%`; }; tick(); setInterval(tick, 1000); } function x1d9u(){ u7b3k.searchInput.addEventListener("input", ()=>{ h4x9d.search = u7b3k.searchInput.value; h4x9d.page = 1; m8x1e(true); }); u7b3k.clearSearch.addEventListener("click", ()=>{ u7b3k.searchInput.value = ""; h4x9d.search = ""; h4x9d.page = 1; m8x1e(true); u7b3k.searchInput.focus(); }); u7b3k.categorySelect.addEventListener("change", ()=>{ h4x9d.category = u7b3k.categorySelect.value; h4x9d.page = 1; m8x1e(true); }); u7b3k.levelSelect.addEventListener("change", ()=>{ h4x9d.level = u7b3k.levelSelect.value; h4x9d.page = 1; m8x1e(true); }); u7b3k.sortSelect.addEventListener("change", ()=>{ h4x9d.sort = u7b3k.sortSelect.value; h4x9d.page = 1; m8x1e(true); }); u7b3k.pageSizeSelect.addEventListener("change", ()=>{ h4x9d.pageSize = parseInt(u7b3k.pageSizeSelect.value,10) || 9; h4x9d.page = 1; m8x1e(false); }); u7b3k.toggleFavoritesOnly.addEventListener("click", ()=>{ const next = !h4x9d.favoritesOnly; h4x9d.favoritesOnly = next; u7b3k.toggleFavoritesOnly.setAttribute("aria-pressed", next ? "true" : "false"); h4x9d.page = 1; m8x1e(true); }); u7b3k.toggleInStockOnly.addEventListener("click", ()=>{ const next = !h4x9d.inStockOnly; h4x9d.inStockOnly = next; u7b3k.toggleInStockOnly.setAttribute("aria-pressed", next ? "true" : "false"); h4x9d.page = 1; m8x1e(true); }); const doReset = ()=>{ h4x9d.search = ""; h4x9d.category = ""; h4x9d.level = ""; h4x9d.sort = "relevance"; h4x9d.favoritesOnly = false; h4x9d.inStockOnly = false; h4x9d.page = 1; u7b3k.searchInput.value = ""; u7b3k.categorySelect.value = ""; u7b3k.levelSelect.value = ""; u7b3k.sortSelect.value = "relevance"; u7b3k.toggleFavoritesOnly.setAttribute("aria-pressed","false"); u7b3k.toggleInStockOnly.setAttribute("aria-pressed","false"); m8x1e(true); }; u7b3k.resetFilters.addEventListener("click", doReset); u7b3k.emptyReset.addEventListener("click", doReset); u7b3k.prevPage.addEventListener("click", ()=>{ h4x9d.page = Math.max(1, h4x9d.page-1); m8x1e(false); window.scrollTo({top:0,behavior:"smooth"}); }); u7b3k.nextPage.addEventListener("click", ()=>{ const pages = Math.max(1, Math.ceil(h4x9d.filtered.length / h4x9d.pageSize)); h4x9d.page = Math.min(pages, h4x9d.page+1); m8x1e(false); window.scrollTo({top:0,behavior:"smooth"}); }); u7b3k.retryLoad.addEventListener("click", k4v7j); u7b3k.themeToggle.addEventListener("click", e9v2s); u7b3k.openCart.addEventListener("click", ()=>q0z2p(true)); u7b3k.cartClose.addEventListener("click", ()=>q0z2p(false)); u7b3k.cartClose2.addEventListener("click", ()=>q0z2p(false)); u7b3k.cartOverlay.addEventListener("click", (e)=>{ if(e.target === u7b3k.cartOverlay.firstElementChild) q0z2p(false); }); u7b3k.cartClearAll.addEventListener("click", ()=>{ if(h4x9d.consent!=="accepted"){ v3e1a("Accept cookies to use cart", "warn"); return; } h4x9d.cart = new Map(); m8x1e(false); i3n8d(); v3e1a("Cart cleared", "info"); }); u7b3k.clearCart.addEventListener("click", ()=>{ if(h4x9d.consent!=="accepted"){ v3e1a("Accept cookies to use cart", "warn"); return; } h4x9d.cart = new Map(); m8x1e(false); v3e1a("Cart cleared", "info"); }); u7b3k.clearFavorites.addEventListener("click", ()=>{ if(h4x9d.consent!=="accepted"){ v3e1a("Accept cookies to save favorites", "warn"); return; } h4x9d.favorites = new Set(); m8x1e(false); v3e1a("Favorites cleared", "info"); }); u7b3k.modalClose.addEventListener("click", y7u0f); u7b3k.modalClose2.addEventListener("click", y7u0f); u7b3k.modalOverlay.addEventListener("click", (e)=>{ if(e.target === u7b3k.modalOverlay.firstElementChild) y7u0f(); }); u7b3k.copyLink.addEventListener("click", async ()=>{ const cid = h4x9d.lastOpenCourseId; if(!cid) return; const url = new URL(window.location.href); url.searchParams.set("course", cid); const txt = url.toString(); try{ await navigator.clipboard.writeText(txt); u7b3k.copyState.className = "mt-2 text-xs text-good"; u7b3k.copyState.textContent = "Copied to clipboard."; u7b3k.copyState.classList.remove("hidden"); v3e1a("Link copied", "good", 1600); }catch(e){ u7b3k.copyState.className = "mt-2 text-xs text-bad"; u7b3k.copyState.textContent = "Clipboard unavailable. You can copy from the address bar."; u7b3k.copyState.classList.remove("hidden"); v3e1a("Clipboard blocked", "warn", 2200); } }); u7b3k.checkoutForm.addEventListener("submit", (e)=>{ e.preventDefault(); y2s7c(); }); u7b3k.openHelp.addEventListener("click", ()=>z7r3n(u7b3k.helpOverlay,true)); u7b3k.helpClose.addEventListener("click", ()=>z7r3n(u7b3k.helpOverlay,false)); u7b3k.helpClose2.addEventListener("click", ()=>z7r3n(u7b3k.helpOverlay,false)); u7b3k.helpOverlay.addEventListener("click", (e)=>{ if(e.target === u7b3k.helpOverlay.firstElementChild) z7r3n(u7b3k.helpOverlay,false); }); u7b3k.openContact.addEventListener("click", ()=>z7r3n(u7b3k.contactOverlay,true)); u7b3k.contactClose.addEventListener("click", ()=>z7r3n(u7b3k.contactOverlay,false)); u7b3k.contactCancel.addEventListener("click", ()=>z7r3n(u7b3k.contactOverlay,false)); u7b3k.contactOverlay.addEventListener("click", (e)=>{ if(e.target === u7b3k.contactOverlay.firstElementChild) z7r3n(u7b3k.contactOverlay,false); }); u7b3k.contactForm.addEventListener("submit", async (e)=>{ e.preventDefault(); const errs = []; if(!e1g9m(u7b3k.contactName.value)) errs.push("Enter a valid name (2–80 chars)."); if(!z6k4a(u7b3k.contactEmail.value)) errs.push("Enter a valid email."); if(!l8o2c(u7b3k.contactPhone.value)) errs.push("Enter a valid phone."); if(r4s0e(u7b3k.contactMessage.value).length<10) errs.push("Message must be at least 10 characters."); u7b3k.contactErrors.classList.add("hidden"); u7b3k.contactSuccess.classList.add("hidden"); u7b3k.contactErrors.textContent = ""; u7b3k.contactSuccess.textContent = ""; if(errs.length){ u7b3k.contactErrors.classList.remove("hidden"); u7b3k.contactErrors.textContent = errs.join(" "); v3e1a("Fix contact form errors", "bad"); return; } const btn = u7b3k.contactForm.querySelector("#jsContactSubmit"); btn.disabled = true; const old = btn.textContent; btn.textContent = "Sending…"; await g6v1p(550); btn.disabled = false; btn.textContent = old; u7b3k.contactSuccess.classList.remove("hidden"); u7b3k.contactSuccess.textContent = "Message sent (demo). We’ll reply to your email within 1–2 business days."; v3e1a("Message sent (demo)", "good"); u7b3k.contactMessage.value = ""; }); u7b3k.openTerms.addEventListener("click", ()=>z7r3n(u7b3k.termsOverlay,true)); u7b3k.termsClose.addEventListener("click", ()=>z7r3n(u7b3k.termsOverlay,false)); u7b3k.termsClose2.addEventListener("click", ()=>z7r3n(u7b3k.termsOverlay,false)); u7b3k.termsOverlay.addEventListener("click", (e)=>{ if(e.target === u7b3k.termsOverlay.firstElementChild) z7r3n(u7b3k.termsOverlay,false); }); u7b3k.cookieAccept.addEventListener("click", ()=>c2h8n("accepted")); u7b3k.cookieReject.addEventListener("click", ()=>c2h8n("rejected")); u7b3k.cookieClose.addEventListener("click", ()=>{ n8e2y(u7b3k.cookieBanner, false); }); window.addEventListener("keydown", (e)=>{ if(e.key !== "Escape") return; if(!u7b3k.cartOverlay.classList.contains("hidden")) q0z2p(false); else if(!u7b3k.modalOverlay.classList.contains("hidden")) y7u0f(); else if(!u7b3k.contactOverlay.classList.contains("hidden")) z7r3n(u7b3k.contactOverlay,false); else if(!u7b3k.helpOverlay.classList.contains("hidden")) z7r3n(u7b3k.helpOverlay,false); else if(!u7b3k.termsOverlay.classList.contains("hidden")) z7r3n(u7b3k.termsOverlay,false); }); window.addEventListener("popstate", ()=>{ const deep = new URL(window.location.href).searchParams.get("course"); if(deep){ const exists = h4x9d.all.some(x=>x.id===deep); if(exists) b0e8s(deep, false); }else{ if(!u7b3k.modalOverlay.classList.contains("hidden")) y7u0f(); } }); } function i0r4f(){ t6j1p(); s1k6q(); if(h4x9d.consent==="accepted"){ i4a0t(); }else{ try{ localStorage.removeItem(k9s2b.themeKey); }catch(e){} } t6j1p(); k2u9d(); l0e7x(); x1d9u(); } (async function init(){ t6j1p(); await w0c2t(); s1k6q(); if(h4x9d.consent==="accepted") i4a0t(); else{ try{ localStorage.removeItem(k9s2b.favKey); }catch(e){} try{ localStorage.removeItem(k9s2b.cartKey); }catch(e){} } k2u9d(); l0e7x(); x1d9u(); await k4v7j(); })(); })();