Orvique Meridian

The Meridian library

Courses for a calmer trading process.

Browse focused lessons designed for study, practice, and review. Course material is educational and does not promise financial outcomes.

Market weather: Measured pace. Focus on structure over speed. Suitable for deliberate daily study.
View tracked
Loading the Meridian library…
`; document.getElementById('site-footer').innerHTML = ``; let products = [], filtered = [], page = 1; const perPage = 6; const tracked = () => JSON.parse(localStorage.getItem('trackedCourseIds') || '[]'); const saveTracked = x => localStorage.setItem('trackedCourseIds', JSON.stringify(x)); const cart = () => JSON.parse(localStorage.getItem('cartItems') || '[]'); const saveCart = x => localStorage.setItem('cartItems', JSON.stringify(x)); const search = document.getElementById('search'); const category = document.getElementById('category'); const statusEl = document.getElementById('catalog-status'); const grid = document.getElementById('course-grid'); const pagination = document.getElementById('pagination'); const detailModal = document.getElementById('detail-modal'); const modalTitle = document.getElementById('modal-title'); const modalContent = document.getElementById('modal-content'); const closeDetail = document.getElementById('close-detail'); function applyFilters() { const q = (search.value || '').toLowerCase().trim(); const cat = category.value; filtered = products.filter(p => { const matchesQ = !q || p.title.toLowerCase().includes(q) || p.summary.toLowerCase().includes(q); const matchesCat = cat === 'all' || p.category === cat; return matchesQ && matchesCat; }); page = 1; render(); } function render() { statusEl.textContent = ''; grid.innerHTML = ''; pagination.innerHTML = ''; if (!filtered.length) { grid.innerHTML = '

No courses match your current filters.

'; return; } const start = (page - 1) * perPage; const pageItems = filtered.slice(start, start + perPage); pageItems.forEach(course => { const card = document.createElement('div'); card.className = 'rounded-3xl border border-slate-200 bg-white p-6 flex flex-col dd23l'; card.innerHTML = `
${course.category}${course.level}

${course.title}

${course.summary}

${course.price} ${course.currency}
${course.duration}
`; card.querySelector('[data-action="details"]').onclick = () => openModal(course); card.querySelector('[data-action="track"]').onclick = () => { const t = tracked(); if (!t.includes(course.id)) { t.push(course.id); saveTracked(t); card.querySelector('[data-action="track"]').textContent = 'Tracked'; card.querySelector('[data-action="track"]').disabled = true; } }; if (tracked().includes(course.id)) { const b = card.querySelector('[data-action="track"]'); b.textContent = 'Tracked'; b.disabled = true; } grid.appendChild(card); }); const totalPages = Math.ceil(filtered.length / perPage); for (let i = 1; i <= totalPages; i++) { const btn = document.createElement('a'); btn.href = '#'; btn.className = `px-4 py-2 rounded-full text-sm border ${i === page ? 'border-slate-900 bg-slate-900 text-white' : 'border-slate-300 hover:border-sky-700'}`; btn.textContent = i; btn.onclick = (e) => { e.preventDefault(); page = i; render(); }; pagination.appendChild(btn); } } function openModal(course) { modalTitle.textContent = course.title; const outcomesHTML = course.outcomes.map(o => `
  • • ${o}
  • `).join(''); const modulesHTML = course.modules.map(m => `
  • • ${m}
  • `).join(''); modalContent.innerHTML = `
    ${course.format} • ${course.duration}

    ${course.description}

    Learning outcomes
    Modules included
    Add to tracked
    `; document.getElementById('add-cart').onclick = () => { const c = cart(); const idx = c.findIndex(i => i.id === course.id); if (idx > -1) c[idx].quantity++; else c.push({id: course.id, quantity: 1}); saveCart(c); document.getElementById('add-cart').textContent = 'Added to cart'; setTimeout(() => { detailModal.classList.remove('flex'); detailModal.classList.add('hidden'); window.location.href = './cart.html'; }, 650); }; detailModal.classList.remove('hidden'); detailModal.classList.add('flex'); } closeDetail.onclick = () => { detailModal.classList.remove('flex'); detailModal.classList.add('hidden'); }; detailModal.onclick = e => { if (e.target === detailModal) { detailModal.classList.remove('flex'); detailModal.classList.add('hidden'); } }; search.oninput = applyFilters; category.onchange = applyFilters; async function init() { try { products = await (await fetch('./catalog.json')).json(); const cats = [...new Set(products.map(x => x.category))]; category.innerHTML = '' + cats.map(x => ``).join(''); filtered = [...products]; statusEl.textContent = ''; render(); const authButtons = document.querySelectorAll('[data-auth]'); const authModal = document.querySelector('#auth-modal'); const authTitle = document.querySelector('#auth-title'); const authClose = document.querySelector('#auth-close'); authButtons.forEach(btn => { btn.onclick = () => { authTitle.textContent = btn.dataset.auth === 'sign in' ? 'Sign in to Orvique Meridian' : 'Register with Orvique Meridian'; authModal.classList.remove('hidden'); authModal.classList.add('flex'); }; }); authClose.onclick = () => { authModal.classList.remove('flex'); authModal.classList.add('hidden'); }; const themeBtn = document.querySelector('#theme-toggle'); themeBtn.onclick = () => { document.body.classList.toggle('bg-slate-950'); document.body.classList.toggle('text-white'); localStorage.setItem('theme', document.body.classList.contains('bg-slate-950') ? 'dark' : 'light'); }; if (localStorage.getItem('theme') === 'dark') { document.body.classList.add('bg-slate-950', 'text-white'); } const mobileBtn = document.querySelector('#mobile-nav'); const mobileMenu = document.querySelector('#mobile-menu'); mobileBtn.onclick = () => { mobileMenu.classList.toggle('hidden'); }; const cb = document.querySelector('#cookie-banner'); if (localStorage.getItem('cookiesAccepted') === 'yes' && cb) cb.remove(); document.querySelector('#accept-cookies')?.addEventListener('click', () => { localStorage.setItem('cookiesAccepted', 'yes'); if (cb) cb.remove(); }); } catch (e) { statusEl.textContent = 'The catalog could not be loaded. Please try again later.'; } } init();