(function () { "use strict"; let initialized = false; let activeNumberValue = 0; let config = { getReferenceData: () => null, getMagickDataset: () => null, ensureTarotSection: null }; const NUMBERS_SPECIAL_BASE_VALUES = [1, 2, 3, 4]; const numbersSpecialFlipState = new Map(); const DEFAULT_NUMBER_ENTRIES = Array.from({ length: 10 }, (_, value) => ({ value, label: `${value}`, opposite: 9 - value, digitalRoot: value, summary: "", keywords: [], associations: { kabbalahNode: value === 0 ? 10 : value, playingSuit: "hearts" } })); const PLAYING_SUIT_SYMBOL = { hearts: "♥", diamonds: "♦", clubs: "♣", spades: "♠" }; const PLAYING_SUIT_LABEL = { hearts: "Hearts", diamonds: "Diamonds", clubs: "Clubs", spades: "Spades" }; const PLAYING_SUIT_TO_TAROT = { hearts: "Cups", diamonds: "Pentacles", clubs: "Wands", spades: "Swords" }; const PLAYING_RANKS = [ { rank: "A", rankLabel: "Ace", rankValue: 1 }, { rank: "2", rankLabel: "Two", rankValue: 2 }, { rank: "3", rankLabel: "Three", rankValue: 3 }, { rank: "4", rankLabel: "Four", rankValue: 4 }, { rank: "5", rankLabel: "Five", rankValue: 5 }, { rank: "6", rankLabel: "Six", rankValue: 6 }, { rank: "7", rankLabel: "Seven", rankValue: 7 }, { rank: "8", rankLabel: "Eight", rankValue: 8 }, { rank: "9", rankLabel: "Nine", rankValue: 9 }, { rank: "10", rankLabel: "Ten", rankValue: 10 }, { rank: "J", rankLabel: "Jack", rankValue: null }, { rank: "Q", rankLabel: "Queen", rankValue: null }, { rank: "K", rankLabel: "King", rankValue: null } ]; const TAROT_RANK_NUMBER_MAP = { ace: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7, eight: 8, nine: 9, ten: 10 }; function getReferenceData() { return typeof config.getReferenceData === "function" ? config.getReferenceData() : null; } function getMagickDataset() { return typeof config.getMagickDataset === "function" ? config.getMagickDataset() : null; } function getElements() { return { countEl: document.getElementById("numbers-count"), listEl: document.getElementById("numbers-list"), detailNameEl: document.getElementById("numbers-detail-name"), detailTypeEl: document.getElementById("numbers-detail-type"), detailSummaryEl: document.getElementById("numbers-detail-summary"), detailBodyEl: document.getElementById("numbers-detail-body"), specialPanelEl: document.getElementById("numbers-special-panel") }; } function normalizeNumberValue(value) { const parsed = Number(value); if (!Number.isFinite(parsed)) { return 0; } const normalized = Math.trunc(parsed); if (normalized < 0) { return 0; } if (normalized > 9) { return 9; } return normalized; } function normalizeNumberEntry(rawEntry) { if (!rawEntry || typeof rawEntry !== "object") { return null; } const value = normalizeNumberValue(rawEntry.value); const oppositeRaw = Number(rawEntry.opposite); const opposite = Number.isFinite(oppositeRaw) ? normalizeNumberValue(oppositeRaw) : (9 - value); const digitalRootRaw = Number(rawEntry.digitalRoot); const digitalRoot = Number.isFinite(digitalRootRaw) ? normalizeNumberValue(digitalRootRaw) : value; const kabbalahNodeRaw = Number(rawEntry?.associations?.kabbalahNode); const kabbalahNode = Number.isFinite(kabbalahNodeRaw) ? Math.max(1, Math.trunc(kabbalahNodeRaw)) : (value === 0 ? 10 : value); const tarotTrumpNumbersRaw = Array.isArray(rawEntry?.associations?.tarotTrumpNumbers) ? rawEntry.associations.tarotTrumpNumbers : []; const tarotTrumpNumbers = Array.from(new Set( tarotTrumpNumbersRaw .map((item) => Number(item)) .filter((item) => Number.isFinite(item)) .map((item) => Math.trunc(item)) )); const playingSuitRaw = String(rawEntry?.associations?.playingSuit || "").trim().toLowerCase(); const playingSuit = ["hearts", "diamonds", "clubs", "spades"].includes(playingSuitRaw) ? playingSuitRaw : "hearts"; return { value, label: String(rawEntry.label || value), opposite, digitalRoot, summary: String(rawEntry.summary || ""), keywords: Array.isArray(rawEntry.keywords) ? rawEntry.keywords.map((keyword) => String(keyword || "").trim()).filter(Boolean) : [], associations: { kabbalahNode, tarotTrumpNumbers, playingSuit } }; } function getNumbersDatasetEntries() { const numbersData = getMagickDataset()?.grouped?.numbers; const rawEntries = Array.isArray(numbersData) ? numbersData : (Array.isArray(numbersData?.entries) ? numbersData.entries : []); const normalizedEntries = rawEntries .map((entry) => normalizeNumberEntry(entry)) .filter(Boolean) .sort((left, right) => left.value - right.value); return normalizedEntries.length ? normalizedEntries : DEFAULT_NUMBER_ENTRIES; } function getNumberEntryByValue(value) { const entries = getNumbersDatasetEntries(); const normalized = normalizeNumberValue(value); return entries.find((entry) => entry.value === normalized) || entries[0] || null; } function computeDigitalRoot(value) { let current = Math.abs(Math.trunc(Number(value))); if (!Number.isFinite(current)) { return null; } while (current >= 10) { current = String(current) .split("") .reduce((sum, digit) => sum + Number(digit), 0); } return current; } function getCalendarMonthLinksForNumber(value) { const referenceData = getReferenceData(); const normalized = normalizeNumberValue(value); const calendarGroups = [ { calendarId: "gregorian", calendarLabel: "Gregorian", months: Array.isArray(referenceData?.calendarMonths) ? referenceData.calendarMonths : [] }, { calendarId: "hebrew", calendarLabel: "Hebrew", months: Array.isArray(referenceData?.hebrewCalendar?.months) ? referenceData.hebrewCalendar.months : [] }, { calendarId: "islamic", calendarLabel: "Islamic", months: Array.isArray(referenceData?.islamicCalendar?.months) ? referenceData.islamicCalendar.months : [] }, { calendarId: "wheel-of-year", calendarLabel: "Wheel of the Year", months: Array.isArray(referenceData?.wheelOfYear?.months) ? referenceData.wheelOfYear.months : [] } ]; const links = []; calendarGroups.forEach((group) => { group.months.forEach((month) => { const monthOrder = Number(month?.order); const normalizedOrder = Number.isFinite(monthOrder) ? Math.trunc(monthOrder) : null; const monthRoot = normalizedOrder != null ? computeDigitalRoot(normalizedOrder) : null; if (monthRoot !== normalized) { return; } links.push({ calendarId: group.calendarId, calendarLabel: group.calendarLabel, monthId: String(month.id || "").trim(), monthName: String(month.name || month.id || "Month").trim(), monthOrder: normalizedOrder }); }); }); return links.filter((link) => link.monthId); } function rankLabelToTarotMinorRank(rankLabel) { const key = String(rankLabel || "").trim().toLowerCase(); if (key === "10" || key === "ten") return "Princess"; if (key === "j" || key === "jack") return "Prince"; if (key === "q" || key === "queen") return "Queen"; if (key === "k" || key === "king") return "Knight"; return String(rankLabel || "").trim(); } function buildFallbackPlayingDeckEntries() { const entries = []; Object.keys(PLAYING_SUIT_SYMBOL).forEach((suit) => { PLAYING_RANKS.forEach((rank) => { const tarotSuit = PLAYING_SUIT_TO_TAROT[suit]; const tarotRank = rankLabelToTarotMinorRank(rank.rankLabel); entries.push({ id: `${rank.rank}${PLAYING_SUIT_SYMBOL[suit]}`, suit, suitLabel: PLAYING_SUIT_LABEL[suit], suitSymbol: PLAYING_SUIT_SYMBOL[suit], rank: rank.rank, rankLabel: rank.rankLabel, rankValue: rank.rankValue, tarotSuit, tarotCard: `${tarotRank} of ${tarotSuit}` }); }); }); return entries; } function getPlayingDeckEntries() { const deckData = getMagickDataset()?.grouped?.["playing-cards-52"]; const rawEntries = Array.isArray(deckData) ? deckData : (Array.isArray(deckData?.entries) ? deckData.entries : []); if (!rawEntries.length) { return buildFallbackPlayingDeckEntries(); } return rawEntries .map((entry) => { const suit = String(entry?.suit || "").trim().toLowerCase(); const rankLabel = String(entry?.rankLabel || "").trim(); const rank = String(entry?.rank || "").trim(); if (!suit || !rank) { return null; } const suitSymbol = String(entry?.suitSymbol || PLAYING_SUIT_SYMBOL[suit] || "").trim(); const tarotSuit = String(entry?.tarotSuit || PLAYING_SUIT_TO_TAROT[suit] || "").trim(); const tarotCard = String(entry?.tarotCard || "").trim(); const rankValueRaw = Number(entry?.rankValue); const rankValue = Number.isFinite(rankValueRaw) ? Math.trunc(rankValueRaw) : null; return { id: String(entry?.id || `${rank}${suitSymbol}`).trim(), suit, suitLabel: String(entry?.suitLabel || PLAYING_SUIT_LABEL[suit] || suit).trim(), suitSymbol, rank, rankLabel: rankLabel || rank, rankValue, tarotSuit, tarotCard: tarotCard || `${rankLabelToTarotMinorRank(rankLabel || rank)} of ${tarotSuit}` }; }) .filter(Boolean); } function findPlayingCardBySuitAndValue(entries, suit, value) { const normalizedSuit = String(suit || "").trim().toLowerCase(); const targetValue = Number(value); return entries.find((entry) => entry.suit === normalizedSuit && Number(entry.rankValue) === targetValue) || null; } function buildNumbersSpecialCardSlots(playingSuit) { const suit = String(playingSuit || "hearts").trim().toLowerCase(); const selectedSuit = ["hearts", "diamonds", "clubs", "spades"].includes(suit) ? suit : "hearts"; const deckEntries = getPlayingDeckEntries(); const cardEl = document.createElement("div"); cardEl.className = "numbers-detail-card numbers-special-card-section"; const headingEl = document.createElement("strong"); headingEl.textContent = "4 Card Arrangement"; const subEl = document.createElement("div"); subEl.className = "numbers-detail-text numbers-detail-text--muted"; subEl.textContent = `Click a card to flip to its opposite (${PLAYING_SUIT_LABEL[selectedSuit]} ↔ ${PLAYING_SUIT_TO_TAROT[selectedSuit]}).`; const boardEl = document.createElement("div"); boardEl.className = "numbers-special-board"; NUMBERS_SPECIAL_BASE_VALUES.forEach((baseValue) => { const oppositeValue = 9 - baseValue; const frontCard = findPlayingCardBySuitAndValue(deckEntries, selectedSuit, baseValue); const backCard = findPlayingCardBySuitAndValue(deckEntries, selectedSuit, oppositeValue); if (!frontCard || !backCard) { return; } const slotKey = `${selectedSuit}:${baseValue}`; const isFlipped = Boolean(numbersSpecialFlipState.get(slotKey)); const faceBtn = document.createElement("button"); faceBtn.type = "button"; faceBtn.className = `numbers-special-card${isFlipped ? " is-flipped" : ""}`; faceBtn.setAttribute("aria-pressed", isFlipped ? "true" : "false"); faceBtn.setAttribute("aria-label", `${frontCard.rankLabel} of ${frontCard.suitLabel}. Click to flip to ${backCard.rankLabel}.`); faceBtn.dataset.suit = selectedSuit; const innerEl = document.createElement("div"); innerEl.className = "numbers-special-card-inner"; const frontFaceEl = document.createElement("div"); frontFaceEl.className = "numbers-special-card-face numbers-special-card-face--front"; const frontRankEl = document.createElement("div"); frontRankEl.className = "numbers-special-card-rank"; frontRankEl.textContent = frontCard.rankLabel; const frontSuitEl = document.createElement("div"); frontSuitEl.className = "numbers-special-card-suit"; frontSuitEl.textContent = frontCard.suitSymbol; const frontMetaEl = document.createElement("div"); frontMetaEl.className = "numbers-special-card-meta"; frontMetaEl.textContent = frontCard.tarotCard; frontFaceEl.append(frontRankEl, frontSuitEl, frontMetaEl); const backFaceEl = document.createElement("div"); backFaceEl.className = "numbers-special-card-face numbers-special-card-face--back"; const backTagEl = document.createElement("div"); backTagEl.className = "numbers-special-card-tag"; backTagEl.textContent = "Opposite"; const backRankEl = document.createElement("div"); backRankEl.className = "numbers-special-card-rank"; backRankEl.textContent = backCard.rankLabel; const backSuitEl = document.createElement("div"); backSuitEl.className = "numbers-special-card-suit"; backSuitEl.textContent = backCard.suitSymbol; const backMetaEl = document.createElement("div"); backMetaEl.className = "numbers-special-card-meta"; backMetaEl.textContent = backCard.tarotCard; backFaceEl.append(backTagEl, backRankEl, backSuitEl, backMetaEl); innerEl.append(frontFaceEl, backFaceEl); faceBtn.append(innerEl); faceBtn.addEventListener("click", () => { const next = !Boolean(numbersSpecialFlipState.get(slotKey)); numbersSpecialFlipState.set(slotKey, next); faceBtn.classList.toggle("is-flipped", next); faceBtn.setAttribute("aria-pressed", next ? "true" : "false"); }); boardEl.appendChild(faceBtn); }); if (!boardEl.childElementCount) { const emptyEl = document.createElement("div"); emptyEl.className = "numbers-detail-text numbers-detail-text--muted"; emptyEl.textContent = "No card slots available for this mapping yet."; boardEl.appendChild(emptyEl); } cardEl.append(headingEl, subEl, boardEl); return cardEl; } function renderNumbersSpecialPanel(value) { const { specialPanelEl } = getElements(); if (!specialPanelEl) { return; } const entry = getNumberEntryByValue(value); const playingSuit = entry?.associations?.playingSuit || "hearts"; const boardCardEl = buildNumbersSpecialCardSlots(playingSuit); specialPanelEl.replaceChildren(boardCardEl); } function parseTarotCardNumber(rawValue) { if (typeof rawValue === "number") { return Number.isFinite(rawValue) ? Math.trunc(rawValue) : null; } if (typeof rawValue === "string") { const trimmed = rawValue.trim(); if (!trimmed || !/^-?\d+$/.test(trimmed)) { return null; } return Number(trimmed); } return null; } function extractTarotCardNumericValue(card) { const directNumber = parseTarotCardNumber(card?.number); if (directNumber !== null) { return directNumber; } const rankKey = String(card?.rank || "").trim().toLowerCase(); if (Object.prototype.hasOwnProperty.call(TAROT_RANK_NUMBER_MAP, rankKey)) { return TAROT_RANK_NUMBER_MAP[rankKey]; } const numerologyRelation = Array.isArray(card?.relations) ? card.relations.find((relation) => String(relation?.type || "").trim().toLowerCase() === "numerology") : null; const relationValue = Number(numerologyRelation?.data?.value); if (Number.isFinite(relationValue)) { return Math.trunc(relationValue); } return null; } function getAlphabetPositionLinksForDigitalRoot(targetRoot) { const alphabets = getMagickDataset()?.grouped?.alphabets; if (!alphabets || typeof alphabets !== "object") { return []; } const links = []; const addLink = (alphabetLabel, entry, buttonLabel, detail) => { const index = Number(entry?.index); if (!Number.isFinite(index)) { return; } const normalizedIndex = Math.trunc(index); if (computeDigitalRoot(normalizedIndex) !== targetRoot) { return; } links.push({ alphabet: alphabetLabel, index: normalizedIndex, label: buttonLabel, detail }); }; const toTitle = (value) => String(value || "") .trim() .replace(/[_-]+/g, " ") .replace(/\s+/g, " ") .toLowerCase() .replace(/\b([a-z])/g, (match, ch) => ch.toUpperCase()); const englishEntries = Array.isArray(alphabets.english) ? alphabets.english : []; englishEntries.forEach((entry) => { const letter = String(entry?.letter || "").trim(); if (!letter) { return; } addLink( "English", entry, `${letter}`, { alphabet: "english", englishLetter: letter } ); }); const greekEntries = Array.isArray(alphabets.greek) ? alphabets.greek : []; greekEntries.forEach((entry) => { const greekName = String(entry?.name || "").trim(); if (!greekName) { return; } const glyph = String(entry?.char || "").trim(); const displayName = String(entry?.displayName || toTitle(greekName)).trim(); addLink( "Greek", entry, glyph ? `${displayName} - ${glyph}` : displayName, { alphabet: "greek", greekName } ); }); const hebrewEntries = Array.isArray(alphabets.hebrew) ? alphabets.hebrew : []; hebrewEntries.forEach((entry) => { const hebrewLetterId = String(entry?.hebrewLetterId || "").trim(); if (!hebrewLetterId) { return; } const glyph = String(entry?.char || "").trim(); const name = String(entry?.name || hebrewLetterId).trim(); const displayName = toTitle(name); addLink( "Hebrew", entry, glyph ? `${displayName} - ${glyph}` : displayName, { alphabet: "hebrew", hebrewLetterId } ); }); const arabicEntries = Array.isArray(alphabets.arabic) ? alphabets.arabic : []; arabicEntries.forEach((entry) => { const arabicName = String(entry?.name || "").trim(); if (!arabicName) { return; } const glyph = String(entry?.char || "").trim(); const displayName = toTitle(arabicName); addLink( "Arabic", entry, glyph ? `${displayName} - ${glyph}` : displayName, { alphabet: "arabic", arabicName } ); }); const enochianEntries = Array.isArray(alphabets.enochian) ? alphabets.enochian : []; enochianEntries.forEach((entry) => { const enochianId = String(entry?.id || "").trim(); if (!enochianId) { return; } const title = String(entry?.title || enochianId).trim(); const displayName = toTitle(title); addLink( "Enochian", entry, `${displayName}`, { alphabet: "enochian", enochianId } ); }); return links.sort((left, right) => { if (left.index !== right.index) { return left.index - right.index; } const alphabetCompare = left.alphabet.localeCompare(right.alphabet); if (alphabetCompare !== 0) { return alphabetCompare; } return left.label.localeCompare(right.label); }); } function getTarotCardsForDigitalRoot(targetRoot, numberEntry = null) { const referenceData = getReferenceData(); const magickDataset = getMagickDataset(); if (typeof config.ensureTarotSection === "function" && referenceData) { config.ensureTarotSection(referenceData, magickDataset); } const allCards = window.TarotSectionUi?.getCards?.() || []; const explicitTrumpNumbers = Array.isArray(numberEntry?.associations?.tarotTrumpNumbers) ? numberEntry.associations.tarotTrumpNumbers .map((value) => Number(value)) .filter((value) => Number.isFinite(value)) .map((value) => Math.trunc(value)) : []; const filteredCards = explicitTrumpNumbers.length ? allCards.filter((card) => { const numberValue = parseTarotCardNumber(card?.number); return card?.arcana === "Major" && numberValue !== null && explicitTrumpNumbers.includes(numberValue); }) : allCards.filter((card) => { const numberValue = extractTarotCardNumericValue(card); return numberValue !== null && computeDigitalRoot(numberValue) === targetRoot; }); return filteredCards .sort((left, right) => { const leftNumber = extractTarotCardNumericValue(left); const rightNumber = extractTarotCardNumericValue(right); if (leftNumber !== rightNumber) { return (leftNumber ?? 0) - (rightNumber ?? 0); } if (left?.arcana !== right?.arcana) { return left?.arcana === "Major" ? -1 : 1; } return String(left?.name || "").localeCompare(String(right?.name || "")); }); } function renderNumbersList() { const { listEl, countEl } = getElements(); if (!listEl) { return; } const entries = getNumbersDatasetEntries(); if (!entries.some((entry) => entry.value === activeNumberValue)) { activeNumberValue = entries[0]?.value ?? 0; } const fragment = document.createDocumentFragment(); entries.forEach((entry) => { const button = document.createElement("button"); button.type = "button"; button.className = `planet-list-item${entry.value === activeNumberValue ? " is-selected" : ""}`; button.dataset.numberValue = String(entry.value); button.setAttribute("role", "option"); button.setAttribute("aria-selected", entry.value === activeNumberValue ? "true" : "false"); const nameEl = document.createElement("span"); nameEl.className = "planet-list-name"; nameEl.textContent = `${entry.label}`; const metaEl = document.createElement("span"); metaEl.className = "planet-list-meta"; metaEl.textContent = `Opposite ${entry.opposite}`; button.append(nameEl, metaEl); fragment.appendChild(button); }); listEl.replaceChildren(fragment); if (countEl) { countEl.textContent = `${entries.length} entries`; } } function renderNumberDetail(value) { const { detailNameEl, detailTypeEl, detailSummaryEl, detailBodyEl } = getElements(); const entry = getNumberEntryByValue(value); if (!entry) { return; } const normalized = entry.value; const opposite = entry.opposite; const rootTarget = normalizeNumberValue(entry.digitalRoot); if (detailNameEl) { detailNameEl.textContent = `Number ${normalized} · ${entry.label}`; } if (detailTypeEl) { detailTypeEl.textContent = `Opposite: ${opposite}`; } if (detailSummaryEl) { detailSummaryEl.textContent = entry.summary || ""; } renderNumbersSpecialPanel(normalized); if (!detailBodyEl) { return; } detailBodyEl.replaceChildren(); const pairCardEl = document.createElement("div"); pairCardEl.className = "numbers-detail-card"; const pairHeadingEl = document.createElement("strong"); pairHeadingEl.textContent = "Number Pair"; const pairTextEl = document.createElement("div"); pairTextEl.className = "numbers-detail-text"; pairTextEl.textContent = `Opposite: ${opposite}`; const keywordText = entry.keywords.length ? `Keywords: ${entry.keywords.join(", ")}` : "Keywords: --"; const pairKeywordsEl = document.createElement("div"); pairKeywordsEl.className = "numbers-detail-text numbers-detail-text--muted"; pairKeywordsEl.textContent = keywordText; const oppositeBtn = document.createElement("button"); oppositeBtn.type = "button"; oppositeBtn.className = "numbers-nav-btn"; oppositeBtn.textContent = `Open Opposite Number ${opposite}`; oppositeBtn.addEventListener("click", () => { selectNumberEntry(opposite); }); pairCardEl.append(pairHeadingEl, pairTextEl, pairKeywordsEl, oppositeBtn); const kabbalahCardEl = document.createElement("div"); kabbalahCardEl.className = "numbers-detail-card"; const kabbalahHeadingEl = document.createElement("strong"); kabbalahHeadingEl.textContent = "Kabbalah Link"; const kabbalahNode = Number(entry?.associations?.kabbalahNode); const kabbalahTextEl = document.createElement("div"); kabbalahTextEl.className = "numbers-detail-text"; kabbalahTextEl.textContent = `Tree node target: ${kabbalahNode}`; const kabbalahBtn = document.createElement("button"); kabbalahBtn.type = "button"; kabbalahBtn.className = "numbers-nav-btn"; kabbalahBtn.textContent = `Open Kabbalah Tree Node ${kabbalahNode}`; kabbalahBtn.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:kabbalah-path", { detail: { pathNo: kabbalahNode } })); }); kabbalahCardEl.append(kabbalahHeadingEl, kabbalahTextEl, kabbalahBtn); const alphabetCardEl = document.createElement("div"); alphabetCardEl.className = "numbers-detail-card"; const alphabetHeadingEl = document.createElement("strong"); alphabetHeadingEl.textContent = "Alphabet Links"; const alphabetLinksWrapEl = document.createElement("div"); alphabetLinksWrapEl.className = "numbers-links-wrap"; const alphabetLinks = getAlphabetPositionLinksForDigitalRoot(rootTarget); if (!alphabetLinks.length) { const emptyAlphabetEl = document.createElement("div"); emptyAlphabetEl.className = "numbers-detail-text numbers-detail-text--muted"; emptyAlphabetEl.textContent = "No alphabet position entries found for this digital root yet."; alphabetLinksWrapEl.appendChild(emptyAlphabetEl); } else { alphabetLinks.forEach((link) => { const button = document.createElement("button"); button.type = "button"; button.className = "numbers-nav-btn"; button.textContent = `${link.alphabet}: ${link.label}`; button.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:alphabet", { detail: link.detail })); }); alphabetLinksWrapEl.appendChild(button); }); } alphabetCardEl.append(alphabetHeadingEl, alphabetLinksWrapEl); const tarotCardEl = document.createElement("div"); tarotCardEl.className = "numbers-detail-card"; const tarotHeadingEl = document.createElement("strong"); tarotHeadingEl.textContent = "Tarot Links"; const tarotLinksWrapEl = document.createElement("div"); tarotLinksWrapEl.className = "numbers-links-wrap"; const tarotCards = getTarotCardsForDigitalRoot(rootTarget, entry); if (!tarotCards.length) { const emptyEl = document.createElement("div"); emptyEl.className = "numbers-detail-text numbers-detail-text--muted"; emptyEl.textContent = "No tarot numeric entries found yet for this root. Add card numbers to map them."; tarotLinksWrapEl.appendChild(emptyEl); } else { tarotCards.forEach((card) => { const button = document.createElement("button"); button.type = "button"; button.className = "numbers-nav-btn"; button.textContent = `${card.name}`; button.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:tarot-trump", { detail: { cardName: card.name } })); }); tarotLinksWrapEl.appendChild(button); }); } tarotCardEl.append(tarotHeadingEl, tarotLinksWrapEl); const calendarCardEl = document.createElement("div"); calendarCardEl.className = "numbers-detail-card"; const calendarHeadingEl = document.createElement("strong"); calendarHeadingEl.textContent = "Calendar Links"; const calendarLinksWrapEl = document.createElement("div"); calendarLinksWrapEl.className = "numbers-links-wrap"; const calendarLinks = getCalendarMonthLinksForNumber(normalized); if (!calendarLinks.length) { const emptyCalendarEl = document.createElement("div"); emptyCalendarEl.className = "numbers-detail-text numbers-detail-text--muted"; emptyCalendarEl.textContent = "No calendar months currently mapped to this number."; calendarLinksWrapEl.appendChild(emptyCalendarEl); } else { calendarLinks.forEach((link) => { const button = document.createElement("button"); button.type = "button"; button.className = "numbers-nav-btn"; button.textContent = `${link.calendarLabel}: ${link.monthName} (Month ${link.monthOrder})`; button.addEventListener("click", () => { document.dispatchEvent(new CustomEvent("nav:calendar-month", { detail: { calendarId: link.calendarId, monthId: link.monthId } })); }); calendarLinksWrapEl.appendChild(button); }); } calendarCardEl.append(calendarHeadingEl, calendarLinksWrapEl); detailBodyEl.append(pairCardEl, kabbalahCardEl, alphabetCardEl, tarotCardEl, calendarCardEl); } function selectNumberEntry(value) { const entry = getNumberEntryByValue(value); activeNumberValue = entry ? entry.value : 0; renderNumbersList(); renderNumberDetail(activeNumberValue); } function ensureNumbersSection() { const { listEl } = getElements(); if (!listEl) { return; } if (!initialized) { listEl.addEventListener("click", (event) => { const target = event.target; if (!(target instanceof Node)) { return; } const button = target instanceof Element ? target.closest(".planet-list-item") : null; if (!(button instanceof HTMLButtonElement)) { return; } const value = Number(button.dataset.numberValue); if (!Number.isFinite(value)) { return; } selectNumberEntry(value); }); initialized = true; } renderNumbersList(); renderNumberDetail(activeNumberValue); } function init(nextConfig = {}) { config = { ...config, ...nextConfig }; } window.TarotNumbersUi = { ...(window.TarotNumbersUi || {}), init, ensureNumbersSection, selectNumberEntry, normalizeNumberValue }; })();