(function () { "use strict"; const { getTarotCardSearchAliases } = window.TarotCardImages || {}; const CLASSICAL_ELEMENT_IDS = ["fire", "water", "air", "earth"]; const ACE_BY_ELEMENT_ID = { water: "Ace of Cups", fire: "Ace of Wands", air: "Ace of Swords", earth: "Ace of Disks" }; const HEBREW_LETTER_NAME_BY_ELEMENT_ID = { fire: "Yod", water: "Heh", air: "Vav", earth: "Heh" }; const HEBREW_LETTER_CHAR_BY_ELEMENT_ID = { fire: "י", water: "ה", air: "ו", earth: "ה" }; const COURT_RANK_BY_ELEMENT_ID = { fire: "Knight", water: "Queen", air: "Prince", earth: "Princess" }; const COURT_SUITS = ["Wands", "Cups", "Swords", "Disks"]; const SUIT_BY_ELEMENT_ID = { fire: "Wands", water: "Cups", air: "Swords", earth: "Disks" }; const SMALL_CARD_GROUPS = [ { label: "2–4", modality: "Cardinal", numbers: [2, 3, 4] }, { label: "5–7", modality: "Fixed", numbers: [5, 6, 7] }, { label: "8–10", modality: "Mutable", numbers: [8, 9, 10] } ]; const SIGN_BY_ELEMENT_AND_MODALITY = { fire: { cardinal: "aries", fixed: "leo", mutable: "sagittarius" }, water: { cardinal: "cancer", fixed: "scorpio", mutable: "pisces" }, air: { cardinal: "libra", fixed: "aquarius", mutable: "gemini" }, earth: { cardinal: "capricorn", fixed: "taurus", mutable: "virgo" } }; const state = { initialized: false, entries: [], filteredEntries: [], selectedId: "", searchQuery: "" }; function getElements() { return { listEl: document.getElementById("elements-list"), countEl: document.getElementById("elements-count"), searchEl: document.getElementById("elements-search-input"), searchClearEl: document.getElementById("elements-search-clear"), detailNameEl: document.getElementById("elements-detail-name"), detailSubEl: document.getElementById("elements-detail-sub"), detailBodyEl: document.getElementById("elements-detail-body") }; } function normalize(value) { return String(value || "") .trim() .toLowerCase() .replace(/\s+/g, " "); } function titleCase(value) { return String(value || "") .split(" ") .filter(Boolean) .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join(" "); } function buildTarotAliasText(cardNames) { if (typeof getTarotCardSearchAliases !== "function") { return Array.isArray(cardNames) ? cardNames.join(" ") : ""; } const aliases = new Set(); (Array.isArray(cardNames) ? cardNames : []).forEach((cardName) => { getTarotCardSearchAliases(cardName).forEach((alias) => aliases.add(alias)); }); return Array.from(aliases).join(" "); } function buildSmallCardGroupsForElement(elementId) { const suit = SUIT_BY_ELEMENT_ID[elementId] || ""; const signByModality = SIGN_BY_ELEMENT_AND_MODALITY[elementId] || {}; return SMALL_CARD_GROUPS.map((group) => { const signId = String(signByModality[String(group.modality || "").toLowerCase()] || "").trim(); const signName = titleCase(signId); const cardNames = group.numbers.map((number) => `${number} of ${suit}`); return { rangeLabel: group.label, modality: group.modality, signId, signName, cardNames }; }); } function buildEntries(magickDataset) { const source = magickDataset?.grouped?.alchemy?.elements; if (!source || typeof source !== "object") { return []; } return CLASSICAL_ELEMENT_IDS .map((id) => { const item = source[id]; if (!item || typeof item !== "object") { return null; } const name = String(item?.name?.en || item?.name || titleCase(id)).trim() || titleCase(id); const symbol = String(item?.symbol || "").trim(); const aceCardName = ACE_BY_ELEMENT_ID[id] || ""; const hebrewLetter = HEBREW_LETTER_CHAR_BY_ELEMENT_ID[id] || ""; const hebrewLetterName = HEBREW_LETTER_NAME_BY_ELEMENT_ID[id] || ""; const courtRank = COURT_RANK_BY_ELEMENT_ID[id] || ""; const courtCardNames = courtRank ? COURT_SUITS.map((suit) => `${courtRank} of ${suit}`) : []; const smallCardGroups = buildSmallCardGroupsForElement(id); const smallCardNames = smallCardGroups.flatMap((group) => group.cardNames || []); const tarotAliasText = buildTarotAliasText([aceCardName, ...courtCardNames, ...smallCardNames]); return { id, name, symbol, elementalId: String(item?.elementalId || "").trim(), aceCardName, hebrewLetter, hebrewLetterName, courtRank, courtCardNames, smallCardGroups, searchText: normalize(`${id} ${name} ${symbol} ${aceCardName} ${hebrewLetter} ${hebrewLetterName} ${courtRank} ${courtCardNames.join(" ")} ${smallCardGroups.map((group) => `${group.modality} ${group.signName} ${group.cardNames.join(" ")}`).join(" ")} ${tarotAliasText}`) }; }) .filter(Boolean); } function findEntryById(id) { const normalizedId = normalize(id); return state.entries.find((entry) => entry.id === normalizedId) || null; } function renderList(elements) { if (!elements?.listEl) { return; } elements.listEl.replaceChildren(); state.filteredEntries.forEach((entry) => { const button = document.createElement("button"); button.type = "button"; button.className = "planet-list-item"; button.dataset.elementId = entry.id; button.setAttribute("role", "option"); const isSelected = entry.id === state.selectedId; button.classList.toggle("is-selected", isSelected); button.setAttribute("aria-selected", isSelected ? "true" : "false"); const name = document.createElement("span"); name.className = "planet-list-name"; name.textContent = `${entry.symbol} ${entry.name}`.trim(); const meta = document.createElement("span"); meta.className = "planet-list-meta"; meta.textContent = `Letter: ${entry.hebrewLetter || "--"} · Ace: ${entry.aceCardName || "--"} · Court: ${entry.courtRank || "--"}`; button.append(name, meta); elements.listEl.appendChild(button); }); if (elements.countEl) { elements.countEl.textContent = `${state.filteredEntries.length} elements`; } if (!state.filteredEntries.length) { const empty = document.createElement("div"); empty.className = "planet-text"; empty.style.padding = "16px"; empty.style.color = "#71717a"; empty.textContent = "No elements match your search."; elements.listEl.appendChild(empty); } } function renderDetail(elements) { if (!elements?.detailNameEl || !elements.detailSubEl || !elements.detailBodyEl) { return; } const entry = findEntryById(state.selectedId); elements.detailBodyEl.replaceChildren(); if (!entry) { elements.detailNameEl.textContent = "--"; elements.detailSubEl.textContent = "Select an element to explore"; return; } elements.detailNameEl.textContent = `${entry.symbol} ${entry.name}`.trim(); elements.detailSubEl.textContent = "Classical Element"; const grid = document.createElement("div"); grid.className = "planet-meta-grid"; const detailsCard = document.createElement("div"); detailsCard.className = "planet-meta-card"; detailsCard.innerHTML = ` Element Details
Name
${entry.name}
Symbol
${entry.symbol || "--"}
Hebrew Letter
${entry.hebrewLetter || "--"}
Court Rank
${entry.courtRank || "--"}
ID
${entry.id}
`; const tarotCard = document.createElement("div"); tarotCard.className = "planet-meta-card"; const tarotTitle = document.createElement("strong"); tarotTitle.textContent = "Tarot Correspondence"; const tarotText = document.createElement("div"); tarotText.className = "planet-text"; tarotText.textContent = [ entry.aceCardName ? `Ace: ${entry.aceCardName}` : "", entry.courtRank ? `Court Rank: ${entry.courtRank} (all suits)` : "" ].filter(Boolean).join(" · ") || "--"; tarotCard.append(tarotTitle, tarotText); if (entry.aceCardName || entry.courtCardNames.length) { const navWrap = document.createElement("div"); navWrap.className = "alpha-nav-btns"; if (entry.aceCardName) { const tarotBtn = document.createElement("button"); tarotBtn.type = "button"; tarotBtn.className = "alpha-nav-btn"; tarotBtn.textContent = `Open ${entry.aceCardName} ↗`; tarotBtn.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:tarot-trump", { detail: { cardName: entry.aceCardName } })); }); navWrap.appendChild(tarotBtn); } entry.courtCardNames.forEach((cardName) => { const courtBtn = document.createElement("button"); courtBtn.type = "button"; courtBtn.className = "alpha-nav-btn"; courtBtn.textContent = `Open ${cardName} ↗`; courtBtn.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:tarot-trump", { detail: { cardName } })); }); navWrap.appendChild(courtBtn); }); tarotCard.appendChild(navWrap); } const smallCardCard = document.createElement("div"); smallCardCard.className = "planet-meta-card"; const smallCardTitle = document.createElement("strong"); smallCardTitle.textContent = "Small Card Sign Types"; smallCardCard.appendChild(smallCardTitle); const smallCardStack = document.createElement("div"); smallCardStack.className = "cal-item-stack"; (entry.smallCardGroups || []).forEach((group) => { const row = document.createElement("div"); row.className = "cal-item-row"; const head = document.createElement("div"); head.className = "cal-item-head"; head.innerHTML = ` ${group.rangeLabel} · ${group.modality} ${group.signName || "--"} `; row.appendChild(head); const navWrap = document.createElement("div"); navWrap.className = "alpha-nav-btns"; if (group.signId) { const signBtn = document.createElement("button"); signBtn.type = "button"; signBtn.className = "alpha-nav-btn"; signBtn.textContent = `Open ${group.signName} ↗`; signBtn.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:zodiac", { detail: { signId: group.signId } })); }); navWrap.appendChild(signBtn); } (group.cardNames || []).forEach((cardName) => { const cardBtn = document.createElement("button"); cardBtn.type = "button"; cardBtn.className = "alpha-nav-btn"; cardBtn.textContent = `Open ${cardName} ↗`; cardBtn.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:tarot-trump", { detail: { cardName } })); }); navWrap.appendChild(cardBtn); }); row.appendChild(navWrap); smallCardStack.appendChild(row); }); smallCardCard.appendChild(smallCardStack); grid.append(detailsCard, tarotCard, smallCardCard); elements.detailBodyEl.appendChild(grid); } function applyFilter(elements) { const query = normalize(state.searchQuery); state.filteredEntries = query ? state.entries.filter((entry) => entry.searchText.includes(query)) : [...state.entries]; if (elements?.searchClearEl) { elements.searchClearEl.disabled = !query; } if (!state.filteredEntries.some((entry) => entry.id === state.selectedId)) { state.selectedId = state.filteredEntries[0]?.id || ""; } renderList(elements); renderDetail(elements); } function selectByElementId(elementId) { const target = findEntryById(elementId); if (!target) { return false; } const elements = getElements(); state.selectedId = target.id; renderList(elements); renderDetail(elements); const listItem = elements.listEl?.querySelector(`[data-element-id="${target.id}"]`); listItem?.scrollIntoView({ block: "nearest" }); return true; } function ensureElementsSection(magickDataset) { const elements = getElements(); if (!elements.listEl || !elements.detailBodyEl) { return; } state.entries = buildEntries(magickDataset); if (!state.selectedId && state.entries.length) { state.selectedId = state.entries[0].id; } applyFilter(elements); if (state.initialized) { return; } elements.listEl.addEventListener("click", (event) => { const target = event.target instanceof Element ? event.target.closest(".planet-list-item") : null; if (!(target instanceof HTMLButtonElement)) { return; } const elementId = target.dataset.elementId; if (!elementId) { return; } state.selectedId = elementId; renderList(elements); renderDetail(elements); }); if (elements.searchEl) { elements.searchEl.addEventListener("input", () => { state.searchQuery = elements.searchEl.value || ""; applyFilter(elements); }); } if (elements.searchClearEl && elements.searchEl) { elements.searchClearEl.addEventListener("click", () => { state.searchQuery = ""; elements.searchEl.value = ""; applyFilter(elements); elements.searchEl.focus(); }); } state.initialized = true; } window.ElementsSectionUi = { ensureElementsSection, selectByElementId }; })();