(function () { "use strict"; function findSignIdByAstrologyName(name, context) { const { api, getState } = context; const token = api.normalizeCalendarText(name); if (!token) { return null; } for (const [signId, sign] of getState().signsById || []) { const idToken = api.normalizeCalendarText(signId); const nameToken = api.normalizeCalendarText(sign?.name?.en || sign?.name || ""); if (token === idToken || token === nameToken) { return signId; } } return null; } function buildMajorArcanaRowsForMonth(context) { const { month, api, getState } = context; const currentState = getState(); if (currentState.selectedCalendar !== "gregorian") { return []; } const monthOrder = Number(month?.order); if (!Number.isFinite(monthOrder)) { return []; } const monthStart = new Date(currentState.selectedYear, monthOrder - 1, 1, 12, 0, 0, 0); const monthEnd = new Date(currentState.selectedYear, monthOrder, 0, 12, 0, 0, 0); const rows = []; currentState.hebrewById?.forEach((letter) => { const astrologyType = api.normalizeCalendarText(letter?.astrology?.type); if (astrologyType !== "zodiac") { return; } const signId = findSignIdByAstrologyName(letter?.astrology?.name, context); const sign = signId ? currentState.signsById?.get(signId) : null; if (!sign) { return; } const startToken = api.parseMonthDayToken(sign?.start); const endToken = api.parseMonthDayToken(sign?.end); if (!startToken || !endToken) { return; } const spanStart = new Date(currentState.selectedYear, startToken.month - 1, startToken.day, 12, 0, 0, 0); const spanEnd = new Date(currentState.selectedYear, endToken.month - 1, endToken.day, 12, 0, 0, 0); const wraps = spanEnd.getTime() < spanStart.getTime(); const segments = wraps ? [ { start: spanStart, end: new Date(currentState.selectedYear, 11, 31, 12, 0, 0, 0) }, { start: new Date(currentState.selectedYear, 0, 1, 12, 0, 0, 0), end: spanEnd } ] : [{ start: spanStart, end: spanEnd }]; segments.forEach((segment) => { const overlap = api.intersectDateRanges(segment.start, segment.end, monthStart, monthEnd); if (!overlap) { return; } const rangeStartDay = overlap.start.getDate(); const rangeEndDay = overlap.end.getDate(); const cardName = String(letter?.tarot?.card || "").trim(); const trumpNumber = Number(letter?.tarot?.trumpNumber); if (!cardName) { return; } rows.push({ id: `${signId}-${rangeStartDay}-${rangeEndDay}`, signId, signName: sign?.name?.en || sign?.name || signId, signSymbol: sign?.symbol || "", cardName, trumpNumber: Number.isFinite(trumpNumber) ? Math.trunc(trumpNumber) : null, hebrewLetterId: String(letter?.hebrewLetterId || "").trim(), hebrewLetterName: String(letter?.name || "").trim(), hebrewLetterChar: String(letter?.char || "").trim(), dayStart: rangeStartDay, dayEnd: rangeEndDay, rangeLabel: `${month?.name || "Month"} ${rangeStartDay}-${rangeEndDay}` }); }); }); rows.sort((left, right) => { if (left.dayStart !== right.dayStart) { return left.dayStart - right.dayStart; } return left.cardName.localeCompare(right.cardName); }); return rows; } function renderMajorArcanaCard(context) { const { month, api } = context; const selectedDay = api.getSelectedDayFilterContext(month); const allRows = buildMajorArcanaRowsForMonth(context); const rows = selectedDay ? allRows.filter((row) => selectedDay.entries.some((entry) => entry.dayNumber >= row.dayStart && entry.dayNumber <= row.dayEnd)) : allRows; if (!rows.length) { return `
Major Arcana Windows
No major arcana windows for this month.
`; } const list = rows.map((row) => { const label = row.hebrewLetterId ? `${row.hebrewLetterChar ? `${row.hebrewLetterChar} ` : ""}${row.hebrewLetterName || row.hebrewLetterId}` : "--"; const displayCardName = api.getDisplayTarotName(row.cardName, row.trumpNumber); return `
${displayCardName}${row.trumpNumber != null ? ` · Trump ${row.trumpNumber}` : ""} ${row.rangeLabel}
${row.signSymbol} ${row.signName} · Hebrew: ${label}
${row.hebrewLetterId ? `` : ""}
`; }).join(""); return `
Major Arcana Windows
${list}
`; } function renderDecanTarotCard(context) { const { month, api } = context; const selectedDay = api.getSelectedDayFilterContext(month); const allRows = api.buildDecanTarotRowsForMonth(month); const rows = selectedDay ? allRows.filter((row) => selectedDay.entries.some((entry) => { const targetDate = entry.gregorianDate; if (!(targetDate instanceof Date) || Number.isNaN(targetDate.getTime())) { return false; } const targetMonth = targetDate.getMonth() + 1; const targetDayNo = targetDate.getDate(); return api.isMonthDayInRange( targetMonth, targetDayNo, row.startMonth, row.startDay, row.endMonth, row.endDay ); })) : allRows; if (!rows.length) { return `
Decan Tarot Windows
No decan tarot windows for this month.
`; } const list = rows.map((row) => { const displayCardName = api.getDisplayTarotName(row.cardName); return `
${row.signSymbol} ${row.signName} · Decan ${row.decanIndex} ${row.startDegree}°–${row.endDegree}° · ${row.dateRange}
`; }).join(""); return `
Decan Tarot Windows
${list}
`; } function renderDayLinksCard(context) { const { month, api } = context; const rows = api.getMonthDayLinkRows(month); if (!rows.length) { return ""; } const selectedContext = api.getSelectedDayFilterContext(month); const selectedDaySet = selectedContext?.dayNumbers || new Set(); const selectedDays = selectedContext?.entries?.map((entry) => entry.dayNumber) || []; const selectedSummary = selectedDays.length ? selectedDays.join(", ") : ""; const links = rows.map((row) => { if (!row.isResolved) { return `${row.day}`; } const isSelected = selectedDaySet.has(Number(row.day)); return ``; }).join(""); const clearButton = selectedContext ? '' : ""; const helperText = selectedContext ? `
Filtered to days: ${selectedSummary}
` : ""; return `
Day Links
Filter this month to events, holidays, and data connected to a specific day.
${helperText}
${links}
${clearButton ? `
${clearButton}
` : ""}
`; } function renderGregorianMonthDetail(context) { const { renderFactsCard, renderAssociationsCard, renderEventsCard, renderHolidaysCard, month } = context; return `
${renderFactsCard(month)} ${renderDayLinksCard(context)} ${renderAssociationsCard(month)} ${renderMajorArcanaCard(context)} ${renderDecanTarotCard(context)} ${renderEventsCard(month)} ${renderHolidaysCard(month, "Holiday Repository")}
`; } function renderHebrewMonthDetail(context) { const { month, api, getState, buildAssociationButtons, renderHolidaysCard } = context; const currentState = getState(); const gregorianStartDate = api.getGregorianReferenceDateForCalendarMonth(month); const factsRows = [ ["Hebrew Name", month.nativeName || "--"], ["Month Order", month.leapYearOnly ? `${month.order} (leap year only)` : String(month.order)], ["Gregorian Reference Year", String(currentState.selectedYear)], ["Month Start (Gregorian)", api.formatGregorianReferenceDate(gregorianStartDate)], ["Days", month.daysVariant ? `${month.days}–${month.daysVariant} (varies)` : String(month.days || "--")], ["Season", month.season || "--"], ["Zodiac Sign", api.cap(month.zodiacSign) || "--"], ["Tribe of Israel", month.tribe || "--"], ["Sense", month.sense || "--"], ["Hebrew Letter", month.hebrewLetter || "--"] ].map(([dt, dd]) => `
${dt}
${dd}
`).join(""); const monthOrder = Number(month?.order); const navButtons = buildAssociationButtons({ ...(month?.associations || {}), ...(Number.isFinite(monthOrder) ? { numberValue: Math.trunc(monthOrder) } : {}) }); const connectionsCard = navButtons ? `
Connections${navButtons}
` : ""; return `
Month Facts
${factsRows}
${connectionsCard}
About ${month.name}
${month.description || "--"}
${renderDayLinksCard(context)} ${renderHolidaysCard(month, "Holiday Repository")}
`; } function renderIslamicMonthDetail(context) { const { month, api, getState, buildAssociationButtons, renderHolidaysCard } = context; const currentState = getState(); const gregorianStartDate = api.getGregorianReferenceDateForCalendarMonth(month); const factsRows = [ ["Arabic Name", month.nativeName || "--"], ["Month Order", String(month.order)], ["Gregorian Reference Year", String(currentState.selectedYear)], ["Month Start (Gregorian)", api.formatGregorianReferenceDate(gregorianStartDate)], ["Meaning", month.meaning || "--"], ["Days", month.daysVariant ? `${month.days}–${month.daysVariant} (varies)` : String(month.days || "--")], ["Sacred Month", month.sacred ? "Yes - warfare prohibited" : "No"] ].map(([dt, dd]) => `
${dt}
${dd}
`).join(""); const monthOrder = Number(month?.order); const hasNumberLink = Number.isFinite(monthOrder) && monthOrder >= 0; const navButtons = hasNumberLink ? buildAssociationButtons({ numberValue: Math.trunc(monthOrder) }) : ""; const connectionsCard = hasNumberLink ? `
Connections${navButtons}
` : ""; return `
Month Facts
${factsRows}
${connectionsCard}
About ${month.name}
${month.description || "--"}
${renderDayLinksCard(context)} ${renderHolidaysCard(month, "Holiday Repository")}
`; } function buildWheelDeityButtons(deities, context) { const { api, getState } = context; const buttons = []; (Array.isArray(deities) ? deities : []).forEach((rawName) => { const cleanName = String(rawName || "").replace(/\s*\/.*$/, "").replace(/\s*\(.*\)$/, "").trim(); const godId = api.findGodIdByName(cleanName) || api.findGodIdByName(rawName); if (!godId) { return; } const god = getState().godsById?.get(godId); const label = god?.name || cleanName; buttons.push(``); }); return buttons; } function renderWheelMonthDetail(context) { const { month, api, getState, buildAssociationButtons, renderHolidaysCard } = context; const currentState = getState(); const gregorianStartDate = api.getGregorianReferenceDateForCalendarMonth(month); const assoc = month?.associations; const themes = Array.isArray(assoc?.themes) ? assoc.themes.join(", ") : "--"; const deities = Array.isArray(assoc?.deities) ? assoc.deities.join(", ") : "--"; const colors = Array.isArray(assoc?.colors) ? assoc.colors.join(", ") : "--"; const herbs = Array.isArray(assoc?.herbs) ? assoc.herbs.join(", ") : "--"; const factsRows = [ ["Date", month.date || "--"], ["Type", api.cap(month.type) || "--"], ["Gregorian Reference Year", String(currentState.selectedYear)], ["Start (Gregorian)", api.formatGregorianReferenceDate(gregorianStartDate)], ["Season", month.season || "--"], ["Element", api.cap(month.element) || "--"], ["Direction", assoc?.direction || "--"] ].map(([dt, dd]) => `
${dt}
${dd}
`).join(""); const assocRows = [ ["Themes", themes], ["Deities", deities], ["Colors", colors], ["Herbs", herbs] ].map(([dt, dd]) => `
${dt}
${dd}
`).join(""); const deityButtons = buildWheelDeityButtons(assoc?.deities, context); const deityLinksCard = deityButtons.length ? `
Linked Deities
${deityButtons.join("")}
` : ""; const monthOrder = Number(month?.order); const hasNumberLink = Number.isFinite(monthOrder) && monthOrder >= 0; const numberButtons = hasNumberLink ? buildAssociationButtons({ numberValue: Math.trunc(monthOrder) }) : ""; const numberLinksCard = hasNumberLink ? `
Connections${numberButtons}
` : ""; return `
Sabbat Facts
${factsRows}
About ${month.name}
${month.description || "--"}
Associations
${assocRows}
${renderDayLinksCard(context)} ${numberLinksCard} ${deityLinksCard} ${renderHolidaysCard(month, "Holiday Repository")}
`; } window.CalendarDetailPanelsUi = { renderGregorianMonthDetail, renderHebrewMonthDetail, renderIslamicMonthDetail, renderWheelMonthDetail }; })();