const { getCenteredWeekStartDay, getDateKey, getMoonPhaseName } = window.TarotCalc; const { loadReferenceData, loadMagickDataset } = window.TarotDataService; const { buildWeekEvents } = window.TarotEventBuilder; const { updateNowPanel } = window.TarotNowUi; const { ensureTarotSection } = window.TarotSectionUi || {}; const { ensurePlanetSection } = window.PlanetSectionUi || {}; const { ensureCyclesSection } = window.CyclesSectionUi || {}; const { ensureElementsSection } = window.ElementsSectionUi || {}; const { ensureAudioCircleSection } = window.AudioCircleUi || {}; const { ensureAudioNotesSection } = window.AudioNotesUi || {}; const { ensureIChingSection } = window.IChingSectionUi || {}; const { ensureKabbalahSection } = window.KabbalahSectionUi || {}; const { ensureCubeSection } = window.CubeSectionUi || {}; const { ensureAlphabetSection } = window.AlphabetSectionUi || {}; const { ensureAlphabetTextSection } = window.AlphabetTextUi || {}; const { ensureZodiacSection } = window.ZodiacSectionUi || {}; const { ensureQuizSection } = window.QuizSectionUi || {}; const { ensureGodsSection } = window.GodsSectionUi || {}; const { ensureEnochianSection } = window.EnochianSectionUi || {}; const { ensureCalendarSection } = window.CalendarSectionUi || {}; const { ensureHolidaySection } = window.HolidaySectionUi || {}; const { ensureNatalPanel } = window.TarotNatalUi || {}; const { ensureNumbersSection, selectNumberEntry, normalizeNumberValue } = window.TarotNumbersUi || {}; const tarotSpreadUi = window.TarotSpreadUi || {}; const settingsUi = window.TarotSettingsUi || {}; const chromeUi = window.TarotChromeUi || {}; const navigationUi = window.TarotNavigationUi || {}; const calendarFormattingUi = window.TarotCalendarFormatting || {}; const calendarVisualsUi = window.TarotCalendarVisuals || {}; const homeUi = window.TarotHomeUi || {}; const sectionStateUi = window.TarotSectionStateUi || {}; const appRuntime = window.TarotAppRuntime || {}; const statusEl = document.getElementById("status"); const monthStripEl = document.getElementById("month-strip"); const calendarEl = document.getElementById("calendar"); const timelineSectionEl = document.getElementById("timeline-section"); const calendarSectionEl = document.getElementById("calendar-section"); const holidaySectionEl = document.getElementById("holiday-section"); const audioCircleSectionEl = document.getElementById("audio-circle-section"); const audioNotesSectionEl = document.getElementById("audio-notes-section"); const tarotSectionEl = document.getElementById("tarot-section"); const tarotHouseSectionEl = document.getElementById("tarot-house-section"); const astronomySectionEl = document.getElementById("astronomy-section"); const natalSectionEl = document.getElementById("natal-section"); const planetSectionEl = document.getElementById("planet-section"); const cyclesSectionEl = document.getElementById("cycles-section"); const elementsSectionEl = document.getElementById("elements-section"); const ichingSectionEl = document.getElementById("iching-section"); const kabbalahSectionEl = document.getElementById("kabbalah-section"); const kabbalahTreeSectionEl = document.getElementById("kabbalah-tree-section"); const cubeSectionEl = document.getElementById("cube-section"); const alphabetSectionEl = document.getElementById("alphabet-section"); const alphabetLettersSectionEl = document.getElementById("alphabet-letters-section"); const alphabetTextSectionEl = document.getElementById("alphabet-text-section"); const numbersSectionEl = document.getElementById("numbers-section"); const zodiacSectionEl = document.getElementById("zodiac-section"); const quizSectionEl = document.getElementById("quiz-section"); const godsSectionEl = document.getElementById("gods-section"); const enochianSectionEl = document.getElementById("enochian-section"); const openHomeEl = document.getElementById("open-home"); const openCalendarEl = document.getElementById("open-calendar"); const openCalendarTimelineEl = document.getElementById("open-calendar-timeline"); const openCalendarMonthsEl = document.getElementById("open-calendar-months"); const openHolidaysEl = document.getElementById("open-holidays"); const openAudioEl = document.getElementById("open-audio"); const openAudioCircleEl = document.getElementById("open-audio-circle"); const openAudioNotesEl = document.getElementById("open-audio-notes"); const openTarotEl = document.getElementById("open-tarot"); const openTarotHouseEl = document.getElementById("open-tarot-house"); const openAstronomyEl = document.getElementById("open-astronomy"); const openPlanetsEl = document.getElementById("open-planets"); const openCyclesEl = document.getElementById("open-cycles"); const openElementsEl = document.getElementById("open-elements"); const openIChingEl = document.getElementById("open-iching"); const openKabbalahEl = document.getElementById("open-kabbalah"); const openKabbalahTreeEl = document.getElementById("open-kabbalah-tree"); const openKabbalahCubeEl = document.getElementById("open-kabbalah-cube"); const openAlphabetEl = document.getElementById("open-alphabet"); const openAlphabetLettersEl = document.getElementById("open-alphabet-letters"); const openAlphabetTextEl = document.getElementById("open-alphabet-text"); const openNumbersEl = document.getElementById("open-numbers"); const openZodiacEl = document.getElementById("open-zodiac"); const openNatalEl = document.getElementById("open-natal"); const openQuizEl = document.getElementById("open-quiz"); const openGodsEl = document.getElementById("open-gods"); const openEnochianEl = document.getElementById("open-enochian"); const latEl = document.getElementById("lat"); const lngEl = document.getElementById("lng"); const nowSkyLayerEl = document.getElementById("now-sky-layer"); const nowPanelEl = document.getElementById("now-panel"); const nowOverlayToggleEl = document.getElementById("now-overlay-toggle"); const connectionGateEl = document.getElementById("connection-gate"); const connectionGateBaseUrlEl = document.getElementById("connection-gate-base-url"); const connectionGateApiKeyEl = document.getElementById("connection-gate-api-key"); const connectionGateStatusEl = document.getElementById("connection-gate-status"); const connectionGateConnectEl = document.getElementById("connection-gate-connect"); const nowElements = { nowHourEl: document.getElementById("now-hour"), nowHourTarotEl: document.getElementById("now-hour-tarot"), nowCountdownEl: document.getElementById("now-countdown"), nowHourNextEl: document.getElementById("now-hour-next"), nowHourCardEl: document.getElementById("now-hour-card"), nowMoonEl: document.getElementById("now-moon"), nowMoonTarotEl: document.getElementById("now-moon-tarot"), nowMoonCountdownEl: document.getElementById("now-moon-countdown"), nowMoonNextEl: document.getElementById("now-moon-next"), nowMoonCardEl: document.getElementById("now-moon-card"), nowDecanEl: document.getElementById("now-decan"), nowDecanTarotEl: document.getElementById("now-decan-tarot"), nowDecanCountdownEl: document.getElementById("now-decan-countdown"), nowDecanNextEl: document.getElementById("now-decan-next"), nowDecanCardEl: document.getElementById("now-decan-card"), nowStatsSabianEl: document.getElementById("now-stats-sabian"), nowStatsPlanetsEl: document.getElementById("now-stats-planets") }; const baseWeekOptions = { hourStart: 0, hourEnd: 24, eventView: ["allday", "time"], taskView: false }; const PLANET_CALENDAR_ORDER = ["saturn", "jupiter", "mars", "sol", "venus", "mercury", "luna"]; const DEFAULT_TAROT_DECK = "ceremonial-magick"; const DEFAULT_SETTINGS = { latitude: 51.5074, longitude: -0.1278, timeFormat: "minutes", birthDate: "", tarotDeck: DEFAULT_TAROT_DECK }; const PLANET_CALENDAR_STYLES = { saturn: { name: "♄ Saturn", color: "#f4f4f5", backgroundColor: "#0a0a0a", borderColor: "#0a0a0a" }, jupiter: { name: "♃ Jupiter", color: "#eff6ff", backgroundColor: "#1d4ed8", borderColor: "#1d4ed8" }, mars: { name: "♂ Mars", color: "#fff1f2", backgroundColor: "#dc2626", borderColor: "#dc2626" }, sol: { name: "☉ Sol", color: "#111827", backgroundColor: "#facc15", borderColor: "#eab308" }, venus: { name: "♀ Venus", color: "#ecfdf5", backgroundColor: "#16a34a", borderColor: "#15803d" }, mercury: { name: "☿ Mercury", color: "#111827", backgroundColor: "#fb923c", borderColor: "#f97316" }, luna: { name: "☾ Luna", color: "#111827", backgroundColor: "#e2e8f0", borderColor: "#cbd5e1" } }; const planetaryCalendars = PLANET_CALENDAR_ORDER.map((planetId) => { const style = PLANET_CALENDAR_STYLES[planetId]; return { id: `planet-${planetId}`, name: style.name, color: style.color, backgroundColor: style.backgroundColor, dragBackgroundColor: style.backgroundColor, borderColor: style.borderColor }; }); const calendar = new tui.Calendar("#calendar", { defaultView: "week", usageStatistics: false, isReadOnly: true, useFormPopup: false, useDetailPopup: false, gridSelection: false, calendars: [ ...planetaryCalendars, { id: "planetary", name: "Planetary (Fallback)", color: "#f4f4f5", backgroundColor: "#52525b", dragBackgroundColor: "#52525b", borderColor: "#52525b" }, { id: "astrology", name: "Astrology & Tarot", color: "#18181b", backgroundColor: "#fcd34d", dragBackgroundColor: "#fcd34d", borderColor: "#fcd34d" } ], week: { ...baseWeekOptions, startDayOfWeek: getCenteredWeekStartDay(new Date()) } }); appRuntime.init?.({ calendar, baseWeekOptions, defaultSettings: DEFAULT_SETTINGS, latEl, lngEl, nowElements, calendarVisualsUi, homeUi, onStatus: (text) => setStatus(text), services: { getCenteredWeekStartDay, getDateKey, loadReferenceData, loadMagickDataset, buildWeekEvents, updateNowPanel }, ensure: { ensureTarotSection, ensurePlanetSection, ensureCyclesSection, ensureIChingSection, ensureCalendarSection, ensureHolidaySection, ensureNatalPanel, ensureQuizSection } }); let currentSettings = { ...DEFAULT_SETTINGS }; let hasRenderedConnectedShell = false; function setStatus(text) { if (!statusEl) { return; } statusEl.textContent = text; } function getConnectionSettings() { return window.TarotAppConfig?.getConnectionSettings?.() || { apiBaseUrl: "", apiKey: "" }; } function syncConnectionGateInputs() { const connectionSettings = getConnectionSettings(); if (connectionGateBaseUrlEl) { connectionGateBaseUrlEl.value = String(connectionSettings.apiBaseUrl || ""); } if (connectionGateApiKeyEl) { connectionGateApiKeyEl.value = String(connectionSettings.apiKey || ""); } } function setConnectionGateStatus(text, tone = "default") { if (!connectionGateStatusEl) { return; } connectionGateStatusEl.textContent = text || ""; if (tone && tone !== "default") { connectionGateStatusEl.dataset.tone = tone; } else { delete connectionGateStatusEl.dataset.tone; } } function showConnectionGate(message, tone = "default") { syncConnectionGateInputs(); if (connectionGateEl) { connectionGateEl.hidden = false; } document.body.classList.add("connection-gated"); setConnectionGateStatus(message, tone); } function hideConnectionGate() { if (connectionGateEl) { connectionGateEl.hidden = true; } document.body.classList.remove("connection-gated"); } function getConnectionSettingsFromGate() { return { apiBaseUrl: String(connectionGateBaseUrlEl?.value || "").trim(), apiKey: String(connectionGateApiKeyEl?.value || "").trim() }; } async function ensureConnectedApp(nextConnectionSettings = null) { if (nextConnectionSettings) { window.TarotAppConfig?.updateConnectionSettings?.(nextConnectionSettings); } syncConnectionGateInputs(); const configuredConnection = getConnectionSettings(); if (!configuredConnection.apiBaseUrl) { showConnectionGate("Enter an API Base URL to load TaroTime.", "error"); return false; } showConnectionGate("Connecting to the API...", "pending"); const probeResult = await window.TarotDataService?.probeConnection?.(); if (!probeResult?.ok) { showConnectionGate(probeResult?.message || "Unable to reach the API.", "error"); return false; } hideConnectionGate(); if (!hasRenderedConnectedShell) { sectionStateUi.setActiveSection?.("home"); hasRenderedConnectedShell = true; } setConnectionGateStatus("Connected.", "success"); setStatus(`Connected to ${configuredConnection.apiBaseUrl}.`); await appRuntime.renderWeek?.(); return true; } function bindConnectionGate() { syncConnectionGateInputs(); if (connectionGateConnectEl) { connectionGateConnectEl.addEventListener("click", () => { void ensureConnectedApp(getConnectionSettingsFromGate()); }); } [connectionGateBaseUrlEl, connectionGateApiKeyEl].forEach((element) => { if (!element) { return; } element.addEventListener("keydown", (event) => { if (event.key === "Enter") { event.preventDefault(); void ensureConnectedApp(getConnectionSettingsFromGate()); } }); }); document.addEventListener("connection:updated", () => { syncConnectionGateInputs(); }); } window.TarotNumbersUi?.init?.({ getReferenceData: () => appRuntime.getReferenceData?.() || null, getMagickDataset: () => appRuntime.getMagickDataset?.() || null, ensureTarotSection }); window.TarotSpreadUi?.init?.({ ensureTarotSection, getReferenceData: () => appRuntime.getReferenceData?.() || null, getMagickDataset: () => appRuntime.getMagickDataset?.() || null, getActiveSection: () => sectionStateUi.getActiveSection?.() || "home", setActiveSection: (section) => sectionStateUi.setActiveSection?.(section) }); sectionStateUi.init?.({ calendar, tarotSpreadUi, settingsUi, calendarVisualsUi, homeUi, getReferenceData: () => appRuntime.getReferenceData?.() || null, getMagickDataset: () => appRuntime.getMagickDataset?.() || null, elements: { calendarEl, monthStripEl, nowPanelEl, timelineSectionEl, calendarSectionEl, holidaySectionEl, audioCircleSectionEl, audioNotesSectionEl, tarotSectionEl, tarotHouseSectionEl, astronomySectionEl, natalSectionEl, planetSectionEl, cyclesSectionEl, elementsSectionEl, ichingSectionEl, kabbalahSectionEl, kabbalahTreeSectionEl, cubeSectionEl, alphabetSectionEl, alphabetLettersSectionEl, alphabetTextSectionEl, numbersSectionEl, zodiacSectionEl, quizSectionEl, godsSectionEl, enochianSectionEl, openHomeEl, openCalendarEl, openCalendarTimelineEl, openCalendarMonthsEl, openHolidaysEl, openAudioEl, openAudioCircleEl, openAudioNotesEl, openTarotEl, openTarotHouseEl, openAstronomyEl, openPlanetsEl, openCyclesEl, openElementsEl, openIChingEl, openKabbalahEl, openKabbalahTreeEl, openKabbalahCubeEl, openAlphabetEl, openAlphabetLettersEl, openAlphabetTextEl, openNumbersEl, openZodiacEl, openNatalEl, openQuizEl, openGodsEl, openEnochianEl }, ensure: { ensureTarotSection, ensurePlanetSection, ensureCyclesSection, ensureElementsSection, ensureIChingSection, ensureKabbalahSection, ensureCubeSection, ensureAlphabetSection, ensureAlphabetTextSection, ensureZodiacSection, ensureQuizSection, ensureGodsSection, ensureEnochianSection, ensureCalendarSection, ensureHolidaySection, ensureNatalPanel, ensureNumbersSection, ensureAudioCircleSection, ensureAudioNotesSection } }); settingsUi.init?.({ defaultSettings: DEFAULT_SETTINGS, onSettingsApplied: (settings) => { appRuntime.applySettings?.(settings); currentSettings = settings; }, onSyncSkyBackground: (geo, force) => homeUi.syncNowSkyBackground?.(geo, force), onStatus: (text) => setStatus(text), onConnectionSaved: async () => ensureConnectedApp(), getActiveSection: () => sectionStateUi.getActiveSection?.() || "home", onReopenActiveSection: (section) => sectionStateUi.setActiveSection?.(section), onRenderWeek: () => appRuntime.renderWeek?.() }); chromeUi.init?.(); calendarFormattingUi.init?.({ getCurrentTimeFormat: () => appRuntime.getCurrentTimeFormat?.() || "minutes", getReferenceData: () => appRuntime.getReferenceData?.() || null }); calendarVisualsUi.init?.({ calendar, monthStripEl, getCurrentGeo: () => appRuntime.getCurrentGeo?.() || null, parseGeoInput: () => appRuntime.parseGeoInput?.(), getMoonPhaseName }); homeUi.init?.({ nowSkyLayerEl, nowPanelEl, getCurrentGeo: () => appRuntime.getCurrentGeo?.() || null }); if (nowOverlayToggleEl && nowPanelEl) { const syncNowOverlayVisibility = () => { nowPanelEl.classList.toggle("is-overlay-hidden", !nowOverlayToggleEl.checked); }; nowOverlayToggleEl.addEventListener("change", syncNowOverlayVisibility); syncNowOverlayVisibility(); } navigationUi.init?.({ tarotSpreadUi, getActiveSection: () => sectionStateUi.getActiveSection?.() || "home", setActiveSection: (section) => sectionStateUi.setActiveSection?.(section), getReferenceData: () => appRuntime.getReferenceData?.() || null, getMagickDataset: () => appRuntime.getMagickDataset?.() || null, normalizeNumberValue, selectNumberEntry, elements: { openHomeEl, openCalendarEl, openCalendarTimelineEl, openCalendarMonthsEl, openHolidaysEl, openAudioEl, openAudioCircleEl, openAudioNotesEl, openTarotEl, openTarotHouseEl, openAstronomyEl, openPlanetsEl, openCyclesEl, openElementsEl, openIChingEl, openKabbalahEl, openKabbalahTreeEl, openKabbalahCubeEl, openAlphabetEl, openAlphabetLettersEl, openAlphabetTextEl, openNumbersEl, openZodiacEl, openNatalEl, openQuizEl, openGodsEl, openEnochianEl }, ensure: { ensureTarotSection, ensurePlanetSection, ensureCyclesSection, ensureElementsSection, ensureIChingSection, ensureKabbalahSection, ensureCubeSection, ensureAlphabetSection, ensureAlphabetTextSection, ensureZodiacSection, ensureGodsSection, ensureCalendarSection, ensureAudioCircleSection } }); window.TarotNatal = { ...(window.TarotNatal || {}), getSettings() { return appRuntime.getCurrentSettings?.() || { ...currentSettings }; }, getContext() { return settingsUi.buildNatalContext?.(appRuntime.getCurrentSettings?.() || currentSettings) || null; }, buildContextFromSettings(settings) { return settingsUi.buildNatalContext?.(settings) || null; } }; const initialSettings = settingsUi.loadInitialSettingsAndApply?.() || { ...DEFAULT_SETTINGS }; homeUi.syncNowSkyBackground?.({ latitude: initialSettings.latitude, longitude: initialSettings.longitude }, true); bindConnectionGate(); void ensureConnectedApp();