function useBuilderApi() {
    const context = window.EA_BUILDER_API_CONTEXT;
    return (context && typeof React.useContext === 'function' ? React.useContext(context) : null) || window.EA;
}
function builderAppPath(path) { return window.EA_APP?.path ? window.EA_APP.path(path) : path; }
function builderDraftKey(key, projectId) {
    const user = typeof loadUser === 'function' ? loadUser() : null;
    const project = projectId || new URLSearchParams(window.location.search || '').get('project') || 'new';
    return key + ':draft:' + encodeURIComponent(user?.id || user?.email || 'anonymous') + ':' + encodeURIComponent(project);
}
function readBuilderConfig(key) { try {
    return JSON.parse(window.localStorage.getItem(builderDraftKey(key)) || 'null');
}
catch (_) {
    return null;
} }
function writeBuilderConfig(key, config) {
    const json = JSON.stringify(config);
    window.localStorage.setItem(builderDraftKey(key), json);
    try {
        window.sessionStorage.setItem(builderDraftKey(key), json);
        window.sessionStorage.setItem(key, json);
    }
    catch (_) { }
}
function builderPendingKey(templateId, projectId) {
    const template = TemplateCatalog.get(templateId);
    return template?.configKey && projectId ? builderDraftKey(template.configKey, projectId) + ':pending' : null;
}
function markBuilderDraftPending(templateId, projectId) {
    const key = builderPendingKey(templateId, projectId);
    if (key)
        window.localStorage.setItem(key, '1');
}
function markBuilderDraftSaved(templateId, projectId, config) {
    const template = TemplateCatalog.get(templateId), key = builderPendingKey(templateId, projectId);
    if (key && window.localStorage.getItem(builderDraftKey(template.configKey, projectId)) === JSON.stringify(config))
        window.localStorage.removeItem(key);
}
function readBuilderRecovery(templateId, project) {
    const template = TemplateCatalog.get(templateId), key = builderPendingKey(templateId, project?.id);
    if (!key || !window.localStorage.getItem(key))
        return null;
    try {
        const config = JSON.parse(window.localStorage.getItem(builderDraftKey(template.configKey, project.id)) || 'null');
        if (config && JSON.stringify(config) !== JSON.stringify(project.config || {}))
            return config;
        window.localStorage.removeItem(key);
    }
    catch (_) { }
    return null;
}
function BuilderRecoveryNotice({ onRestore, onUseSaved }) {
    return React.createElement("div", { className: "builder-recovery-notice", role: "status" },
        React.createElement("h2", null, "Keep your latest edits?"),
        React.createElement("p", null, "This device has changes that were not saved to your account. Choose which version to continue editing."),
        React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', gap: 12 } },
            React.createElement("button", { type: "button", className: "btn btn-primary", onClick: onRestore }, "Restore local edits"),
            React.createElement("button", { type: "button", className: "btn btn-secondary", onClick: onUseSaved }, "Use saved version")));
}
function validateBuilderMedia(config) {
    const visit = value => { if (typeof value === 'string' && /^data:image\//i.test(value))
        throw new Error('Replace embedded photographs using Upload from device before saving.'); if (value && typeof value === 'object')
        Object.values(value).forEach(visit); };
    visit(config);
}
function VerifiedLegacyBuilder({ editor: Editor, ...props }) {
    const api = useBuilderApi();
    const { projectId, template, user, openSignIn } = props;
    const [verified, setVerified] = React.useState(null), [recovery, setRecovery] = React.useState(null), [error, setError] = React.useState(''), [retry, setRetry] = React.useState(0);
    const ownerId = user?.id || null;
    React.useEffect(() => {
        if (!projectId)
            return;
        let cancelled = false;
        setVerified(null);
        setRecovery(null);
        setError('');
        if (!api?.isLoggedIn()) {
            setError('Sign in to open this saved invitation.');
            return;
        }
        api.getProject(projectId).then(({ project }) => {
            if (cancelled)
                return;
            if (!project || TemplateCatalog.normalizeId(project.template_id) !== template.id)
                throw new Error('This project does not belong to the selected design.');
            const local = readBuilderRecovery(template.id, project);
            if (local) {
                setRecovery({ project, local, ownerId });
                return;
            }
            writeBuilderConfig(template.configKey, project.config || {});
            setVerified({ project, ownerId });
        }).catch(err => { if (!cancelled)
            setError(err.message || 'Unable to load this invitation.'); });
        return () => { cancelled = true; };
    }, [projectId, template.id, user?.id, user?.email, retry]);
    const chooseVersion = restore => {
        if (!recovery || recovery.ownerId !== ownerId)
            return;
        const project = { ...recovery.project, config: restore ? recovery.local : recovery.project.config };
        writeBuilderConfig(template.configKey, project.config || {});
        if (!restore)
            markBuilderDraftSaved(template.id, project.id, project.config || {});
        setVerified({ project, ownerId, recovered: restore });
        setRecovery(null);
    };
    if (projectId && (verified?.project.id !== projectId || verified?.ownerId !== ownerId))
        return React.createElement("main", { className: "section builder-load-state" },
            React.createElement("div", { className: "wrap" },
                React.createElement("h1", null, "Your invitation"),
                recovery?.project.id === projectId && recovery.ownerId === ownerId ? React.createElement(BuilderRecoveryNotice, { onRestore: () => chooseVersion(true), onUseSaved: () => chooseVersion(false) }) : React.createElement(React.Fragment, null,
                    React.createElement("p", { role: error ? 'alert' : 'status' }, error || 'Loading your saved invitation…'),
                    error && React.createElement("button", { className: "btn btn-primary", onClick: () => api?.isLoggedIn() ? setRetry(v => v + 1) : openSignIn?.('builder') }, api?.isLoggedIn() ? 'Try again' : 'Sign in'))));
    return React.createElement(Editor, { ...props, key: projectId ? (projectId + ':' + ownerId) : 'new', verifiedProject: verified?.project, verifiedOwnerId: verified?.ownerId, recoveredDraft: verified?.recovered });
}
const TEMPLATE09_CONFIG_KEY = "everafter-template09-config";
const TEMPLATE09_BUILDER_TEMPLATE_PATH = TemplateCatalog.get("royal-pichwai").builderTemplatePath;
const TEMPLATE09_BUILDER_ASSET_ROOT = builderAppPath("/wedding-invitations/uploads/builder-templates/Royal Pichwai");
const BUILDER_AUTOSAVE_DELAY = 900;
const TEMPLATE09_DEFAULT_EVENTS = [
    { id: "mehendi", icon: "mehendi", name: "Mehendi Baithak", date: "2026-12-12", time: "4:30 PM", venue: "Neem Garden", desc: "Botanical greens and soft golds", mapsLink: "https://www.google.com/maps/search/?api=1&query=Peacock+Garden+Haveli+Jaipur" },
    { id: "haldi", icon: "haldi", name: "Haldi", date: "2026-12-13", time: "10:30 AM", venue: "Sunlit Aangan", desc: "Turmeric, ivory and marigold tones", mapsLink: "https://www.google.com/maps/search/?api=1&query=Peacock+Garden+Haveli+Jaipur" },
    { id: "sangeet", icon: "sangeet", name: "Sangeet Soiree", date: "2026-12-13", time: "7:45 PM", venue: "Mirror Courtyard", desc: "Music, stories and a little drama", mapsLink: "https://www.google.com/maps/search/?api=1&query=Peacock+Garden+Haveli+Jaipur" },
    { id: "shaadi", icon: "shaadi", name: "Shaadi", date: "2026-12-14", time: "9:45 AM", venue: "Peacock Mandap", desc: "Traditional attire in jewel tones", mapsLink: "https://www.google.com/maps/search/?api=1&query=Peacock+Garden+Haveli+Jaipur" },
    { id: "reception", icon: "reception", name: "Reception", date: "2026-12-14", time: "8:00 PM", venue: "Moonlit Lawn", desc: "Dinner, blessings and dancing", mapsLink: "https://www.google.com/maps/search/?api=1&query=Peacock+Garden+Haveli+Jaipur" },
    { id: "vidaai", icon: "vidaai", name: "Vidaai", date: "2026-12-15", time: "9:00 AM", venue: "Haveli Gate", desc: "A gentle farewell with family", mapsLink: "https://www.google.com/maps/search/?api=1&query=Peacock+Garden+Haveli+Jaipur" },
];
const TEMPLATE09_LEGACY_EVENTS = [
    { id: "mehendi", icon: "mehendi", name: "Mehendi", date: "2026-12-11", time: "4:00 PM", venue: "Lotus Courtyard", desc: "Greens and florals encouraged.", mapsLink: "" },
    { id: "haldi", icon: "haldi", name: "Haldi", date: "2026-12-12", time: "10:00 AM", venue: "Poolside Courtyard", desc: "Yellow and ivory tones.", mapsLink: "" },
    { id: "sangeet", icon: "sangeet", name: "Sangeet", date: "2026-12-12", time: "7:30 PM", venue: "Royal Ballroom", desc: "Music, performances, and dancing.", mapsLink: "" },
    { id: "shaadi", icon: "shaadi", name: "Shaadi", date: "2026-12-14", time: "9:45 AM", venue: "Lake Mandap", desc: "Traditional Indian attire.", mapsLink: "" },
    { id: "reception", icon: "reception", name: "Reception", date: "2026-12-14", time: "7:30 PM", venue: "Palace Lawns", desc: "Candlelit dinner and celebration.", mapsLink: "" },
];
const TEMPLATE09_EVENT_ICON_OPTIONS = [
    { value: "mehendi", label: "Mehendi", src: `${TEMPLATE09_BUILDER_ASSET_ROOT}/assets/event/pn-evt-ico-mehendi-x-v01.webp` },
    { value: "haldi", label: "Haldi", src: `${TEMPLATE09_BUILDER_ASSET_ROOT}/assets/event/pn-evt-ico-haldi-x-v01.webp` },
    { value: "sangeet", label: "Sangeet", src: `${TEMPLATE09_BUILDER_ASSET_ROOT}/assets/event/pn-evt-ico-sangeet-x-v01.webp` },
    { value: "shaadi", label: "Shaadi", src: `${TEMPLATE09_BUILDER_ASSET_ROOT}/assets/event/pn-evt-ico-shaadi-x-v01.webp` },
    { value: "reception", label: "Reception", src: `${TEMPLATE09_BUILDER_ASSET_ROOT}/assets/event/pn-evt-ico-reception-x-v01.webp` },
    { value: "vidaai", label: "Vidaai", src: `${TEMPLATE09_BUILDER_ASSET_ROOT}/assets/event/pn-evt-ico-vidaai-x-v01.webp` },
];
const TEMPLATE09_DEFAULT_PHOTOS = [
    "assets/Demo/Arch_Demo2.png",
    "assets/Demo/Arch_demo.png",
    "assets/Demo/landscape_demo.png",
    "assets/Demo/hero-arch_demo.png",
];
const TEMPLATE09_DEFAULT_THINGS = [
    { id: "dress-code", label: "Dress Code", value: "Festive Indian elegance in emerald, ivory, saffron, peacock blue, and gold." },
    { id: "venue", label: "Venue", value: "All ceremonies are inside the garden wing and courtyard." },
    { id: "stay-options", label: "Stay Options", value: "A small room block is reserved nearby. Please confirm travel plans early." },
    { id: "hashtag", label: "Wedding Hashtag", value: "Share your favourite moments with #AanyaRohanRaag." },
];
const TEMPLATE09_TABS = [
    { id: "sections", label: "Sections" },
    { id: "essentials", label: "Essentials" },
    { id: "invitation", label: "Invitation" },
    { id: "events", label: "Events" },
    { id: "story", label: "Story" },
    { id: "gallery", label: "Gallery" },
    { id: "info", label: "Info" },
    { id: "rsvp", label: "RSVP" },
    { id: "music", label: "Music" },
];
function builderMusicConfig(value, nativeMusic) {
    const input = { ...(nativeMusic || {}), ...(value || {}) };
    return window.EverafterMusicConfig ? window.EverafterMusicConfig.normalize(input, nativeMusic) : input;
}
function builderNewDraftMusic(config, existing, templateId) {
    if (existing)
        return config;
    config = JSON.parse(JSON.stringify(config));
    if (config.gallery)
        config.gallery.photos = [];
    if (Array.isArray(config.story))
        config.story = config.story.map(row => ({ ...row, image: '' }));
    else if (config.story) {
        if ('photo' in config.story)
            config.story.photo = '';
        if (config.story.photoStrip)
            config.story.photoStrip.frames = [];
    }
    if (config.coupleSection?.moments)
        config.coupleSection.moments = config.coupleSection.moments.map(row => ({ ...row, image: '' }));
    if (Array.isArray(config.memories))
        config.memories = [];
    if (Array.isArray(config.events))
        config.events = config.events.map(row => ({ ...row, ...(Array.isArray(row.photos) ? { photos: [] } : {}), ...('image' in row ? { image: '' } : {}) }));
    const music = { ...(config.music || {}), source: 'template', enabled: true };
    if (templateId === 'royal-pichwai')
        music.src = builderAppPath('/wedding-invitations/uploads/builder-templates/Royal%20Pichwai/assets/song/romantic-lofi-vibedepot.mp3');
    return { ...config, music };
}
function useBuilderPhotoUploads({ templateId, projectId, user }) {
    const owner = user?.id || user?.email || 'anonymous';
    const key = JSON.stringify([templateId, projectId || 'new', owner]);
    const current = React.useRef(null);
    const [, refresh] = React.useState(0);
    if (!current.current || current.current.key !== key) {
        if (current.current)
            current.current.active = false;
        current.current = { key, active: true, tickets: new Set(), projectId: projectId || undefined };
    }
    const scope = current.current;
    React.useEffect(() => {
        scope.active = true;
        return () => { scope.active = false; scope.tickets.clear(); };
    }, [scope]);
    return React.useMemo(() => ({
        projectId: scope.projectId,
        get busy() { return scope.tickets.size > 0; },
        pending: () => scope.active && scope.tickets.size > 0,
        begin(fieldId) {
            if (!scope.active || scope.tickets.size)
                return null;
            const ticket = { fieldId, route: (window.location?.pathname || '') + (window.location?.search || '') };
            scope.tickets.add(ticket);
            refresh(value => value + 1);
            return ticket;
        },
        isCurrent(ticket) {
            const liveUser = typeof loadUser === 'function' ? loadUser() : user;
            return scope.active && current.current === scope && scope.tickets.has(ticket) &&
                (liveUser?.id || liveUser?.email || 'anonymous') === owner &&
                ticket.route === (window.location?.pathname || '') + (window.location?.search || '');
        },
        finish(ticket) {
            if (scope.tickets.delete(ticket) && scope.active && current.current === scope)
                refresh(value => value + 1);
        },
    }), [scope]);
}
function template09BaseDraft(seed = {}, options = {}) {
    const stored = options.ignoreSaved ? null : readTemplate09Config();
    const saved = options.source || (isLegacyGlobalSeedDraft(stored, "royal-pichwai") ? null : stored);
    const source = saved || {};
    const couple = source.couple || {};
    const invite = source.invite || {};
    const story = source.story || {};
    const gallery = source.gallery || {};
    const rsvp = source.rsvp || {};
    const music = source.music || {};
    const closing = source.closing || {};
    return builderNewDraftMusic({
        ...cloneDraft(source),
        couple: {
            bride: couple.bride ?? "Aanya",
            groom: couple.groom ?? "Rohan",
            date: couple.date ?? "2026-12-14",
            venue: couple.venue ?? "Peacock Garden Haveli, Jaipur",
            whatsapp: couple.whatsapp ?? "",
            hashtag: couple.hashtag ?? "#AanyaRohanRaag",
        },
        invite: {
            show: invite.show !== false,
            blessing: invite.blessing ?? "With the blessings of the divine and the love of our families",
            parentsOrder: invite.parentsOrder ?? "bride_first",
            brideFather: invite.brideFather ?? "Mr. Dev Malhotra",
            brideMother: invite.brideMother ?? "Mrs. Naina Malhotra",
            groomFather: invite.groomFather ?? "Mr. Vikram Mehta",
            groomMother: invite.groomMother ?? "Mrs. Leela Mehta",
            showGrandparents: Boolean(invite.showGrandparents),
            brideGF: invite.brideGF ?? "",
            brideGM: invite.brideGM ?? "",
            groomGF: invite.groomGF ?? "",
            groomGM: invite.groomGM ?? "",
        },
        events: Array.isArray(source.events) && !isLegacyTemplate09Events(source.events)
            ? source.events
            : TEMPLATE09_DEFAULT_EVENTS,
        story: {
            show: story.show !== false,
            storyMode: story.storyMode ?? "story",
            storyText: story.storyText ?? "They first met over a shared cup of masala chai after a music rehearsal in Jaipur. One quiet walk through the old city became many, and somewhere between sunrise ragas, family dinners, and an almost-forgotten umbrella, they found home in each other.",
            tags: Array.isArray(story.tags) ? story.tags : ["chai at sunrise", "old city walks", "music always"],
        },
        gallery: {
            show: gallery.show !== false,
            layout: gallery.layout ?? "4",
            photos: Array.isArray(gallery.photos) ? gallery.photos : TEMPLATE09_DEFAULT_PHOTOS,
        },
        thingsToKnow: Array.isArray(source.thingsToKnow) ? source.thingsToKnow : TEMPLATE09_DEFAULT_THINGS,
        rsvp: {
            show: rsvp.show !== false,
            mode: rsvp.mode ?? "whatsapp",
            heading: rsvp.heading ?? "Celebrate with us?",
            subtext: rsvp.subtext ?? "We have kept a place for you beside the lamps, the music, and the people who made this story possible. Come mark the beginning with us.",
            btnText: rsvp.btnText ?? "Confirm your wishes",
            whatsapp: rsvp.whatsapp ?? couple.whatsapp ?? "",
            form_url: rsvp.form_url ?? "",
        },
        music: builderMusicConfig(music, { enabled: false, src: music.source === "template" ? builderAppPath("/wedding-invitations/uploads/builder-templates/Royal%20Pichwai/assets/song/romantic-lofi-vibedepot.mp3") : "assets/song/romantic-lofi-vibedepot.mp3", name: "Romantic Lofi" }),
        closing: {
            show: closing.show !== false,
            line: closing.line ?? "Your blessings make the evening whole.",
        },
    }, saved, 'royal-pichwai');
}
function readTemplate09Config() { return readBuilderConfig(TEMPLATE09_CONFIG_KEY); }
function writeTemplate09Config(config) { writeBuilderConfig(TEMPLATE09_CONFIG_KEY, config); }
function isLegacyGlobalSeedDraft(config, templateId) {
    if (!config || typeof config !== "object")
        return false;
    const couple = config.couple || {};
    const bride = String(couple.bride || "").trim();
    const groom = String(couple.groom || "").trim();
    const venue = String(couple.venue || "").trim();
    const date = String(couple.date || "").trim();
    if (templateId === "royal-pichwai") {
        return bride === "Aanya" && groom === "Rohan" && venue === "Udai Bagh, Udaipur";
    }
    if (templateId === "moonlit-mehfil") {
        return bride === "Aanya" && groom === "Rohan" && (venue === "Udai Bagh, Udaipur" || date === "2026-12-14");
    }
    if (templateId === "vivaha") {
        return bride === "Aanya" && groom === "Rohan" && (venue === "Udai Bagh, Udaipur" || date === "2026-12-14");
    }
    return false;
}
function isLegacyTemplate09Events(events) {
    if (!Array.isArray(events) || events.length !== TEMPLATE09_LEGACY_EVENTS.length)
        return false;
    return TEMPLATE09_LEGACY_EVENTS.every((legacy, index) => {
        const event = events[index] || {};
        return ["id", "name", "date", "time", "venue", "desc"].every((key) => String(event[key] || "") === String(legacy[key] || ""));
    });
}
function cloneDraft(value) {
    return JSON.parse(JSON.stringify(value));
}
function setDeepDraft(draft, path, value) {
    const next = cloneDraft(draft);
    let target = next;
    path.slice(0, -1).forEach((key) => { target = target[key]; });
    target[path[path.length - 1]] = value;
    if (typeof value === 'boolean' && path.length === 2 && (path[0] === 'visibility' || path[1] === 'show')) {
        const section = path[0] === 'visibility' ? path[1] : ({ invite: 'invitation', coupleSection: 'couple' }[path[0]] || path[0]);
        next.sections = { ...(next.sections || {}), [section]: value };
    }
    return next;
}
function addDaysIso(iso, days) {
    if (!iso)
        return "";
    const [y, m, d] = iso.split("-").map(Number);
    const date = new Date(Date.UTC(y, (m || 1) - 1, d || 1));
    date.setUTCDate(date.getUTCDate() + days);
    return date.toISOString().slice(0, 10);
}
function buildCalendarUrls(couple) {
    if (!/^\d{4}-\d{2}-\d{2}$/.test(couple.date || ""))
        return { google: "", apple: "" };
    const parsedDate = new Date(couple.date + "T00:00:00Z");
    if (!Number.isFinite(parsedDate.getTime()) || parsedDate.toISOString().slice(0, 10) !== couple.date)
        return { google: "", apple: "" };
    const bride = couple.bride || "Bride";
    const groom = couple.groom || "Groom";
    const start = (couple.date || "2026-12-14").replace(/-/g, "");
    const end = addDaysIso(couple.date || "2026-12-14", 1).replace(/-/g, "");
    const title = `${bride} weds ${groom}`;
    const location = couple.venue || "";
    const google = "https://calendar.google.com/calendar/render?" + new URLSearchParams({
        action: "TEMPLATE",
        text: title,
        dates: `${start}/${end}`,
        location,
    }).toString();
    const apple = "data:text/calendar;charset=utf8," + encodeURIComponent([
        "BEGIN:VCALENDAR",
        "VERSION:2.0",
        "BEGIN:VEVENT",
        `DTSTART:${start}`,
        `DTEND:${end}`,
        `SUMMARY:${title}`,
        `LOCATION:${location}`,
        "END:VEVENT",
        "END:VCALENDAR",
    ].join("\n"));
    return { google, apple };
}
function buildTemplate09Config(draft) {
    const config = cloneDraft(draft);
    config.events = Array.isArray(config.events)
        ? config.events.filter((event) => event.name || event.date || event.time || event.venue)
        : [];
    config.gallery.photos = (config.gallery.photos || []).filter(Boolean);
    config.thingsToKnow = Array.isArray(config.thingsToKnow)
        ? config.thingsToKnow.filter((item) => item.label || item.value)
        : [];
    config.calendarUrls = buildCalendarUrls(config.couple);
    return config;
}
function template09DisplayDate(iso) {
    if (!iso)
        return "";
    const [y, m, d] = iso.split("-");
    const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    return `${Number(d)} ${months[Number(m) - 1] || ""} ${y}`;
}
function resolveWeddingAssetUrl(assetPath) {
    try {
        return new URL(assetPath.startsWith("/") ? builderAppPath(assetPath) : assetPath, window.location.origin + "/").href;
    }
    catch (_) {
        return assetPath;
    }
}
function buildBuilderPreviewSrc(builderTemplateUrl, templateId, previewVersion, previewSession) {
    try {
        const url = new URL(builderTemplateUrl, window.location.origin + "/");
        const configKey = TemplateCatalog.get(templateId)?.configKey;
        if (configKey) {
            const draftKey = builderDraftKey(configKey);
            try {
                window.sessionStorage.setItem(draftKey, JSON.stringify(readBuilderConfig(configKey) || {}));
            }
            catch (_) { }
            url.searchParams.set('draftKey', draftKey);
        }
        url.searchParams.set("builder", "1");
        url.searchParams.set("frame", "builder");
        url.searchParams.set("v", String(previewVersion));
        if (previewSession)
            url.searchParams.set("session", previewSession);
        return url.href;
    }
    catch (_) {
        const sep = String(builderTemplateUrl || "").includes("?") ? "&" : "?";
        const session = previewSession ? `&session=${encodeURIComponent(previewSession)}` : "";
        return `${builderTemplateUrl}${sep}builder=1&frame=builder&v=${previewVersion}${session}`;
    }
}
function prepareBuilderPreviewDocument(frame, doc) {
    try {
        const body = doc?.body;
        const html = doc?.documentElement;
        if (!doc || !html || !body)
            return;
        html.dataset.everafterBuilderPreview = "1";
        body.dataset.everafterBuilderPreview = "1";
        try {
            frame.contentWindow.history.scrollRestoration = "manual";
        }
        catch (_) { }
        const resumeTop = Number(frame?.dataset?.everafterPreviewScrollY || 0);
        const shouldResumeEnteredPreview = Number.isFinite(resumeTop) && resumeTop > 8;
        const royalIntro = doc.getElementById("intro");
        if (royalIntro && royalIntro.classList?.contains("intro") && shouldResumeEnteredPreview) {
            royalIntro.classList.add("is-complete");
            body.classList.remove("intro-active");
        }
        if (shouldResumeEnteredPreview) {
            const moonlitIntro = doc.querySelector(".opening-film");
            const moonlitSkip = doc.querySelector(".op-skip");
            if (moonlitIntro && moonlitSkip && typeof moonlitSkip.click === "function") {
                moonlitSkip.click();
            }
        }
    }
    catch (_) { }
}
function resetBuilderPreviewScroll(frame, doc) {
    try {
        const win = frame?.contentWindow;
        if (!win || !doc)
            return;
        const src = frame.getAttribute("src") || "";
        if (frame.dataset.everafterResetSrc === src)
            return;
        frame.dataset.everafterResetSrc = src;
        let memoryKey = src;
        try {
            const url = new URL(src, window.location.href);
            url.searchParams.delete("v");
            memoryKey = `${url.pathname}?${url.searchParams.toString()}`;
        }
        catch (_) { }
        const previousMemoryKey = frame.dataset.everafterPreviewMemoryKey || "";
        if (previousMemoryKey && previousMemoryKey !== memoryKey) {
            frame.dataset.everafterPreviewScrollY = "0";
        }
        frame.dataset.everafterPreviewMemoryKey = memoryKey;
        const savedTop = previousMemoryKey === memoryKey ? Number(frame.dataset.everafterPreviewScrollY || 0) : 0;
        const targetTop = Number.isFinite(savedTop) && savedTop > 8 ? savedTop : 0;
        frame.dataset.everafterPreviewInteracted = "0";
        const reset = () => {
            try {
                if (frame.dataset.everafterPreviewInteracted === "1" || doc.documentElement?.dataset?.apologyPreviewSection)
                    return;
                win.scrollTo({ top: targetTop, left: 0, behavior: "auto" });
                if (doc.documentElement)
                    doc.documentElement.scrollTop = targetTop;
                if (doc.body)
                    doc.body.scrollTop = targetTop;
                win.dispatchEvent(new Event("scroll"));
            }
            catch (_) { }
        };
        [0, 80, 260, 700, 1400, 2400, 3600].forEach((delay) => window.setTimeout(reset, delay));
    }
    catch (_) { }
}
function hideBuilderPreviewScrollbars(eventOrFrame) {
    const frame = eventOrFrame?.currentTarget || eventOrFrame;
    const apply = () => {
        try {
            const doc = frame?.contentDocument;
            const head = doc?.head || doc?.getElementsByTagName?.("head")?.[0];
            if (!doc || !head)
                return false;
            let style = doc.getElementById("builder-preview-scrollbar-hide");
            if (!style) {
                style = doc.createElement("style");
                style.id = "builder-preview-scrollbar-hide";
                head.appendChild(style);
            }
            style.textContent = `
        html, body {
          overflow-x: visible !important;
          scrollbar-width: none !important;
          -ms-overflow-style: none !important;
        }
        html, body, * {
          scrollbar-width: none !important;
          -ms-overflow-style: none !important;
        }
        html::-webkit-scrollbar,
        body::-webkit-scrollbar,
        *::-webkit-scrollbar {
          display: none !important;
          width: 0 !important;
          height: 0 !important;
          background: transparent !important;
        }
        html[data-everafter-builder-preview="1"],
        body[data-everafter-builder-preview="1"] {
          overscroll-behavior: contain !important;
          scroll-behavior: auto !important;
          touch-action: pan-y !important;
        }
        html[data-everafter-builder-preview="1"] .film-site,
        body[data-everafter-builder-preview="1"] .film-site,
        html[data-everafter-builder-preview="1"] .scene-tunnel,
        body[data-everafter-builder-preview="1"] .scene-tunnel {
          overflow: visible !important;
        }
        html[data-everafter-builder-preview="1"] .tunnel-sticky,
        body[data-everafter-builder-preview="1"] .tunnel-sticky {
          position: sticky !important;
          top: 0 !important;
        }
        html[data-everafter-builder-preview="1"] .intro.is-lit .intro-bg-lit {
          opacity: 1 !important;
          animation: none !important;
        }
        html[data-everafter-builder-preview="1"] .intro.is-lit .intro-dark-vignette {
          opacity: 0 !important;
        }
        html[data-everafter-builder-preview="1"] .intro.is-lit .intro-warm-glow,
        html[data-everafter-builder-preview="1"] .intro.is-lit .intro-jhoomer-glow,
        html[data-everafter-builder-preview="1"] .intro.is-lit .diya-floor-glow,
        html[data-everafter-builder-preview="1"] .intro.is-lit .intro-rose-scatter,
        html[data-everafter-builder-preview="1"] .intro.is-lit .intro-dust,
        html[data-everafter-builder-preview="1"] .intro.is-lit .intro-petals {
          opacity: 1 !important;
        }
        html[data-everafter-builder-preview="1"] .intro.show-names .intro-reveal::before,
        html[data-everafter-builder-preview="1"] .intro.show-names .intro-reveal::after {
          opacity: 1 !important;
          transform: translateX(-50%) scale(1) !important;
        }
        html[data-everafter-builder-preview="1"] .intro.show-names .intro-reveal::before {
          transform: translate(-50%, -50%) scale(1) !important;
        }
        html[data-everafter-builder-preview="1"] .intro.show-names .names,
        html[data-everafter-builder-preview="1"] .intro.show-date .ornament,
        html[data-everafter-builder-preview="1"] .intro.show-date .date,
        html[data-everafter-builder-preview="1"] .intro.show-venue .venue,
        html[data-everafter-builder-preview="1"] .intro.show-lotus .lotus-cta-group,
        html[data-everafter-builder-preview="1"] .intro.show-names .names .word {
          opacity: 1 !important;
          transform: translateX(-50%) translateY(0) scale(1) !important;
          transition-delay: 0ms !important;
        }
        html[data-everafter-builder-preview="1"] .intro.show-names .names .word {
          transform: translateY(0) scale(1) !important;
        }
        html[data-everafter-builder-preview="1"] .intro.show-lotus .lotus-cta-group {
          transform: translate(-50%, 0) scale(1) !important;
        }
      `;
            if (doc.documentElement) {
                doc.documentElement.dataset.everafterBuilderPreview = "1";
                doc.documentElement.style.scrollbarWidth = "none";
                doc.documentElement.style.overflowX = "visible";
                doc.documentElement.style.touchAction = "pan-y";
            }
            if (doc.body) {
                doc.body.dataset.everafterBuilderPreview = "1";
                doc.body.style.scrollbarWidth = "none";
                doc.body.style.overflowX = "visible";
                doc.body.style.touchAction = "pan-y";
            }
            prepareBuilderPreviewDocument(frame, doc);
            resetBuilderPreviewScroll(frame, doc);
            installBuilderPreviewScrollControl(frame, doc);
            return true;
        }
        catch (_) {
            return false;
        }
    };
    apply();
    window.setTimeout(apply, 80);
    window.setTimeout(apply, 350);
    window.setTimeout(apply, 1000);
    window.setTimeout(apply, 3000);
    window.setTimeout(apply, 4800);
}
function installBuilderPreviewScrollControl(frame, doc) {
    if (!frame || !doc || !frame.contentWindow || doc.__everafterBuilderScrollControl)
        return;
    doc.__everafterBuilderScrollControl = true;
    let lastTouchY = null;
    let lastUnlockAt = 0;
    const markInteracted = () => {
        try {
            frame.dataset.everafterPreviewInteracted = "1";
        }
        catch (_) { }
    };
    const currentScroll = () => (frame.contentWindow?.scrollY ||
        doc.documentElement?.scrollTop ||
        doc.body?.scrollTop ||
        0);
    const rememberScroll = () => {
        try {
            frame.dataset.everafterPreviewScrollY = String(Math.max(0, Math.round(currentScroll())));
        }
        catch (_) { }
    };
    const maxScroll = () => {
        const html = doc.documentElement;
        const body = doc.body;
        const height = Math.max(html?.scrollHeight || 0, body?.scrollHeight || 0);
        const viewport = frame.contentWindow?.innerHeight || html?.clientHeight || 0;
        return Math.max(0, height - viewport);
    };
    const applyScrollBy = (deltaY) => {
        const win = frame.contentWindow;
        if (!win || !deltaY || maxScroll() < 24)
            return;
        const before = currentScroll();
        try {
            win.scrollBy({ top: deltaY, left: 0, behavior: "auto" });
        }
        catch (_) {
            try {
                win.scrollBy(0, deltaY);
            }
            catch (__) { }
        }
        window.setTimeout(() => {
            if (Math.abs(currentScroll() - before) <= 2) {
                const top = Math.max(0, Math.min(maxScroll(), before + deltaY));
                if (doc.documentElement)
                    doc.documentElement.scrollTop = top;
                if (doc.body)
                    doc.body.scrollTop = top;
            }
            rememberScroll();
            try {
                win.dispatchEvent(new Event("scroll"));
            }
            catch (_) { }
        }, 20);
    };
    const nudgeNativeScroll = (deltaY, delay = 80) => {
        window.setTimeout(() => applyScrollBy(deltaY), delay);
    };
    const fallbackScrollIfNeeded = (before, deltaY, delay = 70) => {
        if (!deltaY || maxScroll() < 24)
            return;
        window.setTimeout(() => {
            if (Math.abs(currentScroll() - before) <= 2)
                applyScrollBy(deltaY);
        }, delay);
    };
    const unlockIntroIfNeeded = () => {
        let unlocked = false;
        const now = Date.now();
        if (now - lastUnlockAt < 260)
            return false;
        const skipIntro = doc.getElementById("skipIntro") || doc.querySelector(".skip-intro");
        if (doc.body?.classList?.contains("intro-active")) {
            if (skipIntro && typeof skipIntro.click === "function") {
                skipIntro.click();
                unlocked = true;
            }
            else {
                doc.body.classList.remove("intro-active");
                const intro = doc.getElementById("intro");
                if (intro)
                    intro.classList.add("is-complete");
                unlocked = true;
            }
        }
        const moonlitIntro = doc.querySelector(".opening-film");
        const moonlitSkip = doc.querySelector(".op-skip");
        if (moonlitIntro && moonlitSkip && typeof moonlitSkip.click === "function") {
            moonlitSkip.click();
            unlocked = true;
        }
        if (unlocked)
            lastUnlockAt = now;
        return unlocked;
    };
    doc.addEventListener("wheel", (event) => {
        markInteracted();
        const deltaY = event.deltaY || 0;
        const before = currentScroll();
        if (unlockIntroIfNeeded()) {
            if (event.cancelable)
                event.preventDefault();
            nudgeNativeScroll(deltaY || 280);
        }
        else {
            fallbackScrollIfNeeded(before, deltaY, 160);
        }
        window.setTimeout(rememberScroll, 80);
        window.setTimeout(rememberScroll, 260);
    }, { capture: true, passive: false });
    doc.addEventListener("pointerdown", markInteracted, { capture: true, passive: true });
    doc.addEventListener("touchstart", (event) => {
        markInteracted();
        lastTouchY = event.touches?.[0]?.clientY ?? null;
        unlockIntroIfNeeded();
        window.setTimeout(rememberScroll, 160);
    }, { capture: true, passive: true });
    doc.addEventListener("touchmove", (event) => {
        markInteracted();
        const currentY = event.touches?.[0]?.clientY ?? null;
        const deltaY = currentY == null || lastTouchY == null ? 240 : lastTouchY - currentY;
        lastTouchY = currentY;
        const before = currentScroll();
        if (unlockIntroIfNeeded()) {
            if (event.cancelable)
                event.preventDefault();
            nudgeNativeScroll(deltaY || 280);
        }
        else {
            fallbackScrollIfNeeded(before, deltaY || 240, 160);
        }
        window.setTimeout(rememberScroll, 120);
    }, { capture: true, passive: false });
    doc.addEventListener("keydown", markInteracted, { capture: true, passive: true });
    frame.contentWindow.addEventListener("scroll", rememberScroll, { passive: true });
}
function focusBuilderPreviewFrame(event) {
    try {
        const frame = event.currentTarget?.querySelector?.("iframe") || event.currentTarget;
        if (frame && typeof frame.focus === "function") {
            frame.focus({ preventScroll: true });
        }
    }
    catch (_) { }
}
function scrollBuilderEditorIntoView(event) {
    try {
        const root = event?.currentTarget?.closest?.(".saas-template-builder") || document;
        const editor = root.querySelector?.(".saas-builder-side");
        editor?.scrollIntoView?.({ behavior: "smooth", block: "start" });
    }
    catch (_) { }
}
const BUILDER_PREVIEW_TAB_TARGETS = {
    "royal-pichwai": {
        essentials: "#intro",
        invitation: "#invite",
        events: "#events",
        story: "#couple",
        gallery: "#gallery",
        info: "#things",
        rsvp: "#rsvp",
        music: "#intro",
    },
    "moonlit-mehfil": {
        essentials: "#story",
        story: "#tunnel",
        events: "#events",
        couple: "#couple",
        gallery: "#gallery",
        rsvp: "#rsvp",
        music: "#story",
    },
    vivaha: {
        essentials: "#top",
        story: "#story-start",
        photos: "#our-story",
        events: "#ceremonies",
        closing: "#rsvp",
        visibility: "#top",
    },
};
function unlockBuilderPreviewIntro(frame, doc) {
    try {
        const royalSkip = doc.getElementById("skipIntro") || doc.querySelector(".skip-intro");
        if (doc.body?.classList?.contains("intro-active") && royalSkip && typeof royalSkip.click === "function") {
            royalSkip.click();
        }
        const moonlitSkip = doc.querySelector(".op-skip");
        if (moonlitSkip && typeof moonlitSkip.click === "function")
            moonlitSkip.click();
        prepareBuilderPreviewDocument(frame, doc);
        if (frame?.contentWindow)
            frame.contentWindow.dispatchEvent(new Event("scroll"));
    }
    catch (_) { }
}
function scrollBuilderPreviewToTab(templateId, tab, options = {}) {
    const delay = options.delay ?? 120;
    const attempts = options.attempts || [delay, delay + 520, delay + 1350];
    attempts.forEach((attemptDelay, index) => window.setTimeout(() => {
        try {
            const frame = document.querySelector(".saas-preview-workspace iframe") || document.querySelector(".saas-phone-preview iframe");
            const doc = frame?.contentDocument;
            const win = frame?.contentWindow;
            if (!frame || !doc || !win)
                return;
            unlockBuilderPreviewIntro(frame, doc);
            const selector = BUILDER_PREVIEW_TAB_TARGETS[templateId]?.[tab];
            if (!selector)
                return;
            const target = doc.querySelector(selector);
            if (!target)
                return;
            const top = Math.max(0, target.getBoundingClientRect().top + (win.scrollY || doc.documentElement?.scrollTop || 0) - 8);
            win.scrollTo({ top, left: 0, behavior: options.instant || index > 0 ? "auto" : "smooth" });
            window.setTimeout(() => {
                try {
                    win.dispatchEvent(new Event("scroll"));
                }
                catch (_) { }
            }, 220);
        }
        catch (_) { }
    }, attemptDelay));
}
function BuilderActionLabel({ full, compact }) {
    return (React.createElement(React.Fragment, null,
        React.createElement("span", { className: "builder-label-full" }, full),
        React.createElement("span", { className: "builder-label-compact" }, compact || full)));
}
const BUILDER_MOBILE_VIEWPORT = { width: 390, height: 844 };
function BuilderPhonePreview({ activeTemplate, fallbackName, previewSrc, onRequestClose, freezeSource = false }) {
    const screenRef = React.useRef(null);
    const initialSource = React.useRef(previewSrc);
    const frameKeyCleanup = React.useRef(null);
    const closePreview = React.useRef(onRequestClose);
    const iframeSrc = freezeSource ? initialSource.current : previewSrc;
    const [visible, setVisible] = React.useState(false);
    const [loaded, setLoaded] = React.useState(false);
    const [viewportBox, setViewportBox] = React.useState({ width: BUILDER_MOBILE_VIEWPORT.width, height: BUILDER_MOBILE_VIEWPORT.height });
    React.useEffect(() => { closePreview.current = onRequestClose; }, [onRequestClose]);
    React.useEffect(() => () => frameKeyCleanup.current?.(), []);
    React.useEffect(() => { setLoaded(false); }, [iframeSrc, visible]);
    React.useLayoutEffect(() => {
        const screen = screenRef.current;
        if (!screen)
            return undefined;
        const measure = () => {
            const rect = screen.getBoundingClientRect();
            setVisible(rect.width > 0 && rect.height > 0);
            if (rect.width <= 0 || rect.height <= 0)
                return;
            setViewportBox({
                width: Math.max(1, Math.round(rect.width)),
                height: Math.max(1, Math.round(rect.height)),
            });
        };
        measure();
        let resizeObserver = null;
        if (typeof ResizeObserver !== "undefined") {
            resizeObserver = new ResizeObserver(measure);
            resizeObserver.observe(screen);
        }
        window.addEventListener("resize", measure);
        return () => {
            if (resizeObserver)
                resizeObserver.disconnect();
            window.removeEventListener("resize", measure);
        };
    }, []);
    const title = (activeTemplate?.name || fallbackName || "Invitation") + " preview";
    const onFrameLoad = (event) => {
        hideBuilderPreviewScrollbars(event);
        setLoaded(true);
        frameKeyCleanup.current?.();
        frameKeyCleanup.current = null;
        if (!closePreview.current)
            return;
        try {
            const doc = event.currentTarget.contentDocument;
            const escape = (keyEvent) => {
                if (keyEvent.key !== 'Escape')
                    return;
                keyEvent.preventDefault();
                keyEvent.stopPropagation();
                closePreview.current?.();
            };
            doc?.addEventListener('keydown', escape, true);
            frameKeyCleanup.current = () => doc?.removeEventListener('keydown', escape, true);
        }
        catch (_) { }
    };
    return (React.createElement("div", { className: "builder-phone-emu phone-emu-wrap" },
        React.createElement("div", { className: "phone-emu-frame", onClick: focusBuilderPreviewFrame },
            React.createElement("div", { className: "phone-emu-bezel" },
                React.createElement("div", { className: "phone-emu-screen", ref: screenRef },
                    React.createElement("div", { className: "phone-emu-mobile-viewport", style: {
                            width: viewportBox.width,
                            height: viewportBox.height,
                            transform: "none",
                        } },
                        visible && React.createElement("iframe", { title: title, src: iframeSrc, allow: "autoplay 'none'", onLoad: onFrameLoad, tabIndex: 0 }),
                        visible && !loaded && React.createElement("div", { className: "builder-preview-loading", role: "status" }, "Loading preview\u2026"))),
                React.createElement("div", { className: "phone-emu-island" },
                    React.createElement("span", { className: "phone-emu-island-dot" }),
                    React.createElement("span", { className: "phone-emu-island-bar" })),
                React.createElement("span", { className: "phone-emu-btn phone-emu-btn-mute" }),
                React.createElement("span", { className: "phone-emu-btn phone-emu-btn-vup" }),
                React.createElement("span", { className: "phone-emu-btn phone-emu-btn-vdown" }),
                React.createElement("span", { className: "phone-emu-btn phone-emu-btn-power" })))));
}
function BuilderPreviewWindow({ open, onClose, activeTemplate, fallbackName, previewSrc }) {
    const dialogRef = React.useRef(null);
    const backdropStart = React.useRef(false);
    const titleId = React.useRef('builder-preview-title-' + Math.random().toString(36).slice(2, 9));
    const templateName = activeTemplate?.name || fallbackName || 'Invitation';
    React.useLayoutEffect(() => {
        const dialog = dialogRef.current;
        if (!dialog || !open)
            return undefined;
        const body = document.body;
        const page = document.documentElement;
        const oldBodyOverflow = body.style.overflow;
        const oldPageOverflow = page.style.overflow;
        const oldOverscroll = page.style.overscrollBehavior;
        body.style.overflow = 'hidden';
        page.style.overflow = 'hidden';
        page.style.overscrollBehavior = 'none';
        if (!dialog.open)
            dialog.showModal();
        dialog.querySelector('.builder-return-action')?.focus({ preventScroll: true });
        return () => {
            if (dialog.open)
                dialog.close();
            body.style.overflow = oldBodyOverflow;
            page.style.overflow = oldPageOverflow;
            page.style.overscrollBehavior = oldOverscroll;
            backdropStart.current = false;
        };
    }, [open]);
    const isOutsideSheet = (event) => {
        if (event.target !== event.currentTarget)
            return false;
        const rect = event.currentTarget.getBoundingClientRect();
        return event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom;
    };
    return (React.createElement("dialog", { ref: dialogRef, className: "builder-preview-sheet", "aria-labelledby": titleId.current, onCancel: (event) => { event.preventDefault(); onClose(); }, onClose: () => { if (open)
            onClose(); }, onPointerDown: (event) => { backdropStart.current = isOutsideSheet(event); }, onClick: (event) => { if (backdropStart.current && isOutsideSheet(event))
            onClose(); backdropStart.current = false; } },
        React.createElement("header", { className: "builder-preview-sheet-header" },
            React.createElement("span", { className: "builder-preview-sheet-handle", "aria-hidden": "true" }),
            React.createElement("div", { className: "builder-preview-sheet-toolbar" },
                React.createElement("button", { type: "button", className: "builder-return-action", onClick: onClose },
                    React.createElement("span", { "aria-hidden": "true" }, "\u2190"),
                    " Back to editing"),
                React.createElement("div", { className: "builder-preview-sheet-heading" },
                    React.createElement("span", null, "Preview so far"),
                    React.createElement("h2", { className: "builder-preview-sheet-title", id: titleId.current }, templateName)),
                React.createElement("button", { type: "button", className: "builder-preview-sheet-close", "aria-label": "Close preview", onClick: onClose },
                    React.createElement("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "none", stroke: "currentColor", strokeWidth: "1.6", "aria-hidden": "true" },
                        React.createElement("path", { d: "m6 6 12 12M18 6 6 18" }))))),
        React.createElement("div", { className: "builder-preview-sheet-body" }, open && React.createElement(BuilderPhonePreview, { activeTemplate: activeTemplate, fallbackName: fallbackName, previewSrc: previewSrc, onRequestClose: onClose, freezeSource: true }))));
}
function useBuilderPreviewPolish(deps) {
    React.useEffect(() => {
        const run = () => {
            document.querySelectorAll(".saas-preview-workspace iframe, .builder-preview-sheet iframe").forEach((frame) => {
                hideBuilderPreviewScrollbars(frame);
            });
        };
        const timers = [0, 120, 420, 1100, 2200].map((delay) => window.setTimeout(run, delay));
        return () => timers.forEach((timer) => window.clearTimeout(timer));
    }, deps);
}
function syncBuilderProjectUrl(templateId, projectId, api = window.EA) {
    if (api?.isAdminEditor)
        return api.syncProjectUrl(templateId, projectId);
    if (!templateId || !projectId)
        return;
    window.EA_ACTIVE_PROJECT_ID = projectId;
    try {
        window.localStorage.setItem("ea-project-id-" + templateId, projectId);
    }
    catch (_) { }
    const path = builderAppPath(`/builder/${templateId}?project=${encodeURIComponent(projectId)}`);
    if (window.location.pathname + window.location.search === path)
        return;
    window.history.replaceState({ view: "builder", templateId, projectId }, "", path);
}
function useLoadedProjectConfig({ projectId, templateId, user, verifiedProject, verifiedOwnerId, recoveredDraft, setActiveProjectId, setDraft, makeDraft, writeConfig, setPreviewVersion, setSavedAt, onConfigLoaded, loadPendingRef }) {
    const api = useBuilderApi();
    const makeDraftRef = React.useRef(makeDraft);
    React.useEffect(() => { makeDraftRef.current = makeDraft; });
    React.useEffect(() => {
        setActiveProjectId(projectId || null);
        if (!projectId || !api?.isLoggedIn())
            return;
        if (verifiedProject?.id === projectId && verifiedOwnerId === user?.id && TemplateCatalog.normalizeId(verifiedProject.template_id) === templateId) {
            if (loadPendingRef)
                loadPendingRef.current = false;
            setSavedAt(recoveredDraft ? 'Restored on this device. Save draft to update your account.' : 'Loaded');
            return;
        }
        let cancelled = false;
        if (loadPendingRef)
            loadPendingRef.current = true;
        api.getProject(projectId)
            .then((res) => {
            if (cancelled)
                return;
            const project = res.project;
            if (!project || TemplateCatalog.normalizeId(project.template_id) !== templateId) {
                setActiveProjectId(null);
                window.history.replaceState({ view: "builder", templateId, projectId: null }, "", builderAppPath(`/builder/${templateId}`));
                return;
            }
            const loadedConfig = project.config || {};
            writeConfig(loadedConfig);
            if (typeof onConfigLoaded === "function")
                onConfigLoaded(loadedConfig);
            setDraft(makeDraftRef.current(loadedConfig));
            setSavedAt("Loaded");
            setPreviewVersion((v) => v + 1);
        })
            .catch(() => { })
            .finally(() => { if (loadPendingRef)
            loadPendingRef.current = false; });
        return () => {
            cancelled = true;
            if (loadPendingRef)
                loadPendingRef.current = false;
        };
    }, [projectId, templateId, user?.id, user?.email, verifiedProject, verifiedOwnerId, recoveredDraft]);
}
function useBuilderAutosave({ config, activeProjectId, templateId, user, writeConfig, setPreviewVersion, setSavedAt, skipNextRef, loadPendingRef, uploading = false, photoUploads }) {
    const api = useBuilderApi();
    React.useEffect(() => {
        if (uploading)
            return;
        if (skipNextRef?.current) {
            skipNextRef.current = false;
            return;
        }
        if (loadPendingRef?.current)
            return;
        let cancelled = false;
        try {
            writeConfig(config);
            markBuilderDraftPending(templateId, activeProjectId);
            setSavedAt('Saved on this device');
        }
        catch (err) {
            setSavedAt('Save failed: ' + err.message);
            return;
        }
        const id = window.setTimeout(async () => {
            if (cancelled || loadPendingRef?.current || photoUploads?.pending())
                return;
            try {
                setPreviewVersion(v => v + 1);
                const remote = activeProjectId && api?.isLoggedIn() && window.EA_UI_PREVIEW !== true;
                if (remote) {
                    validateBuilderMedia(config);
                    await api.saveProject(activeProjectId, config, builderProjectName(config, templateId));
                    markBuilderDraftSaved(templateId, activeProjectId, config);
                }
                if (!cancelled)
                    setSavedAt(remote ? (api.isAdminEditor ? 'Saved for the customer' : 'Saved to your account') : 'Saved on this device');
            }
            catch (err) {
                if (!cancelled)
                    setSavedAt('Save failed: ' + err.message);
            }
        }, BUILDER_AUTOSAVE_DELAY);
        return () => { cancelled = true; window.clearTimeout(id); };
    }, [config, activeProjectId, templateId, user?.id, user?.email, uploading]);
}
function useBuilderPreviewNavigation(isPreviewMode, setIsPreviewMode) {
    const editorPosition = React.useRef(null);
    const previousMode = React.useRef(isPreviewMode);
    React.useLayoutEffect(() => {
        if (previousMode.current === isPreviewMode)
            return;
        previousMode.current = isPreviewMode;
        const root = document.querySelector('.saas-template-builder');
        if (!isPreviewMode && editorPosition.current) {
            const position = editorPosition.current;
            editorPosition.current = null;
            window.requestAnimationFrame(() => {
                const form = root?.querySelector('.saas-builder-form');
                if (form)
                    form.scrollTop = position.formTop;
                window.scrollTo({ top: position.pageTop, left: position.pageLeft, behavior: 'instant' });
                if (position.trigger?.isConnected)
                    position.trigger.focus({ preventScroll: true });
            });
        }
    }, [isPreviewMode]);
    return {
        enterPreview(event) {
            if (!isPreviewMode) {
                const form = document.querySelector('.saas-template-builder .saas-builder-form');
                editorPosition.current = { pageTop: window.scrollY || 0, pageLeft: window.scrollX || 0, formTop: form?.scrollTop || 0, trigger: event?.currentTarget || document.activeElement };
            }
            setIsPreviewMode(true);
        },
        returnToEditor() { setIsPreviewMode(false); },
    };
}
function BuilderProgressActions({ tabs, tab, onTabChange, onPreview, disabled = false }) {
    const sections = tabs.map(item => Array.isArray(item) ? { id: item[0], label: item[1] } : item);
    const index = sections.findIndex(item => item.id === tab);
    const next = sections[index + 1];
    const advance = () => {
        if (!next || disabled)
            return;
        onTabChange(next.id);
        window.requestAnimationFrame(() => {
            const form = document.querySelector('.saas-template-builder .saas-builder-form');
            if (!form)
                return;
            form.scrollTop = 0;
            if (window.matchMedia('(max-width: 820px)').matches)
                form.scrollIntoView({ block: 'start', behavior: 'instant' });
            form.querySelector('.builder-panel-title h3')?.focus({ preventScroll: true });
        });
    };
    return (React.createElement("div", { className: 'builder-progress-actions' + (next ? '' : ' is-last-section'), "aria-label": "Invitation editing actions" },
        React.createElement("p", null,
            index + 1,
            " of ",
            sections.length,
            React.createElement("span", { "aria-hidden": "true" }, " \u00B7 "),
            sections[index]?.label),
        React.createElement("div", { className: "builder-progress-buttons" },
            React.createElement("button", { type: "button", className: "builder-preview-so-far", onClick: onPreview, disabled: disabled },
                React.createElement("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "none", stroke: "currentColor", strokeWidth: "1.6", "aria-hidden": "true" },
                    React.createElement("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z" }),
                    React.createElement("circle", { cx: "12", cy: "12", r: "3" })),
                "Preview so far"),
            next && React.createElement("button", { type: "button", className: "builder-next-section", onClick: advance, disabled: disabled, "aria-label": 'Next section: ' + next.label },
                "Next section ",
                React.createElement("span", { "aria-hidden": "true" }, "\u2192")))));
}
function builderSaveStatus(savedAt) {
    if (!savedAt)
        return "Changes save on this device. Save a draft to keep it in your dashboard.";
    if (savedAt === "Loaded")
        return "Your saved invitation is ready.";
    return /^\d/.test(savedAt) ? "Saved at " + savedAt : savedAt;
}
function BuilderPreviewNotice({ compact = false }) {
    return React.createElement("p", { className: 'builder-ui-preview-note' + (compact ? ' is-compact' : ''), role: "note" }, "UI preview: edits save on this device. Publishing and photo uploads are unavailable.");
}
function BuilderTemplateChooser({ goTo, unavailable = false }) {
    const templates = TemplateCatalog.list("builder");
    const [category, setCategory] = React.useState("all");
    const visible = templates.filter((template) => templateMatchesCategory(template, category));
    const demoHref = (template) => {
        const path = window.EA_APP?.path ? window.EA_APP.path(template.demoPath) : template.demoPath;
        const url = new URL(path, window.location.origin);
        url.searchParams.set('demo', '1');
        return url.href;
    };
    return (React.createElement("main", { className: "section gallery-page builder-chooser" },
        React.createElement("div", { className: "wrap" },
            React.createElement("div", { className: "builder-chooser-heading" },
                React.createElement("h1", { className: "display" }, "Choose your design"),
                React.createElement("p", { className: "muted" }, unavailable ? "This design is unavailable for new invitations. Choose another design to get started." : "Choose a design, then make the names, photographs and celebrations your own."),
                window.EA_UI_PREVIEW === true ? React.createElement(BuilderPreviewNotice, null) : React.createElement("p", { className: "builder-chooser-note" }, "Edit and preview before publishing. Sign in to keep a draft in your dashboard.")),
            React.createElement(TemplateCategoryTabs, { active: category, onChange: setCategory, templates: templates }),
            React.createElement("p", { className: "builder-chooser-count", role: "status" },
                visible.length,
                " ",
                visible.length === 1 ? 'design' : 'designs',
                " to make your own"),
            visible.length ? (React.createElement("div", { className: "showcase-grid" }, visible.map((template) => (React.createElement("article", { className: "showcase-card", key: template.id },
                React.createElement("div", { className: "sc-phone-stage" },
                    React.createElement(TemplateShowcasePhone, { template: template, previewMode: "builder" })),
                React.createElement("div", { className: "builder-chooser-card-copy" },
                    React.createElement("h2", { className: "sc-title" }, template.name),
                    React.createElement("p", { className: "sc-desc" }, template.tagline || template.style),
                    React.createElement("div", { className: "sc-price" },
                        React.createElement("span", { className: "sc-price-now" },
                            "\u20B9",
                            template.price.toLocaleString("en-IN")),
                        React.createElement("span", { className: "builder-chooser-price-note" }, "to publish")),
                    React.createElement("button", { className: "sc-cta-btn", type: "button", onClick: () => goTo("builder", { template, projectId: null }), "aria-label": 'Customize ' + template.name }, "Customize"),
                    React.createElement("a", { className: "builder-chooser-demo", href: demoHref(template), target: "_blank", rel: "noopener noreferrer", "aria-label": 'View ' + template.name + ' demo in a new tab' }, "View demo"))))))) : React.createElement(TemplateCategoryEmpty, { category: getTemplateCategory(category) }))));
}
function Builder({ goTo, t, template, user, openSignIn, projectId }) {
    if (!template || (!projectId && !TemplateCatalog.canCreate(template.id)))
        return React.createElement(BuilderTemplateChooser, { goTo: goTo, unavailable: Boolean(template || parseRoute(window.location.pathname).templateId) });
    if (window.WeddingKeepsakeModel?.models?.[template.id])
        return React.createElement(WeddingKeepsakeBuilder, { key: template.id + ':' + (projectId || 'new'), goTo: goTo, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    if (template.experienceType === 'apology')
        return React.createElement(ApologyBuilder, { key: template.id + ':' + (projectId || 'new'), goTo: goTo, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    const completeModel = template?.id === 'patjhad' ? window.PatjhadModel : template?.id === 'amethyst' ? window.AmethystModel : template?.id === 'neelangan' ? window.NeelanganModel : null;
    if (completeModel)
        return React.createElement(FullInvitationBuilder, { key: template.id + ':' + (projectId || 'new'), goTo: goTo, template: template, user: user, openSignIn: openSignIn, projectId: projectId, model: completeModel });
    if (template?.id === "sargam")
        return React.createElement(SargamBuilder, { goTo: goTo, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    if (template?.id === "moonlit-mehfil")
        return React.createElement(VerifiedLegacyBuilder, { editor: MoonlitMehfilBuilder, goTo: goTo, t: t, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    if (template?.id === "vivaha")
        return React.createElement(VerifiedLegacyBuilder, { editor: VivahaBuilder, goTo: goTo, t: t, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    if (template?.id === "dear-you")
        return React.createElement(VerifiedLegacyBuilder, { editor: DearYouBuilder, goTo: goTo, t: t, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    if (template?.id === "haveli-dusk")
        return React.createElement(VerifiedLegacyBuilder, { editor: HaveliDuskBuilder, goTo: goTo, t: t, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    if (template.id === "royal-pichwai")
        return React.createElement(VerifiedLegacyBuilder, { editor: RoyalPichwaiBuilder, goTo: goTo, t: t, template: template, user: user, openSignIn: openSignIn, projectId: projectId });
    return React.createElement(BuilderTemplateChooser, { goTo: goTo, unavailable: true });
}
function slugStem(value) {
    return String(value || "")
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, "-")
        .replace(/^-+|-+$/g, "");
}
function coupleSlugStem(config, fallback) {
    const couple = config?.couple || {};
    const fromNames = [couple.bride, couple.groom].filter(Boolean).join(" ");
    return slugStem(fromNames || fallback || "invitation") || "invitation";
}
function makePublicSlug(config, fallback) {
    return `${coupleSlugStem(config, fallback)}-${Date.now().toString(36)}`;
}
function shouldRefreshDefaultSlug(slug, config) {
    const current = coupleSlugStem(config);
    if (!slug)
        return true;
    if (!current || current === "invitation")
        return false;
    if (slug.startsWith(current + "-"))
        return false;
    return ["aanya-rohan", "zoya-ayaan", "diya-aarav", "aarya-rohan"].some((stem) => slug.startsWith(stem + "-"));
}
function builderProjectName(config, templateId) {
    return [config?.couple?.bride, config?.couple?.groom].filter(Boolean).join(" & ") || [config?.from, config?.to].filter(Boolean).join(" & ") || templateId || "Wedding invitation";
}
async function runSaveDraft({ templateId, config, writeConfig, projectId, setProjectId, api = window.EA }) {
    if (window.EA_UI_PREVIEW === true) {
        try {
            writeConfig(config);
            return { ok: true, local: true };
        }
        catch (err) {
            return { ok: false, reason: err.message || "Could not save on this device." };
        }
    }
    if (!api?.isLoggedIn())
        return { ok: false, reason: "login" };
    try {
        validateBuilderMedia(config);
        writeConfig(config);
        markBuilderDraftPending(templateId, projectId);
        let activeProjectId = projectId || null;
        const projectName = builderProjectName(config, templateId);
        if (activeProjectId) {
            const saved = await api.saveProject(activeProjectId, config, projectName);
            activeProjectId = saved.project?.id || activeProjectId;
        }
        else {
            const created = await api.createProject(templateId, projectName, config);
            activeProjectId = created.project?.id || null;
            if (activeProjectId) {
                await api.saveProject(activeProjectId, undefined, undefined, "draft");
            }
        }
        if (!activeProjectId)
            return { ok: false, reason: "no_project" };
        if (setProjectId)
            setProjectId(activeProjectId);
        const latestConfig = readBuilderConfig(TemplateCatalog.get(templateId)?.configKey) || config;
        syncBuilderProjectUrl(templateId, activeProjectId, api);
        writeConfig(latestConfig);
        if (JSON.stringify(latestConfig) !== JSON.stringify(config))
            markBuilderDraftPending(templateId, activeProjectId);
        markBuilderDraftSaved(templateId, activeProjectId, config);
        return { ok: true, projectId: activeProjectId };
    }
    catch (err) {
        if (!api.isAdminEditor && (err.status === 403 || err.status === 404))
            return { ok: false, reason: "project_not_found" };
        return { ok: false, reason: err.message || "save_failed" };
    }
}
async function runPublish({ templateId, config, writeConfig, projectId, setProjectId, api = window.EA }) {
    if (window.EA_UI_PREVIEW === true)
        return { ok: false, reason: "Publishing is unavailable in this UI preview." };
    if (!api?.isLoggedIn())
        return { ok: false, reason: "login" };
    try {
        validateBuilderMedia(config);
        writeConfig(config);
        markBuilderDraftPending(templateId, projectId);
        let activeProjectId = projectId || null;
        const coupleName = builderProjectName(config, templateId);
        let currentSlug = null;
        if (activeProjectId) {
            try {
                const saved = await api.saveProject(activeProjectId, config, coupleName);
                currentSlug = saved.project?.slug || null;
            }
            catch (err) {
                if (!api.isAdminEditor && (err.status === 403 || err.status === 404))
                    return { ok: false, reason: "project_not_found" };
                throw err;
            }
        }
        if (!activeProjectId) {
            const r = await api.createProject(templateId, coupleName, config);
            activeProjectId = r.project?.id;
            currentSlug = r.project?.slug || null;
        }
        if (!activeProjectId)
            return { ok: false, reason: "no_project" };
        if (setProjectId)
            setProjectId(activeProjectId);
        const latestConfig = readBuilderConfig(TemplateCatalog.get(templateId)?.configKey) || config;
        syncBuilderProjectUrl(templateId, activeProjectId, api);
        writeConfig(latestConfig);
        if (JSON.stringify(latestConfig) !== JSON.stringify(config))
            markBuilderDraftPending(templateId, activeProjectId);
        markBuilderDraftSaved(templateId, activeProjectId, config);
        if (!api.isAdminEditor) {
            if (typeof window.checkoutProject !== "function")
                throw new Error("Payment checkout is unavailable. Please refresh and try again.");
            await window.checkoutProject({ templateId, projectId: activeProjectId });
        }
        const publishSlug = currentSlug ? undefined : makePublicSlug(config, coupleName);
        const pub = api.isAdminEditor
            ? await api.publishProject(activeProjectId, { slug: publishSlug })
            : await api.saveProject(activeProjectId, undefined, undefined, "published", publishSlug);
        const slug = pub.project?.slug || publishSlug || currentSlug;
        return slug ? { ok: true, slug, projectId: activeProjectId } : { ok: false, reason: "missing_slug" };
    }
    catch (err) {
        return { ok: false, reason: err.message };
    }
}
function ShareModal({ slug, onClose }) {
    const api = typeof useBuilderApi === 'function' ? useBuilderApi() : window.EA;
    const origin = window.location.origin;
    const url = origin + builderAppPath(`/p/${encodeURIComponent(slug)}`);
    const [copied, setCopied] = React.useState(false);
    const [copyError, setCopyError] = React.useState("");
    const dialogRef = React.useRef(null);
    const closeRef = React.useRef(null);
    const qr = `https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=${encodeURIComponent(url)}&bgcolor=fffdf9&color=292329&margin=12&qzone=1`;
    React.useEffect(() => {
        const previousFocus = document.activeElement;
        const previousOverflow = document.body.style.overflow;
        document.body.style.overflow = "hidden";
        closeRef.current?.focus();
        return () => {
            document.body.style.overflow = previousOverflow;
            previousFocus?.focus?.({ preventScroll: true });
        };
    }, []);
    const onDialogKeyDown = (event) => {
        if (event.key === "Escape") {
            event.preventDefault();
            onClose();
            return;
        }
        if (event.key !== "Tab")
            return;
        const controls = Array.from(dialogRef.current?.querySelectorAll('button:not(:disabled), a[href], input:not(:disabled)') || []);
        const first = controls[0], last = controls[controls.length - 1];
        if (event.shiftKey && document.activeElement === first) {
            event.preventDefault();
            last?.focus();
        }
        else if (!event.shiftKey && document.activeElement === last) {
            event.preventDefault();
            first?.focus();
        }
    };
    const copy = async () => {
        try {
            await navigator.clipboard.writeText(url);
            setCopyError("");
            setCopied(true);
        }
        catch (_) {
            setCopied(false);
            setCopyError("Select and copy the invitation link above.");
        }
    };
    const whatsapp = () => {
        const msg = `Made for you. Open this invitation:\n${url}`;
        window.open(`https://wa.me/?text=${encodeURIComponent(msg)}`, "_blank", "noopener,noreferrer");
    };
    return (React.createElement("div", { className: "builder-share-overlay", style: { position: "fixed", inset: 0, zIndex: 9900, background: "var(--builder-overlay,rgba(20,37,29,.5))", display: "flex", alignItems: "center", justifyContent: "center", padding: 16 }, onClick: (e) => e.target === e.currentTarget && onClose() },
        React.createElement("div", { ref: dialogRef, className: "builder-share-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "builder-share-title", "aria-describedby": "builder-share-description", onKeyDown: onDialogKeyDown, style: { background: "var(--builder-white,#fff)", borderRadius: 16, padding: "56px 28px 28px", width: "100%", maxWidth: 440, position: "relative", boxShadow: "var(--builder-dialog-shadow,0 20px 60px rgba(20,37,29,.18))" } },
            React.createElement("button", { ref: closeRef, className: "builder-share-close", type: "button", "aria-label": "Close sharing dialog", onClick: onClose, style: { position: "absolute", top: 14, right: 14, background: "var(--builder-tint,#eaf1ed)", border: "none", borderRadius: 9, width: 44, height: 44, cursor: "pointer", fontSize: 14, fontFamily: "var(--builder-font,'Inter Tight',sans-serif)", color: "var(--builder-muted,#59675f)", display: "flex", alignItems: "center", justifyContent: "center" } }, "\u2715"),
            React.createElement("div", { style: { textAlign: "center", marginBottom: 28 } },
                React.createElement("h2", { id: "builder-share-title", style: { fontFamily: "var(--builder-font,'Inter Tight',sans-serif)", fontSize: 24, color: "var(--builder-ink,#243c33)", margin: 0, fontWeight: 600 } }, "Your invitation is live"),
                React.createElement("p", { id: "builder-share-description", style: { color: "var(--builder-muted,#59675f)", fontSize: 14, marginTop: 8, lineHeight: 1.6 } },
                    "Copy your link or send it on WhatsApp. ",
                    api?.isAdminEditor ? 'This invitation is saved in the customer account. You can manage it from administration.' : 'You can return to your dashboard to edit the invitation.')),
            React.createElement("div", { className: "builder-share-link", style: { display: "flex", gap: 8, marginBottom: 16 } },
                React.createElement("input", { "aria-label": "Invitation link", readOnly: true, value: url, onFocus: (event) => event.target.select(), style: { flex: 1, background: "var(--builder-surface,#f4f6f3)", border: 0, borderRadius: 9, padding: "10px 14px", fontSize: 14, fontFamily: "var(--builder-font,'Inter Tight',sans-serif)", color: "var(--builder-ink,#243c33)", minHeight: 44 } }),
                React.createElement("button", { type: "button", onClick: copy, style: { padding: "10px 16px", borderRadius: 9, border: "none", cursor: "pointer", background: copied ? "var(--builder-success,#286144)" : "var(--builder-accent,#294e45)", color: "var(--builder-white,#fff)", fontSize: 14, fontFamily: "var(--builder-font,'Inter Tight',sans-serif)", fontWeight: 600, whiteSpace: "nowrap" } }, copied ? "Copied!" : "Copy link")),
            React.createElement("p", { role: "status", style: { fontSize: 13, color: "var(--builder-muted,#59675f)", margin: copyError || copied ? "-6px 0 16px" : 0 } }, copyError || (copied ? "Invitation link copied." : "")),
            React.createElement("button", { type: "button", onClick: whatsapp, style: { width: "100%", background: "var(--builder-accent,#294e45)", color: "var(--builder-white,#fff)", border: "none", borderRadius: 9, padding: "14px", fontSize: 14, fontFamily: "var(--builder-font,'Inter Tight',sans-serif)", fontWeight: 600, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: 10, marginBottom: 24 } },
                React.createElement("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "currentColor" },
                    React.createElement("path", { d: "M20.52 3.48A11.93 11.93 0 0012 0C5.37 0 0 5.37 0 12c0 2.11.55 4.16 1.6 5.97L0 24l6.22-1.57A12.06 12.06 0 0012 24c6.63 0 12-5.37 12-12 0-3.2-1.25-6.21-3.48-8.52zM12 22a9.94 9.94 0 01-5.08-1.39l-.36-.22-3.69.93.99-3.58-.24-.38A9.93 9.93 0 012 12C2 6.48 6.48 2 12 2s10 4.48 10 10-4.48 10-10 10zm5.44-7.44c-.3-.15-1.75-.86-2.02-.96-.27-.1-.47-.15-.67.15s-.77.96-.94 1.16c-.17.2-.35.22-.65.07a8.15 8.15 0 01-2.39-1.47 8.93 8.93 0 01-1.66-2.06c-.17-.3-.02-.46.13-.61.13-.13.3-.35.45-.52.15-.17.2-.3.3-.5.1-.2.05-.37-.02-.52-.07-.15-.67-1.6-.91-2.19-.24-.57-.48-.49-.67-.5H6.7c-.2 0-.52.07-.79.37s-1.04 1.02-1.04 2.48 1.07 2.88 1.22 3.08c.15.2 2.1 3.2 5.08 4.49.71.31 1.27.49 1.7.63.72.23 1.37.2 1.88.12.57-.09 1.75-.72 2-1.41.25-.7.25-1.29.17-1.41-.08-.12-.27-.2-.57-.34z" })),
                "Share on WhatsApp"),
            React.createElement("div", { style: { textAlign: "center" } },
                React.createElement("div", { style: { display: "inline-block", padding: 8, background: "var(--builder-white,#fff)", borderRadius: 12, boxShadow: "var(--builder-qr-shadow,0 4px 16px -6px rgba(20,37,29,.18))" } },
                    React.createElement("img", { src: qr, alt: "QR code for your invitation link", width: "180", height: "180", style: { display: "block", borderRadius: 6 } })),
                React.createElement("p", { style: { fontSize: 13, color: "var(--builder-muted,#59675f)", marginTop: 8 } }, "Scan to open your invitation")),
            React.createElement("div", { style: { textAlign: "center", marginTop: 16 } },
                React.createElement("a", { className: "builder-share-dashboard", href: builderAppPath(api?.isAdminEditor ? '/admin' : '/dashboard'), style: { fontSize: 14, color: "var(--builder-ink,#243c33)", textDecoration: "underline", fontFamily: "var(--builder-font,'Inter Tight',sans-serif)" } }, api?.isAdminEditor ? 'Back to administration' : 'Manage your invitation')))));
}
function RoyalPichwaiBuilder({ goTo, t, template, user, openSignIn, projectId, verifiedProject, verifiedOwnerId, recoveredDraft }) {
    const api = useBuilderApi();
    const activeTemplate = template || TemplateCatalog.get("royal-pichwai");
    const [draft, setDraft] = React.useState(() => template09BaseDraft(t));
    const [activeProjectId, setActiveProjectId] = React.useState(projectId || null);
    const [tab, setTab] = React.useState("essentials");
    const [previewVersion, setPreviewVersion] = React.useState(1);
    const [savedAt, setSavedAt] = React.useState("");
    const [isPreviewMode, setIsPreviewMode] = React.useState(() => {
        try {
            return new URLSearchParams(window.location.search).get("preview") === "1";
        }
        catch (_) {
            return false;
        }
    });
    const [shareSlug, setShareSlug] = React.useState(null);
    const [publishing, setPublishing] = React.useState(false);
    const [publishAfterAuth, setPublishAfterAuth] = React.useState(false);
    const [savingDraft, setSavingDraft] = React.useState(false);
    const [musicUploading, setMusicUploading] = React.useState(false);
    const photoUploads = useBuilderPhotoUploads({ templateId: 'royal-pichwai', projectId: activeProjectId || projectId, user });
    const mediaUploading = musicUploading || photoUploads.busy;
    const [saveAfterAuth, setSaveAfterAuth] = React.useState(false);
    const [draftMsg, setDraftMsg] = React.useState("");
    const skipNextAutosaveRef = React.useRef(true);
    const projectLoadPendingRef = React.useRef(false);
    const previewSessionRef = React.useRef(`royal-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`);
    const { enterPreview, returnToEditor } = useBuilderPreviewNavigation(isPreviewMode, setIsPreviewMode);
    const config = React.useMemo(() => buildTemplate09Config(draft), [draft]);
    const builderTemplatePath = activeTemplate?.builderTemplatePath || TEMPLATE09_BUILDER_TEMPLATE_PATH;
    const builderTemplateUrl = resolveWeddingAssetUrl(builderTemplatePath);
    const previewSrc = buildBuilderPreviewSrc(builderTemplateUrl, "royal-pichwai", previewVersion, previewSessionRef.current);
    useBuilderPreviewPolish([previewSrc, isPreviewMode]);
    useLoadedProjectConfig({
        verifiedProject, verifiedOwnerId, recoveredDraft,
        projectId,
        templateId: "royal-pichwai",
        user,
        setActiveProjectId,
        setDraft,
        makeDraft: (source) => template09BaseDraft(t, { source }),
        writeConfig: writeTemplate09Config,
        setPreviewVersion,
        setSavedAt,
        onConfigLoaded: () => { skipNextAutosaveRef.current = true; },
        loadPendingRef: projectLoadPendingRef,
    });
    useBuilderAutosave({
        uploading: mediaUploading, photoUploads,
        user,
        config,
        activeProjectId,
        templateId: "royal-pichwai",
        writeConfig: writeTemplate09Config,
        setPreviewVersion,
        setSavedAt,
        skipNextRef: skipNextAutosaveRef,
        loadPendingRef: projectLoadPendingRef,
    });
    const update = (path, value) => setDraft((current) => setDeepDraft(current, path, value));
    const swapNames = () => {
        setDraft((current) => {
            const next = cloneDraft(current);
            const bride = next.couple.bride;
            next.couple.bride = next.couple.groom;
            next.couple.groom = bride;
            return next;
        });
    };
    const updateEvent = (index, key, value) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.events[index][key] = value;
            return next;
        });
    };
    const addEvent = () => {
        setDraft((current) => ({
            ...cloneDraft(current),
            events: [...current.events, { id: `event-${Date.now()}`, icon: "shaadi", name: "New Ceremony", date: current.couple.date, time: "6:00 PM", venue: "", desc: "", mapsLink: "" }],
        }));
    };
    const removeEvent = (index) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.events.splice(index, 1);
            return next;
        });
    };
    const updatePhoto = (index, value) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.gallery.photos[index] = value;
            return next;
        });
    };
    const updateThing = (index, key, value) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.thingsToKnow[index][key] = value;
            return next;
        });
    };
    const addThing = () => {
        setDraft((current) => ({
            ...cloneDraft(current),
            thingsToKnow: [...current.thingsToKnow, { id: `note-${Date.now()}`, label: "Guest Note", value: "" }],
        }));
    };
    const removeThing = (index) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.thingsToKnow.splice(index, 1);
            return next;
        });
    };
    const saveNow = () => {
        writeTemplate09Config(config);
        setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
        setPreviewVersion((v) => v + 1);
    };
    const persistDraft = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setSavingDraft(true);
        setDraftMsg("");
        const res = await runSaveDraft({ api, templateId: "royal-pichwai", config, writeConfig: writeTemplate09Config, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setSavingDraft(false);
        if (res.ok) {
            setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
            setPreviewVersion((v) => v + 1);
            setDraftMsg(res.local ? "Draft saved on this device for this UI preview." : (api.isAdminEditor ? "Draft saved for the customer." : "Draft saved in your dashboard."));
        }
        else if (res.reason === "login") {
            setDraftMsg("Sign in to save this draft.");
        }
        else {
            setDraftMsg("Could not save draft: " + res.reason);
        }
    }, [config, activeProjectId, mediaUploading]);
    const handleSaveDraft = () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (window.EA_UI_PREVIEW === true) {
            persistDraft();
            return;
        }
        if (!api?.isLoggedIn()) {
            setSaveAfterAuth(true);
            setDraftMsg("Sign in to save this draft.");
            openSignIn ? openSignIn("builder") : alert("Please sign in to save your draft.");
            return;
        }
        persistDraft();
    };
    const showRealtimePreview = (event) => {
        writeTemplate09Config(config);
        setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
        setPreviewVersion((v) => v + 1);
        enterPreview(event);
    };
    const resetDemo = () => {
        if (photoUploads.pending())
            return;
        if (!window.confirm("Reset this design to its sample details? Your current changes will be replaced." + (activeProjectId ? " Your saved invitation will also update." : "")))
            return;
        try {
            window.localStorage.removeItem(builderDraftKey(TEMPLATE09_CONFIG_KEY));
        }
        catch (_) { }
        setDraft(template09BaseDraft(t, { ignoreSaved: true }));
        setTab("essentials");
        setIsPreviewMode(false);
        setPreviewVersion((v) => v + 1);
    };
    const publishNow = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setPublishing(true);
        const res = await runPublish({ api, templateId: "royal-pichwai", config, writeConfig: writeTemplate09Config, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setPublishing(false);
        if (res.ok)
            setShareSlug(res.slug);
        else if (res.reason !== "login")
            alert("Could not publish: " + res.reason);
    }, [config, activeProjectId, mediaUploading]);
    React.useEffect(() => {
        if (!publishAfterAuth || !api?.isLoggedIn())
            return;
        setPublishAfterAuth(false);
        publishNow();
    }, [publishAfterAuth, user, publishNow]);
    React.useEffect(() => {
        if (!saveAfterAuth || !api?.isLoggedIn())
            return;
        setSaveAfterAuth(false);
        persistDraft();
    }, [saveAfterAuth, user, persistDraft]);
    const handlePublish = async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (!api?.isLoggedIn()) {
            setPublishAfterAuth(true);
            openSignIn ? openSignIn("builder") : alert("Please sign in to publish your invitation.");
            return;
        }
        publishNow();
    };
    return (React.createElement("div", { className: "saas-template-builder" },
        shareSlug && React.createElement(ShareModal, { slug: shareSlug, onClose: () => setShareSlug(null) }),
        React.createElement("aside", { className: "saas-builder-side" },
            React.createElement("div", { className: "saas-template-switch" },
                React.createElement("div", null,
                    React.createElement("span", null, "Template"),
                    React.createElement("strong", null, activeTemplate?.name || "Royal Pichwai")),
                React.createElement("button", { type: "button", onClick: () => goTo("builder", { projectId: null }) }, api.isAdminEditor ? 'Administration' : 'Change design')),
            React.createElement("label", { className: "builder-section-picker" },
                React.createElement("span", null, "Editing section"),
                React.createElement("select", { disabled: photoUploads.busy, value: tab, onChange: (e) => setTab(e.target.value) }, TEMPLATE09_TABS.map((item) => React.createElement("option", { key: item.id, value: item.id }, item.label)))),
            React.createElement("nav", { className: "saas-builder-tabs", "aria-label": "Builder sections" }, TEMPLATE09_TABS.map((item) => (React.createElement("button", { key: item.id, disabled: photoUploads.busy, "aria-current": tab === item.id ? "step" : undefined, className: tab === item.id ? "active" : "", onClick: () => setTab(item.id) }, item.label)))),
            React.createElement("fieldset", { className: "saas-builder-form", disabled: mediaUploading || savingDraft || publishing, style: { border: 0, margin: 0, minWidth: 0 } },
                React.createElement(TemplateSectionsPanel, { sections: window.EverafterLegacyOptions.definitions("royal-pichwai", draft), value: draft.sections, onChange: sections => setDraft(current => window.EverafterLegacyOptions.prepare({ ...current, sections }, "royal-pichwai")) }),
                tab === "essentials" && (React.createElement(BuilderPanel, { icon: "o", title: "The Couple", hint: "Live updates the opening reveal, invite names, calendar links, and closing page." },
                    React.createElement(BuildField, { label: "Bride's name", value: draft.couple.bride, onChange: (v) => update(["couple", "bride"], v) }),
                    React.createElement(BuildField, { label: "Groom's name", value: draft.couple.groom, onChange: (v) => update(["couple", "groom"], v) }),
                    React.createElement("div", { className: "builder-inline-row" },
                        React.createElement("span", null,
                            "Name display order",
                            React.createElement("br", null),
                            React.createElement("strong", null,
                                draft.couple.bride,
                                " & ",
                                draft.couple.groom)),
                        React.createElement("button", { type: "button", onClick: swapNames }, "Switch")),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Wedding date", type: "date", value: draft.couple.date, onChange: (v) => update(["couple", "date"], v) }),
                        React.createElement(BuildField, { label: "Venue", value: draft.couple.venue, onChange: (v) => update(["couple", "venue"], v) })),
                    React.createElement(BuildField, { label: "WhatsApp number", value: draft.couple.whatsapp, onChange: (v) => update(["couple", "whatsapp"], v), placeholder: "+91 98765 43210" }),
                    React.createElement(BuildField, { label: "Wedding hashtag", value: draft.couple.hashtag, onChange: (v) => update(["couple", "hashtag"], v) }))),
                tab === "invitation" && (React.createElement(BuilderPanel, { icon: "m", title: "Invitation Card", hint: "Controls the formal invitation section inside the generated website." },
                    React.createElement(BuildToggle, { label: "Show invitation section", checked: draft.invite.show, onChange: (v) => update(["invite", "show"], v) }),
                    React.createElement(BuildField, { label: "Opening blessing", value: draft.invite.blessing, onChange: (v) => update(["invite", "blessing"], v), multi: true, rows: 3 }),
                    React.createElement(BuildField, { label: "Bride's father", value: draft.invite.brideFather, onChange: (v) => update(["invite", "brideFather"], v) }),
                    React.createElement(BuildField, { label: "Bride's mother", value: draft.invite.brideMother, onChange: (v) => update(["invite", "brideMother"], v) }),
                    React.createElement(BuildField, { label: "Groom's father", value: draft.invite.groomFather, onChange: (v) => update(["invite", "groomFather"], v) }),
                    React.createElement(BuildField, { label: "Groom's mother", value: draft.invite.groomMother, onChange: (v) => update(["invite", "groomMother"], v) }),
                    React.createElement(BuildSelect, { label: "Parents display order", value: draft.invite.parentsOrder, onChange: (v) => update(["invite", "parentsOrder"], v), options: [["bride_first", "Bride's family first"], ["groom_first", "Groom's family first"]] }),
                    React.createElement(BuildToggle, { label: "Show grandparents blessing", checked: draft.invite.showGrandparents, onChange: (v) => update(["invite", "showGrandparents"], v) }),
                    draft.invite.showGrandparents && (React.createElement(React.Fragment, null,
                        React.createElement(BuildField, { label: "Bride grandfather", value: draft.invite.brideGF, onChange: (v) => update(["invite", "brideGF"], v) }),
                        React.createElement(BuildField, { label: "Bride grandmother", value: draft.invite.brideGM, onChange: (v) => update(["invite", "brideGM"], v) }),
                        React.createElement(BuildField, { label: "Groom grandfather", value: draft.invite.groomGF, onChange: (v) => update(["invite", "groomGF"], v) }),
                        React.createElement(BuildField, { label: "Groom grandmother", value: draft.invite.groomGM, onChange: (v) => update(["invite", "groomGM"], v) }))))),
                tab === "events" && (React.createElement(BuilderPanel, { icon: "e", title: "Events", hint: "Add every ceremony. Empty events are ignored in the generated invite." },
                    draft.events.map((event, index) => (React.createElement("div", { className: "builder-repeat", key: event.id || index },
                        React.createElement("div", { className: "builder-repeat-head" },
                            React.createElement("strong", null, event.name || `Event ${index + 1}`),
                            React.createElement("button", { onClick: () => removeEvent(index), "aria-label": "Remove event" }, "Remove")),
                        React.createElement(EventIconPicker, { value: event.icon, onChange: (v) => updateEvent(index, "icon", v) }),
                        React.createElement(BuildField, { label: "Event name", value: event.name, onChange: (v) => updateEvent(index, "name", v) }),
                        React.createElement("div", { className: "builder-two-col" },
                            React.createElement(BuildField, { label: "Date", type: "date", value: event.date, onChange: (v) => updateEvent(index, "date", v) }),
                            React.createElement(BuildField, { label: "Time", value: event.time, onChange: (v) => updateEvent(index, "time", v) })),
                        React.createElement(BuildField, { label: "Venue", value: event.venue, onChange: (v) => updateEvent(index, "venue", v) }),
                        React.createElement(BuildField, { label: "Description", value: event.desc, onChange: (v) => updateEvent(index, "desc", v), multi: true }),
                        React.createElement(BuildField, { label: "Map link", value: event.mapsLink, onChange: (v) => updateEvent(index, "mapsLink", v), placeholder: "https://maps.google.com/..." })))),
                    React.createElement("button", { className: "builder-add-btn", onClick: addEvent }, "Add ceremony"))),
                tab === "story" && (React.createElement(BuilderPanel, { icon: "s", title: "Story", hint: "This controls the Meet The Couple garden section." },
                    React.createElement(BuildToggle, { label: "Show story section", checked: draft.story.show, onChange: (v) => update(["story", "show"], v) }),
                    React.createElement(BuildSelect, { label: "Story style", value: draft.story.storyMode, onChange: (v) => update(["story", "storyMode"], v), options: [["story", "Written paragraph"], ["tags", "Memory chips"]] }),
                    draft.story.storyMode === "story" ? (React.createElement(BuildField, { label: "Couple story", value: draft.story.storyText, onChange: (v) => update(["story", "storyText"], v), multi: true, rows: 7 })) : (React.createElement(BuildField, { label: "Tags, comma separated", value: draft.story.tags.join(", "), onChange: (v) => update(["story", "tags"], v.split(",").map((x) => x.trim()).filter(Boolean)) })))),
                tab === "gallery" && (React.createElement(BuilderPanel, { icon: "g", title: "Gallery", hint: "Upload photos from your device or paste a URL. Empty slots are skipped." },
                    React.createElement(BuildToggle, { label: "Show gallery", checked: draft.gallery.show, onChange: (v) => update(["gallery", "show"], v) }),
                    React.createElement(LegacyPhotoList, { photos: draft.gallery.photos, uploadScope: photoUploads, onChange: photos => setDraft(current => ({ ...current, gallery: { ...current.gallery, photos, layout: "auto" } })) }))),
                tab === "info" && (React.createElement(BuilderPanel, { icon: "i", title: "Guest Info", hint: "These become the Things To Know cards." },
                    draft.thingsToKnow.map((item, index) => (React.createElement("div", { className: "builder-repeat", key: item.id || index },
                        React.createElement("div", { className: "builder-repeat-head" },
                            React.createElement("strong", null, item.label || `Note ${index + 1}`),
                            React.createElement("button", { onClick: () => removeThing(index) }, "Remove")),
                        React.createElement(BuildField, { label: "Card label", value: item.label, onChange: (v) => updateThing(index, "label", v) }),
                        React.createElement(BuildField, { label: "Card text", value: item.value, onChange: (v) => updateThing(index, "value", v), multi: true })))),
                    React.createElement("button", { className: "builder-add-btn", onClick: addThing }, "Add guest note"))),
                tab === "rsvp" && (React.createElement(BuilderPanel, { icon: "r", title: "RSVP", hint: "Controls the response section and calendar links." },
                    React.createElement(BuildToggle, { label: "Show RSVP section", checked: draft.rsvp.show, onChange: (v) => update(["rsvp", "show"], v) }),
                    React.createElement(BuildSelect, { label: "RSVP mode", value: draft.rsvp.mode, onChange: (v) => update(["rsvp", "mode"], v), options: [["native", "Built-in guest RSVP"], ["whatsapp", "WhatsApp"], ["form", "External form"]] }),
                    React.createElement(BuildField, { label: "Heading", value: draft.rsvp.heading, onChange: (v) => update(["rsvp", "heading"], v) }),
                    React.createElement(BuildField, { label: "Subtext", value: draft.rsvp.subtext, onChange: (v) => update(["rsvp", "subtext"], v), multi: true, rows: 4 }),
                    React.createElement(BuildField, { label: "Button text", value: draft.rsvp.btnText, onChange: (v) => update(["rsvp", "btnText"], v) }),
                    draft.rsvp.mode === "form" ? (React.createElement(BuildField, { label: "Form URL", value: draft.rsvp.form_url, onChange: (v) => update(["rsvp", "form_url"], v) })) : draft.rsvp.mode === "whatsapp" ? (React.createElement(BuildField, { label: "WhatsApp number", value: draft.rsvp.whatsapp || draft.couple.whatsapp, onChange: (v) => update(["rsvp", "whatsapp"], v) })) : null,
                    React.createElement(BuildToggle, { label: "Show closing blessing", checked: draft.closing.show, onChange: (v) => update(["closing", "show"], v) }),
                    React.createElement(BuildField, { label: "Closing line", value: draft.closing.line, onChange: (v) => update(["closing", "line"], v) }))),
                React.createElement("div", { hidden: tab !== "music" },
                    React.createElement(BuilderPanel, { icon: "a", title: "Music" },
                        React.createElement(MusicUploadPanel, { value: draft.music, nativeMusic: template09BaseDraft({}, { ignoreSaved: true }).music, templateId: "royal-pichwai", projectId: activeProjectId || projectId, scopeKey: projectId || 'new', user: user, disabled: savingDraft || publishing || photoUploads.busy, onChange: value => update(["music"], value), onBusyChange: setMusicUploading, openSignIn: openSignIn, active: tab === "music" })))),
            React.createElement(BuilderProgressActions, { tabs: TEMPLATE09_TABS, tab: tab, onTabChange: setTab, onPreview: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading })),
        React.createElement("main", { className: "saas-builder-preview" },
            React.createElement("div", { className: "saas-builder-topbar" },
                React.createElement("div", { className: "builder-save-status" },
                    React.createElement("span", { className: "builder-status-dot" }),
                    React.createElement("span", null,
                        React.createElement("strong", null, activeProjectId ? "Your invitation" : "New design"),
                        React.createElement("small", { role: "status" }, draftMsg || builderSaveStatus(savedAt)))),
                window.EA_UI_PREVIEW === true && React.createElement(BuilderPreviewNotice, { compact: true }),
                React.createElement("div", { className: "saas-builder-actions" },
                    React.createElement("button", { type: "button", className: "mobile-edit-action", onClick: scrollBuilderEditorIntoView },
                        React.createElement(BuilderActionLabel, { full: "Edit details", compact: "Edit" })),
                    React.createElement("button", { type: "button", className: "desktop-reset-action", onClick: resetDemo, disabled: savingDraft || publishing || mediaUploading }, "Reset"),
                    React.createElement("button", { type: "button", onClick: handleSaveDraft, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: savingDraft ? "Saving..." : "Save draft", compact: savingDraft ? "Saving" : "Save" })),
                    React.createElement("button", { type: "button", className: "primary", onClick: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: "Preview so far", compact: "Preview so far" })),
                    React.createElement("button", { type: "button", className: "publish", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined },
                        React.createElement(BuilderActionLabel, { full: publishing ? "Publishing..." : "Publish invitation", compact: publishing ? "Publishing" : "Publish" })))),
            React.createElement("div", { className: "saas-preview-label" }, "Live preview"),
            React.createElement("div", { className: "saas-preview-workspace" }, !isPreviewMode && React.createElement(BuilderPhonePreview, { activeTemplate: activeTemplate, fallbackName: "Royal Pichwai", previewSrc: previewSrc })),
            React.createElement("div", { className: "saas-publish-bar" },
                React.createElement("div", { className: "saas-publish-template" },
                    React.createElement("span", { className: "saas-publish-thumb" }),
                    React.createElement("div", null,
                        React.createElement("strong", null, activeTemplate?.name || "Royal Pichwai"),
                        React.createElement("span", null, "Personal dashboard \u00B7 Mobile optimised \u00B7 WhatsApp sharing"))),
                React.createElement("button", { type: "button", className: "saas-publish-btn", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined }, publishing ? "Publishing…" : "Publish invitation"))),
        React.createElement(BuilderPreviewWindow, { open: isPreviewMode, onClose: returnToEditor, activeTemplate: activeTemplate, fallbackName: "Royal Pichwai", previewSrc: previewSrc })));
}
function BuilderPanel({ icon, title, hint, children }) {
    return (React.createElement("section", { className: "builder-panel" },
        React.createElement("div", { className: "builder-panel-title" },
            React.createElement("h3", { tabIndex: -1 }, title)),
        hint && React.createElement("p", null, hint),
        React.createElement("div", { className: "builder-fields" }, children)));
}
function BuildField({ label, value, onChange, multi, type = "text", placeholder = "", rows = 3 }) {
    return (React.createElement("label", { className: "builder-field" },
        React.createElement("span", null, label),
        multi ? (React.createElement("textarea", { value: value ?? "", rows: rows, placeholder: placeholder, onChange: (e) => onChange(e.target.value) })) : (React.createElement("input", { type: type, value: value ?? "", placeholder: placeholder, onChange: (e) => onChange(e.target.value) }))));
}
function BuildSelect({ label, value, onChange, options }) {
    return (React.createElement("label", { className: "builder-field" },
        React.createElement("span", null, label),
        React.createElement("select", { value: value || "", onChange: (e) => onChange(e.target.value) }, options.map(([optionValue, optionLabel]) => (React.createElement("option", { key: optionValue, value: optionValue }, optionLabel))))));
}
function EventIconPicker({ value, onChange }) {
    return (React.createElement("div", { className: "builder-field" },
        React.createElement("span", null, "Icon"),
        React.createElement("div", { className: "builder-icon-picker", role: "group", "aria-label": "Ceremony icon" }, TEMPLATE09_EVENT_ICON_OPTIONS.map((option) => (React.createElement("button", { key: option.value, type: "button", className: "builder-icon-option " + (value === option.value ? "active" : ""), "aria-pressed": value === option.value, onClick: () => onChange(option.value) },
            React.createElement("img", { src: option.src, alt: "" }),
            React.createElement("span", null, option.label)))))));
}
function BuildToggle({ label, checked, onChange }) {
    return (React.createElement("label", { className: "builder-field builder-visibility-select" },
        React.createElement("span", null, label),
        React.createElement("select", { value: checked ? "show" : "hide", onChange: (event) => onChange(event.target.value === "show") },
            React.createElement("option", { value: "show" }, "Show"),
            React.createElement("option", { value: "hide" }, "Hide"))));
}
function BuilderPhotoDisclosure({ label, value, caption, children, populated = Boolean(value), emptyLabel = "Add a photograph" }) {
    const [open, setOpen] = React.useState(() => !populated);
    return (React.createElement("details", { className: "builder-photo-disclosure", open: open, onToggle: (event) => {
            if (event.target === event.currentTarget)
                setOpen(event.currentTarget.open);
        } },
        React.createElement("summary", null,
            React.createElement("span", { className: "builder-photo-summary-thumb", "aria-hidden": "true" }, value ? React.createElement("img", { key: value, src: value, alt: "", loading: "lazy", onError: (event) => { event.currentTarget.style.visibility = "hidden"; } }) : React.createElement("span", null, "+")),
            React.createElement("span", { className: "builder-photo-summary-text" },
                React.createElement("strong", null, label),
                React.createElement("span", { className: "builder-photo-summary-meta" }, caption || (value ? "Photo selected" : populated ? "Text added; photo optional" : emptyLabel)))),
        React.createElement("div", { className: "builder-photo-disclosure-body" }, children)));
}
async function uploadBuilderImage(file, capturedProjectId, api = window.EA) {
    if (window.EA_UI_PREVIEW === true)
        throw new Error('Photo uploads are unavailable in this UI preview.');
    if (!api?.isLoggedIn()) {
        window.everafterOpenSignIn?.('builder');
        throw new Error('Sign in, then select your photograph again to upload it securely.');
    }
    if (!api.uploadImage)
        throw new Error('Image uploads are unavailable. Please try again later.');
    const projectId = arguments.length > 1 ? capturedProjectId : new URLSearchParams(window.location.search || '').get('project') || undefined;
    const result = await api.uploadImage(file, projectId), url = result?.url || result?.upload?.url;
    if (typeof url !== 'string' || !/^https:\/\//i.test(url))
        throw new Error('The image service did not return a secure photo URL.');
    return url;
}
function BuildPhotoField({ label, value, onChange, uploadScope, slotKey, placeholder = "", previewSize = 56 }) {
    const api = useBuilderApi();
    const fileRef = React.useRef(null);
    const inputId = React.useId();
    const [busy, setBusy] = React.useState(false);
    const [err, setErr] = React.useState("");
    const request = React.useRef(null);
    const latest = React.useRef(null);
    const mounted = React.useRef(true);
    const identity = JSON.stringify([slotKey || inputId, label, value || '']);
    latest.current = { identity, onChange, uploadScope };
    React.useEffect(() => {
        mounted.current = true;
        setBusy(false);
        setErr('');
        return () => {
            mounted.current = false;
            const pending = request.current;
            if (pending)
                pending.scope?.finish(pending.ticket);
            request.current = null;
        };
    }, [uploadScope]);
    const hasImage = Boolean(value);
    const isData = typeof value === "string" && value.startsWith("data:");
    const onPick = async (event) => {
        const file = event.target.files && event.target.files[0];
        event.target.value = "";
        if (!file || request.current || uploadScope?.pending())
            return;
        if (!["image/jpeg", "image/png", "image/webp"].includes(file.type)) {
            setErr("Please choose a JPEG, PNG or WebP photograph.");
            return;
        }
        const ticket = uploadScope?.begin(inputId);
        if (uploadScope && !ticket)
            return;
        const pending = { ticket, scope: uploadScope, identity };
        request.current = pending;
        const current = () => mounted.current && request.current === pending && latest.current.identity === pending.identity && latest.current.uploadScope === pending.scope && (!pending.scope || pending.scope.isCurrent(ticket));
        setBusy(true);
        setErr("");
        try {
            const url = await uploadBuilderImage(file, uploadScope?.projectId, api);
            if (current())
                latest.current.onChange(url);
        }
        catch (e) {
            if (current())
                setErr(e?.message || "Upload failed.");
        }
        finally {
            pending.scope?.finish(ticket);
            if (request.current === pending) {
                request.current = null;
                if (mounted.current)
                    setBusy(false);
            }
        }
    };
    return (React.createElement("div", { className: "builder-field builder-photo-field" },
        React.createElement("span", null, label),
        React.createElement("div", { style: { display: "flex", gap: 8, alignItems: "center" } },
            React.createElement("div", { "aria-hidden": "true", style: {
                    width: previewSize, height: previewSize, borderRadius: 8, flex: "0 0 auto",
                    background: hasImage ? `#efe6d8 center/cover no-repeat url("${value}")` : "#fffaf1",
                    border: "1px solid rgba(44,33,24,0.16)",
                    display: "flex", alignItems: "center", justifyContent: "center",
                    color: "rgba(44,33,24,0.45)", fontSize: 18,
                } }, hasImage ? null : "+"),
            React.createElement("div", { className: "builder-photo-controls", style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 6 } },
                React.createElement("div", { style: { display: "flex", gap: 6, flexWrap: "wrap" } },
                    React.createElement("button", { type: "button", onClick: () => fileRef.current?.click(), disabled: busy || window.EA_UI_PREVIEW === true, "aria-label": (hasImage ? 'Replace ' : 'Upload ') + label.toLowerCase(), title: window.EA_UI_PREVIEW === true ? 'Photo uploads are unavailable in this UI preview.' : undefined }, busy ? "Uploading…" : (hasImage ? "Replace" : "Upload from device")),
                    hasImage && (React.createElement("button", { type: "button", onClick: () => { setErr(""); onChange(""); }, disabled: busy, "aria-label": 'Clear ' + label.toLowerCase() }, "Clear photo"))),
                React.createElement("input", { ref: fileRef, type: "file", "aria-label": label + " upload", accept: "image/jpeg,image/png,image/webp", disabled: busy || window.EA_UI_PREVIEW === true, style: { display: "none" }, onChange: onPick }),
                window.EA_UI_PREVIEW === true && React.createElement("span", { className: "builder-ui-preview-upload-note" }, "Uploads are unavailable in this UI preview. You can try a photo URL."),
                err && React.createElement("span", { id: inputId + '-error', role: "alert", style: { color: "#8f2746", fontSize: 13 } }, err))),
        React.createElement("details", { className: "builder-photo-link" },
            React.createElement("summary", null, "Use an image link"),
            React.createElement("label", { htmlFor: inputId },
                label,
                " image link"),
            React.createElement("input", { id: inputId, type: "text", value: isData ? "" : (value || ""), placeholder: "https://...", inputMode: "url", autoCapitalize: "none", autoCorrect: "off", spellCheck: false, "aria-invalid": Boolean(err), "aria-describedby": err ? inputId + '-error' : undefined, onChange: (e) => onChange(e.target.value), disabled: isData || busy }))));
}
const MOONLIT_CONFIG_KEY = "everafter-moonlit-mehfil-config";
const MOONLIT_BUILDER_TEMPLATE_PATH = TemplateCatalog.get("moonlit-mehfil").builderTemplatePath;
const MOONLIT_DEFAULT_STORY = [
    { kicker: "How we met", title: "An evening, a lake,\nand a stranger who stayed", copy: "It was supposed to be a quick dinner with mutual friends. Two hours in, {groom} stopped pretending to look at his phone, and {bride} stopped pretending she didn't notice.", mood: "Udaipur · First evening · 2023", image: "assets/cinema/noor-palace-lake.jpg" },
    { kicker: "Falling slowly", title: "A hundred dinners,\none thousand voice notes", copy: "Long walks after long days. Lanterns on the roof, playlists made at 2 a.m., jokes only the two of them understood. Somewhere along the way, every story started with 'we'.", mood: "Together · The early days", image: "assets/cinema/noor-white-aisle.jpg" },
    { kicker: "The yes", title: "Marigolds, a ring,\nand a very long pause", copy: "On the morning of her birthday, in a garden full of yellow flowers, {groom} finally asked the question he'd been carrying for months. {bride} cried first, then laughed, then said yes — twice.", mood: "Spring · The proposal · 2025", image: "assets/cinema/noor-mehendi-marigold.jpg" },
    { kicker: "And now", title: "Two families,\none beautiful night", copy: "Eighteenth of December, under a sky full of lanterns. Everyone we love, in one place, watching us say the only word that matters. This is the story we've been writing all along.", mood: "December 2026 · {venueShort}", image: "assets/cinema/noor-couple-portrait.jpg" },
];
const MOONLIT_DEFAULT_EVENTS = [
    { id: "mehendi", name: "Mehfil-e-Mehendi", date: "2026-12-16", time: "5:30 PM", venue: "Saffron Terrace", desc: "Henna, marigolds, close family, and the first music of the celebration.", image: "assets/cinema/noor-mehendi-marigold.jpg", icon: "❋", mapsLink: "" },
    { id: "sangeet", name: "Shaam-e-Sangeet", date: "2026-12-17", time: "7:30 PM", venue: "Mirror Hall", desc: "A floral stage, candlelight, choreography, and late-night desserts.", image: "assets/cinema/noor-floral-stage.jpg", icon: "♪", mapsLink: "" },
    { id: "nikah", name: "Nikah & Vows", date: "2026-12-18", time: "11:30 AM", venue: "Moon Courtyard", desc: "A serene ceremony framed with white florals and warm aisle light.", image: "assets/cinema/noor-white-aisle.jpg", icon: "☾", mapsLink: "" },
    { id: "daawat", name: "Daawat", date: "2026-12-18", time: "8:00 PM", venue: "Garden Lawns", desc: "Dinner, speeches, and one more dance with the palace glowing behind you.", image: "assets/cinema/noor-palace-lake.jpg", icon: "✦", mapsLink: "" },
];
const MOONLIT_DEFAULT_PHOTOS = [
    "assets/cinema/noor-palace-lake.jpg",
    "assets/cinema/noor-couple-portrait.jpg",
    "assets/cinema/noor-floral-stage.jpg",
    "assets/cinema/noor-mehendi-marigold.jpg",
    "assets/cinema/noor-mehendi-rings.jpg",
    "assets/cinema/noor-candle-detail.jpg",
    "assets/cinema/noor-white-aisle.jpg",
    "assets/cinema/palace-facade-night.jpg",
];
const MOONLIT_DEFAULT_COUPLE = {
    show: true,
    lede: "Our love, told in lanterns and small rituals — quiet mehendi mornings, candlelit aisles, and one long moonlit night that ends in vows.",
    moments: [
        { num: "I", title: "Mehendi", when: "Hands sealed in henna", date: "16 Dec", image: "assets/cinema/noor-mehendi-marigold.jpg" },
        { num: "II", title: "Sangeet", when: "Music, marigolds, midnight", date: "17 Dec", image: "assets/cinema/noor-floral-stage.jpg" },
        { num: "III", title: "Nikah", when: "Vows by candlelight", date: "18 Dec", image: "assets/cinema/noor-white-aisle.jpg" },
        { num: "IV", title: "Together", when: "A night you will remember", date: "18 Dec", image: "assets/cinema/noor-couple-portrait.jpg" },
    ],
    quote: "Of all the eyes that I have known, your eyes are the night I want to keep.",
    cite: "Zoya, to Ayaan",
};
const MOONLIT_TABS = [
    { id: "sections", label: "Sections" },
    { id: "essentials", label: "Essentials" },
    { id: "story", label: "Our Story" },
    { id: "events", label: "Celebrations" },
    { id: "couple", label: "Us, Together" },
    { id: "gallery", label: "Photos" },
    { id: "rsvp", label: "RSVP" },
    { id: "music", label: "Music" },
];
function readMoonlitConfig() { return readBuilderConfig(MOONLIT_CONFIG_KEY); }
function writeMoonlitConfig(config) { writeBuilderConfig(MOONLIT_CONFIG_KEY, config); }
function moonlitAutoHashtag(bride, groom) {
    const strip = (s) => (s || "").replace(/[^A-Za-z0-9]+/g, "");
    return "#" + strip(bride) + strip(groom);
}
function moonlitBaseDraft(seed = {}, options = {}) {
    const stored = options.ignoreSaved ? null : readMoonlitConfig();
    const saved = options.source || (isLegacyGlobalSeedDraft(stored, "moonlit-mehfil") ? null : stored);
    const source = saved || {};
    const couple = source.couple || {};
    const rsvp = source.rsvp || {};
    const coupleSection = source.coupleSection || {};
    const music = source.music || {};
    const visibility = source.visibility || {};
    const bride = couple.bride ?? "Zoya";
    const groom = couple.groom ?? "Ayaan";
    const auto = moonlitAutoHashtag(bride, groom);
    const rawHashtag = (couple.hashtag || "").trim();
    const isAutoHashtag = !rawHashtag || rawHashtag === auto || rawHashtag === "#ZoyaAyaanNoor";
    return builderNewDraftMusic({
        ...cloneDraft(source),
        couple: {
            bride,
            groom,
            date: couple.date ?? "2026-12-18",
            venue: couple.venue ?? "Noor Mahal Courtyard, Udaipur",
            hashtag: isAutoHashtag ? auto : rawHashtag,
            hashtagCustom: !isAutoHashtag,
            tagline: couple.tagline ?? "An evening sealed in moonlight",
            whatsapp: couple.whatsapp ?? "",
        },
        story: Array.isArray(source.story) ? source.story : MOONLIT_DEFAULT_STORY,
        events: Array.isArray(source.events) ? source.events : MOONLIT_DEFAULT_EVENTS,
        coupleSection: {
            show: coupleSection.show !== false,
            lede: coupleSection.lede ?? MOONLIT_DEFAULT_COUPLE.lede,
            moments: Array.isArray(coupleSection.moments) ? coupleSection.moments : MOONLIT_DEFAULT_COUPLE.moments,
            quote: coupleSection.quote ?? MOONLIT_DEFAULT_COUPLE.quote,
            cite: coupleSection.cite ?? MOONLIT_DEFAULT_COUPLE.cite,
        },
        gallery: { photos: Array.isArray(source.gallery?.photos) ? source.gallery.photos : MOONLIT_DEFAULT_PHOTOS },
        rsvp: {
            heading: rsvp.heading ?? "Will you join the mehfil?",
            subtext: rsvp.subtext ?? "We have saved you a place near the lights, beside the music, and right in the middle of our story.",
            btnText: rsvp.btnText ?? "RSVP on WhatsApp",
            whatsapp: rsvp.whatsapp ?? couple.whatsapp ?? "",
        },
        music: builderMusicConfig(music, { enabled: true, mode: "ambient", src: "", autoplay: false, label: "Ambient mehfil" }),
        visibility: {
            story: visibility.story !== false,
            events: visibility.events !== false,
            couple: visibility.couple !== false && coupleSection.show !== false,
            gallery: visibility.gallery !== false,
            rsvp: visibility.rsvp !== false,
        },
    }, saved);
}
function buildMoonlitConfig(draft) {
    const config = cloneDraft(draft);
    config.story = (config.story || []).filter((s) => s.kicker || s.title || s.copy);
    config.events = (config.events || []).filter((e) => e.name || e.date || e.time || e.venue);
    if (config.coupleSection && Array.isArray(config.coupleSection.moments)) {
        config.coupleSection.moments = config.coupleSection.moments.filter((m) => m.title || m.image);
    }
    config.gallery.photos = (config.gallery.photos || []).filter(Boolean);
    config.calendarUrls = buildCalendarUrls(config.couple);
    return config;
}
function MoonlitMehfilBuilder({ goTo, t, template, user, openSignIn, projectId, verifiedProject, verifiedOwnerId, recoveredDraft }) {
    const api = useBuilderApi();
    const activeTemplate = template || TemplateCatalog.get("moonlit-mehfil");
    const [draft, setDraft] = React.useState(() => moonlitBaseDraft(t));
    const [activeProjectId, setActiveProjectId] = React.useState(projectId || null);
    const [tab, setTab] = React.useState("essentials");
    const [previewVersion, setPreviewVersion] = React.useState(1);
    const [savedAt, setSavedAt] = React.useState("");
    const [isPreviewMode, setIsPreviewMode] = React.useState(() => {
        try {
            return new URLSearchParams(window.location.search).get("preview") === "1";
        }
        catch (_) {
            return false;
        }
    });
    const [shareSlug, setShareSlug] = React.useState(null);
    const [publishing, setPublishing] = React.useState(false);
    const [publishAfterAuth, setPublishAfterAuth] = React.useState(false);
    const [savingDraft, setSavingDraft] = React.useState(false);
    const [musicUploading, setMusicUploading] = React.useState(false);
    const photoUploads = useBuilderPhotoUploads({ templateId: 'moonlit-mehfil', projectId: activeProjectId || projectId, user });
    const mediaUploading = musicUploading || photoUploads.busy;
    const [saveAfterAuth, setSaveAfterAuth] = React.useState(false);
    const [draftMsg, setDraftMsg] = React.useState("");
    const skipNextAutosaveRef = React.useRef(true);
    const projectLoadPendingRef = React.useRef(false);
    const previewSessionRef = React.useRef(`moonlit-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`);
    const { enterPreview, returnToEditor } = useBuilderPreviewNavigation(isPreviewMode, setIsPreviewMode);
    const config = React.useMemo(() => buildMoonlitConfig(draft), [draft]);
    const builderTemplatePath = activeTemplate?.builderTemplatePath || MOONLIT_BUILDER_TEMPLATE_PATH;
    const builderTemplateUrl = resolveWeddingAssetUrl(builderTemplatePath);
    const previewSrc = buildBuilderPreviewSrc(builderTemplateUrl, "moonlit-mehfil", previewVersion, previewSessionRef.current);
    useBuilderPreviewPolish([previewSrc, isPreviewMode]);
    useLoadedProjectConfig({
        verifiedProject, verifiedOwnerId, recoveredDraft,
        projectId,
        templateId: "moonlit-mehfil",
        user,
        setActiveProjectId,
        setDraft,
        makeDraft: (source) => moonlitBaseDraft(t, { source }),
        writeConfig: writeMoonlitConfig,
        setPreviewVersion,
        setSavedAt,
        onConfigLoaded: () => { skipNextAutosaveRef.current = true; },
        loadPendingRef: projectLoadPendingRef,
    });
    useBuilderAutosave({
        uploading: mediaUploading, photoUploads,
        user,
        config,
        activeProjectId,
        templateId: "moonlit-mehfil",
        writeConfig: writeMoonlitConfig,
        setPreviewVersion,
        setSavedAt,
        skipNextRef: skipNextAutosaveRef,
        loadPendingRef: projectLoadPendingRef,
    });
    const update = (path, value) => setDraft((current) => setDeepDraft(current, path, value));
    const updateCoupleName = (key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.couple[key] = value;
        if (!next.couple.hashtagCustom) {
            next.couple.hashtag = moonlitAutoHashtag(next.couple.bride, next.couple.groom);
        }
        return next;
    });
    const updateHashtag = (value) => setDraft((current) => {
        const next = cloneDraft(current);
        const trimmed = (value || "").trim();
        const auto = moonlitAutoHashtag(next.couple.bride, next.couple.groom);
        next.couple.hashtag = trimmed || auto;
        next.couple.hashtagCustom = !!trimmed && trimmed !== auto;
        return next;
    });
    const swapNames = () => setDraft((current) => {
        const next = cloneDraft(current);
        [next.couple.bride, next.couple.groom] = [next.couple.groom, next.couple.bride];
        if (!next.couple.hashtagCustom) {
            next.couple.hashtag = moonlitAutoHashtag(next.couple.bride, next.couple.groom);
        }
        return next;
    });
    const updateStory = (index, key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.story[index][key] = value;
        return next;
    });
    const updateMoment = (index, key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.coupleSection.moments[index][key] = value;
        return next;
    });
    const addMoment = () => setDraft((current) => {
        if ((current.coupleSection.moments || []).length >= 20)
            return current;
        const next = cloneDraft(current);
        const romanFor = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII"];
        next.coupleSection.moments.push({
            num: romanFor[next.coupleSection.moments.length] || "·",
            title: "New chapter",
            when: "",
            date: "",
            image: ""
        });
        return next;
    });
    const removeMoment = (index) => setDraft((current) => {
        if ((current.coupleSection.moments || []).length === 0)
            return current;
        const next = cloneDraft(current);
        next.coupleSection.moments.splice(index, 1);
        return next;
    });
    const updateEvent = (index, key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.events[index][key] = value;
        return next;
    });
    const addEvent = () => setDraft((current) => ({
        ...cloneDraft(current),
        events: [...current.events, { id: `event-${Date.now()}`, name: "New ceremony", date: current.couple.date, time: "6:00 PM", venue: "", desc: "", image: "", icon: "✦", mapsLink: "" }],
    }));
    const removeEvent = (index) => setDraft((current) => {
        const next = cloneDraft(current);
        next.events.splice(index, 1);
        return next;
    });
    const updatePhoto = (index, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.gallery.photos[index] = value;
        return next;
    });
    const addPhoto = () => setDraft((current) => {
        if ((current.gallery.photos || []).length >= 20)
            return current;
        const next = cloneDraft(current);
        next.gallery.photos.push("");
        return next;
    });
    const removePhoto = (index) => setDraft((current) => {
        if (!(current.gallery.photos || []).length)
            return current;
        const next = cloneDraft(current);
        next.gallery.photos.splice(index, 1);
        return next;
    });
    const saveNow = () => {
        writeMoonlitConfig(config);
        setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
        setPreviewVersion((v) => v + 1);
    };
    const persistDraft = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setSavingDraft(true);
        setDraftMsg("");
        const res = await runSaveDraft({ api, templateId: "moonlit-mehfil", config, writeConfig: writeMoonlitConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setSavingDraft(false);
        if (res.ok) {
            setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
            setPreviewVersion((v) => v + 1);
            setDraftMsg(res.local ? "Draft saved on this device for this UI preview." : (api.isAdminEditor ? "Draft saved for the customer." : "Draft saved in your dashboard."));
        }
        else if (res.reason === "login") {
            setDraftMsg("Sign in to save this draft.");
        }
        else {
            setDraftMsg("Could not save draft: " + res.reason);
        }
    }, [config, activeProjectId, mediaUploading]);
    const handleSaveDraft = () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (window.EA_UI_PREVIEW === true) {
            persistDraft();
            return;
        }
        if (!api?.isLoggedIn()) {
            setSaveAfterAuth(true);
            setDraftMsg("Sign in to save this draft.");
            openSignIn ? openSignIn("builder") : alert("Please sign in to save your draft.");
            return;
        }
        persistDraft();
    };
    const showRealtimePreview = (event) => { saveNow(); enterPreview(event); };
    const resetDemo = () => {
        if (photoUploads.pending())
            return;
        if (!window.confirm("Reset this design to its sample details? Your current changes will be replaced." + (activeProjectId ? " Your saved invitation will also update." : "")))
            return;
        try {
            window.localStorage.removeItem(builderDraftKey(MOONLIT_CONFIG_KEY));
        }
        catch (_) { }
        setDraft(moonlitBaseDraft(t, { ignoreSaved: true }));
        setTab("essentials");
        setIsPreviewMode(false);
        setPreviewVersion((v) => v + 1);
    };
    const publishNow = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setPublishing(true);
        const res = await runPublish({ api, templateId: "moonlit-mehfil", config, writeConfig: writeMoonlitConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setPublishing(false);
        if (res.ok)
            setShareSlug(res.slug);
        else if (res.reason !== "login")
            alert("Could not publish: " + res.reason);
    }, [config, activeProjectId, mediaUploading]);
    React.useEffect(() => {
        if (!publishAfterAuth || !api?.isLoggedIn())
            return;
        setPublishAfterAuth(false);
        publishNow();
    }, [publishAfterAuth, user, publishNow]);
    React.useEffect(() => {
        if (!saveAfterAuth || !api?.isLoggedIn())
            return;
        setSaveAfterAuth(false);
        persistDraft();
    }, [saveAfterAuth, user, persistDraft]);
    const handlePublish = async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (!api?.isLoggedIn()) {
            setPublishAfterAuth(true);
            openSignIn ? openSignIn("builder") : alert("Please sign in to publish your invitation.");
            return;
        }
        publishNow();
    };
    return (React.createElement("div", { className: "saas-template-builder" },
        shareSlug && React.createElement(ShareModal, { slug: shareSlug, onClose: () => setShareSlug(null) }),
        React.createElement("aside", { className: "saas-builder-side" },
            React.createElement("div", { className: "saas-template-switch" },
                React.createElement("div", null,
                    React.createElement("span", null, "Template"),
                    React.createElement("strong", null, activeTemplate?.name || "Moonlit Mehfil")),
                React.createElement("button", { type: "button", onClick: () => goTo("builder", { projectId: null }) }, api.isAdminEditor ? 'Administration' : 'Change design')),
            React.createElement("label", { className: "builder-section-picker" },
                React.createElement("span", null, "Editing section"),
                React.createElement("select", { disabled: photoUploads.busy, value: tab, onChange: (e) => setTab(e.target.value) }, MOONLIT_TABS.map((item) => React.createElement("option", { key: item.id, value: item.id }, item.label)))),
            React.createElement("nav", { className: "saas-builder-tabs", "aria-label": "Builder sections" }, MOONLIT_TABS.map((item) => (React.createElement("button", { key: item.id, disabled: photoUploads.busy, "aria-current": tab === item.id ? "step" : undefined, className: tab === item.id ? "active" : "", onClick: () => setTab(item.id) }, item.label)))),
            React.createElement("fieldset", { className: "saas-builder-form", disabled: mediaUploading || savingDraft || publishing, style: { border: 0, margin: 0, minWidth: 0 } },
                React.createElement(TemplateSectionsPanel, { sections: window.EverafterLegacyOptions.definitions("moonlit-mehfil", draft), value: draft.sections, onChange: sections => setDraft(current => window.EverafterLegacyOptions.prepare({ ...current, sections }, "moonlit-mehfil")) }),
                tab === "essentials" && (React.createElement(BuilderPanel, { icon: "o", title: "The Couple", hint: "Live-updates the names, tagline, and date everywhere in the site." },
                    React.createElement(BuildField, { label: "Bride's name", value: draft.couple.bride, onChange: (v) => updateCoupleName("bride", v) }),
                    React.createElement(BuildField, { label: "Groom's name", value: draft.couple.groom, onChange: (v) => updateCoupleName("groom", v) }),
                    React.createElement("div", { className: "builder-inline-row" },
                        React.createElement("span", null,
                            "Name display order",
                            React.createElement("br", null),
                            React.createElement("strong", null,
                                draft.couple.bride,
                                " & ",
                                draft.couple.groom)),
                        React.createElement("button", { type: "button", onClick: swapNames }, "Switch")),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Wedding date", type: "date", value: draft.couple.date, onChange: (v) => update(["couple", "date"], v) }),
                        React.createElement(BuildField, { label: "Venue", value: draft.couple.venue, onChange: (v) => update(["couple", "venue"], v) })),
                    React.createElement(BuildField, { label: "Tagline", value: draft.couple.tagline, onChange: (v) => update(["couple", "tagline"], v), placeholder: "An evening sealed in moonlight" }),
                    React.createElement(BuildField, { label: draft.couple.hashtagCustom ? "Wedding hashtag (custom)" : "Wedding hashtag (auto from names — type to override)", value: draft.couple.hashtag, onChange: updateHashtag, placeholder: moonlitAutoHashtag(draft.couple.bride, draft.couple.groom) }),
                    React.createElement(BuildField, { label: "WhatsApp number", value: draft.couple.whatsapp, onChange: (v) => update(["couple", "whatsapp"], v), placeholder: "+91 98765 43210" }))),
                tab === "story" && (React.createElement(BuilderPanel, { icon: "s", title: "Our Story", hint: "Four love-story moments: how you met, falling slowly, the yes, and now. Each renders as a scroll-driven scene." },
                    React.createElement(BuildToggle, { label: "Show this section", checked: draft.visibility.story, onChange: (v) => update(["visibility", "story"], v) }),
                    draft.story.map((scene, index) => (React.createElement("div", { className: "builder-repeat", key: index },
                        React.createElement("div", { className: "builder-repeat-head" },
                            React.createElement("strong", null, scene.kicker || `Moment ${index + 1}`)),
                        React.createElement(BuildField, { label: "Tag (e.g. How we met)", value: scene.kicker, onChange: (v) => updateStory(index, "kicker", v) }),
                        React.createElement(BuildField, { label: "Title", value: scene.title, onChange: (v) => updateStory(index, "title", v), multi: true, rows: 2, placeholder: "Use a newline to break the title into two lines" }),
                        React.createElement(BuildField, { label: "Story", value: scene.copy, onChange: (v) => updateStory(index, "copy", v), multi: true, rows: 4 }),
                        React.createElement(BuildField, { label: "Mood line", value: scene.mood, onChange: (v) => updateStory(index, "mood", v), placeholder: "Udaipur \u00B7 First evening \u00B7 2023" }),
                        React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo", value: scene.image, onChange: (v) => updateStory(index, "image", v), placeholder: "assets/cinema/..." })))))),
                tab === "events" && (React.createElement(BuilderPanel, { icon: "e", title: "Celebrations", hint: "Each event becomes a tab in the Celebrations section. The photo path renders as the background image for that night." },
                    React.createElement(BuildToggle, { label: "Show this section", checked: draft.visibility.events, onChange: (v) => update(["visibility", "events"], v) }),
                    draft.events.map((event, index) => (React.createElement("div", { className: "builder-repeat", key: event.id || index },
                        React.createElement("div", { className: "builder-repeat-head" },
                            React.createElement("strong", null, event.name || `Event ${index + 1}`),
                            React.createElement("button", { onClick: () => removeEvent(index), "aria-label": "Remove event" }, "Remove")),
                        React.createElement(BuildField, { label: "Event name", value: event.name, onChange: (v) => updateEvent(index, "name", v) }),
                        React.createElement("div", { className: "builder-two-col" },
                            React.createElement(BuildField, { label: "Date", type: "date", value: event.date, onChange: (v) => updateEvent(index, "date", v) }),
                            React.createElement(BuildField, { label: "Time", value: event.time, onChange: (v) => updateEvent(index, "time", v) })),
                        React.createElement(BuildField, { label: "Venue", value: event.venue, onChange: (v) => updateEvent(index, "venue", v) }),
                        React.createElement(BuildField, { label: "Description", value: event.desc, onChange: (v) => updateEvent(index, "desc", v), multi: true }),
                        React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo", value: event.image, onChange: (v) => updateEvent(index, "image", v), placeholder: "assets/cinema/your-photo.jpg" }),
                        React.createElement("div", { className: "builder-two-col" },
                            React.createElement(BuildField, { label: "Icon (single character)", value: event.icon, onChange: (v) => updateEvent(index, "icon", v), placeholder: "\u274B / \u266A / \u263E / \u2726" }),
                            React.createElement(BuildField, { label: "Map link (optional)", value: event.mapsLink, onChange: (v) => updateEvent(index, "mapsLink", v), placeholder: "https://maps.google.com/..." }))))),
                    React.createElement("button", { className: "builder-add-btn", onClick: addEvent }, "Add ceremony"))),
                tab === "couple" && (React.createElement(BuilderPanel, { icon: "u", title: "Us, Together", hint: "Add up to 20 moments with an optional photograph and your own words." },
                    React.createElement(BuildToggle, { label: "Show this section", checked: draft.visibility.couple, onChange: (v) => update(["visibility", "couple"], v) }),
                    React.createElement(BuildField, { label: "Section lede", value: draft.coupleSection.lede, onChange: (v) => update(["coupleSection", "lede"], v), multi: true, rows: 3 }),
                    draft.coupleSection.moments.map((moment, index) => (React.createElement(BuilderPhotoDisclosure, { key: index, label: `Moment ${index + 1}`, value: moment.image, caption: moment.title },
                        React.createElement("div", { className: "builder-repeat-head" }, draft.coupleSection.moments.length > 0 && (React.createElement("button", { type: "button", onClick: () => { if (!photoUploads.pending())
                                removeMoment(index); } }, "Remove moment"))),
                        React.createElement("div", { className: "builder-two-col" },
                            React.createElement(BuildField, { label: "Number (I / II / III\u2026)", value: moment.num, onChange: (v) => updateMoment(index, "num", v) }),
                            React.createElement(BuildField, { label: "Title (Mehendi / Sangeet\u2026)", value: moment.title, onChange: (v) => updateMoment(index, "title", v) })),
                        React.createElement(BuildField, { label: "One-line description (the 'when' phrase)", value: moment.when, onChange: (v) => updateMoment(index, "when", v), placeholder: "Hands sealed in henna" }),
                        React.createElement(BuildField, { label: "Date label", value: moment.date, onChange: (v) => updateMoment(index, "date", v), placeholder: "16 Dec" }),
                        React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo", value: moment.image, onChange: (v) => updateMoment(index, "image", v), placeholder: "assets/cinema/your-photo.jpg" })))),
                    draft.coupleSection.moments.length < 20 && (React.createElement("button", { className: "builder-add-btn", onClick: addMoment },
                        "Add chapter (",
                        draft.coupleSection.moments.length,
                        " / 20)")),
                    React.createElement(BuildField, { label: "Closing love quote", value: draft.coupleSection.quote, onChange: (v) => update(["coupleSection", "quote"], v), multi: true, rows: 3 }),
                    React.createElement(BuildField, { label: "Quote attribution", value: draft.coupleSection.cite, onChange: (v) => update(["coupleSection", "cite"], v), placeholder: "Zoya, to Ayaan" }))),
                tab === "gallery" && (React.createElement(BuilderPanel, { icon: "g", title: "Photos", hint: "Upload photos from your device or paste a URL. Empty slots are skipped. Add up to 20." },
                    React.createElement(BuildToggle, { label: "Show this section", checked: draft.visibility.gallery, onChange: (v) => update(["visibility", "gallery"], v) }),
                    draft.gallery.photos.map((photo, index) => (React.createElement(BuilderPhotoDisclosure, { key: index, label: `Photograph ${index + 1}`, value: photo || "" },
                        React.createElement("div", { className: "builder-repeat-head" }, draft.gallery.photos.length > 0 && (React.createElement("button", { type: "button", onClick: () => { if (!photoUploads.pending())
                                removePhoto(index); } }, "Remove photograph"))),
                        React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo", value: photo || "", onChange: (v) => updatePhoto(index, v), placeholder: "assets/cinema/your-photo.jpg" })))),
                    draft.gallery.photos.length < 20 && (React.createElement("button", { className: "builder-add-btn", onClick: addPhoto },
                        "Add photo (",
                        draft.gallery.photos.length,
                        " / 20)")))),
                tab === "rsvp" && (React.createElement(BuilderPanel, { icon: "r", title: "RSVP", hint: "The closing 'Will you join the mehfil?' card." },
                    React.createElement(BuildToggle, { label: "Show this section", checked: draft.visibility.rsvp, onChange: (v) => update(["visibility", "rsvp"], v) }),
                    React.createElement(BuildField, { label: "Heading", value: draft.rsvp.heading, onChange: (v) => update(["rsvp", "heading"], v) }),
                    React.createElement(BuildField, { label: "Subtext", value: draft.rsvp.subtext, onChange: (v) => update(["rsvp", "subtext"], v), multi: true, rows: 4 }),
                    React.createElement(BuildField, { label: "Button text", value: draft.rsvp.btnText, onChange: (v) => update(["rsvp", "btnText"], v) }),
                    React.createElement(BuildField, { label: "WhatsApp number", value: draft.rsvp.whatsapp, onChange: (v) => update(["rsvp", "whatsapp"], v) }))),
                React.createElement("div", { hidden: tab !== "music" },
                    React.createElement(BuilderPanel, { icon: "a", title: "Music" },
                        React.createElement(MusicUploadPanel, { value: draft.music, nativeMusic: moonlitBaseDraft({}, { ignoreSaved: true }).music, templateId: "moonlit-mehfil", projectId: activeProjectId || projectId, scopeKey: projectId || 'new', user: user, disabled: savingDraft || publishing || photoUploads.busy, onChange: value => update(["music"], value), onBusyChange: setMusicUploading, openSignIn: openSignIn, active: tab === "music" })))),
            React.createElement(BuilderProgressActions, { tabs: MOONLIT_TABS, tab: tab, onTabChange: setTab, onPreview: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading })),
        React.createElement("main", { className: "saas-builder-preview" },
            React.createElement("div", { className: "saas-builder-topbar" },
                React.createElement("div", { className: "builder-save-status" },
                    React.createElement("span", { className: "builder-status-dot" }),
                    React.createElement("span", null,
                        React.createElement("strong", null, activeProjectId ? "Your invitation" : "New design"),
                        React.createElement("small", { role: "status" }, draftMsg || builderSaveStatus(savedAt)))),
                window.EA_UI_PREVIEW === true && React.createElement(BuilderPreviewNotice, { compact: true }),
                React.createElement("div", { className: "saas-builder-actions" },
                    React.createElement("button", { type: "button", className: "mobile-edit-action", onClick: scrollBuilderEditorIntoView },
                        React.createElement(BuilderActionLabel, { full: "Edit details", compact: "Edit" })),
                    React.createElement("button", { type: "button", className: "desktop-reset-action", onClick: resetDemo, disabled: savingDraft || publishing || mediaUploading }, "Reset"),
                    React.createElement("button", { type: "button", onClick: handleSaveDraft, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: savingDraft ? "Saving..." : "Save draft", compact: savingDraft ? "Saving" : "Save" })),
                    React.createElement("button", { type: "button", className: "primary", onClick: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: "Preview so far", compact: "Preview so far" })),
                    React.createElement("button", { type: "button", className: "publish", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined },
                        React.createElement(BuilderActionLabel, { full: publishing ? "Publishing..." : "Publish invitation", compact: publishing ? "Publishing" : "Publish" })))),
            React.createElement("div", { className: "saas-preview-label" }, "Live preview"),
            React.createElement("div", { className: "saas-preview-workspace" }, !isPreviewMode && React.createElement(BuilderPhonePreview, { activeTemplate: activeTemplate, fallbackName: "Moonlit Mehfil", previewSrc: previewSrc })),
            React.createElement("div", { className: "saas-publish-bar" },
                React.createElement("div", { className: "saas-publish-template" },
                    React.createElement("span", { className: "saas-publish-thumb" }),
                    React.createElement("div", null,
                        React.createElement("strong", null, activeTemplate?.name || "Moonlit Mehfil"),
                        React.createElement("span", null, "Cinematic scroll \u00B7 Mobile optimised \u00B7 WhatsApp sharing"))),
                React.createElement("button", { type: "button", className: "saas-publish-btn", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined }, publishing ? "Publishing…" : "Publish invitation"))),
        React.createElement(BuilderPreviewWindow, { open: isPreviewMode, onClose: returnToEditor, activeTemplate: activeTemplate, fallbackName: "Moonlit Mehfil", previewSrc: previewSrc })));
}
const VIVAHA_CONFIG_KEY = "everafter-vivaha-config";
const VIVAHA_BUILDER_TEMPLATE_PATH = TemplateCatalog.get("vivaha").builderTemplatePath;
const VIVAHA_DEFAULT_EVENTS = [
    {
        id: "mehendi",
        label: "01 · Mehendi & Tilak",
        title: "The hands begin to remember him.",
        subtitle: "Henna takes its time. So does Diya. Family-only, low candles, songs only the dadis still know.",
        date: "16 Dec · 5:30 PM",
        venue: "Saffron Terrace · Diya's home",
        mapsLink: "https://maps.app.goo.gl/gZBDMec4ipVWYYxJA",
        photos: [
            { src: "assets/photos/mehendi.jpg", alt: "Mehendi hands", span: "col-span-6 sm:col-span-7 row-span-2", caption: "The artist begins at the fingertips." },
            { src: "assets/photos/bride-portrait.jpg", alt: "Mehendi detail", span: "col-span-6 sm:col-span-5 row-span-1", caption: "A small heart hidden in the design." },
            { src: "assets/photos/groom.jpg", alt: "Tilak", span: "col-span-6 sm:col-span-5 row-span-1", caption: "A drop of saffron from her father." },
        ],
    },
    {
        id: "haldi",
        label: "02 · Haldi & Sangeet",
        title: "Turmeric mornings, neon nights.",
        subtitle: "Yellow hands at noon, choreographed bhangra by midnight. Bring soft shoes and a louder voice.",
        date: "17 Dec · 11 AM + 7:30 PM",
        venue: "Lawns + Mirror Hall, hotel",
        mapsLink: "https://maps.app.goo.gl/gZBDMec4ipVWYYxJA",
        photos: [
            { src: "assets/photos/couple-2.jpg", alt: "Haldi", span: "col-span-6 sm:col-span-5 row-span-2", caption: "A grandmother's palm, yellow all afternoon." },
            { src: "assets/photos/sangeet-1.jpg", alt: "Sangeet", span: "col-span-6 sm:col-span-7 row-span-1", caption: "The cousins have been rehearsing for months." },
            { src: "assets/photos/couple.jpg", alt: "Haldi pots", span: "col-span-6 sm:col-span-3 row-span-1" },
            { src: "assets/photos/sangeet-2.jpg", alt: "Lights", span: "col-span-6 sm:col-span-4 row-span-1", caption: "Dress to dance." },
        ],
    },
    {
        id: "pheras",
        label: "03 · Pheras & Vidaai",
        title: "Seven steps around the fire.",
        subtitle: "On the morning of the eighteenth, by the lake, with our families holding their breath — we will take the steps her grandparents took fifty years ago.",
        date: "18 Dec · Wedding 11:42 AM",
        venue: "Banyan Courtyard, by the lake",
        mapsLink: "https://maps.app.goo.gl/gZBDMec4ipVWYYxJA",
        photos: [
            { src: "assets/photos/pheras-1.jpg", alt: "Mandap", span: "col-span-6 sm:col-span-8 row-span-2", caption: "The mandap, dressed in jasmine." },
            { src: "assets/photos/bride.jpg", alt: "Pheras", span: "col-span-6 sm:col-span-4 row-span-1", caption: "The fire takes us round." },
            { src: "assets/photos/pheras-3.jpg", alt: "Vidaai", span: "col-span-6 sm:col-span-4 row-span-1", caption: "Vidaai · by four in the afternoon." },
        ],
    },
];
const VIVAHA_DEFAULT_PHOTO_STRIP = [
    { src: "assets/photos/couple.jpg", year: "2018", caption: "A monsoon, an inbox." },
    { src: "assets/photos/couple-2.jpg", year: "2019", caption: "A train station that smelled like rain." },
    { src: "assets/photos/bride-portrait.jpg", year: "2021", caption: "A postcard from Kasol." },
    { src: "assets/photos/groom.jpg", year: "2024", caption: "A voice note that ended in yes." },
    { src: "assets/photos/sangeet-1.jpg", year: "2026", caption: "Rehearsing the rooms we will fill." },
    { src: "assets/photos/mehendi.jpg", year: "2026", caption: "And then — December." },
];
const VIVAHA_TABS = [
    { id: "essentials", label: "Essentials" },
    { id: "story", label: "Story" },
    { id: "photos", label: "Photo strip" },
    { id: "events", label: "Ceremonies" },
    { id: "closing", label: "RSVP & Closing" },
    { id: "visibility", label: "Sections" },
    { id: "music", label: "Music" },
];
function readVivahaConfig() { return readBuilderConfig(VIVAHA_CONFIG_KEY); }
function writeVivahaConfig(config) { writeBuilderConfig(VIVAHA_CONFIG_KEY, config); }
function vivahaAutoHashtag(bride, groom) {
    const strip = (s) => (s || "").replace(/[^A-Za-z0-9]+/g, "");
    return "#" + strip(bride) + strip(groom);
}
function inferVivahaCityFromVenue(venue, fallback = "Udaipur") {
    const parts = String(venue || "").split(",").map((part) => part.trim()).filter(Boolean);
    return parts.length > 1 ? parts[parts.length - 1] : fallback;
}
function vivahaVenueShort(venue, city) {
    const cleanVenue = String(venue || "").trim();
    const cleanCity = String(city || "").trim();
    if (!cleanVenue)
        return cleanCity;
    if (!cleanCity || cleanVenue.toLowerCase().includes(cleanCity.toLowerCase()))
        return cleanVenue;
    return `${cleanVenue} · ${cleanCity}`;
}
function vivahaBaseDraft(seed = {}, options = {}) {
    const stored = options.ignoreSaved ? null : readVivahaConfig();
    const saved = options.source || (isLegacyGlobalSeedDraft(stored, "vivaha") ? null : stored);
    const src = saved || {};
    const couple = src.couple || {};
    const hero = src.hero || {};
    const story = src.story || {};
    const lap = story.laptop || {};
    const boy = story.boy || {};
    const girl = story.girl || {};
    const tog = story.together || {};
    const cd = story.countdown || {};
    const ps = story.photoStrip || {};
    const scratch = src.scratch || {};
    const pullRope = src.pullRope || {};
    const closing = src.closing || {};
    const pause = src.pause || {};
    const visibility = src.visibility || {};
    const bride = couple.bride ?? "Diya";
    const groom = couple.groom ?? "Aarav";
    const auto = vivahaAutoHashtag(bride, groom);
    const rawHashtag = (couple.hashtag || "").trim();
    const isAutoHashtag = !rawHashtag || rawHashtag === auto || rawHashtag === "#DiyaAarav";
    const frames = Array.isArray(ps.frames) ? ps.frames : VIVAHA_DEFAULT_PHOTO_STRIP;
    return builderNewDraftMusic({
        ...cloneDraft(src),
        couple: {
            bride,
            groom,
            brideDevanagari: couple.brideDevanagari ?? "दीया",
            groomDevanagari: couple.groomDevanagari ?? "आरव",
            date: couple.date ?? "2026-12-18",
            timeLabel: couple.timeLabel ?? "11:42 AM",
            timeRaw: couple.timeRaw ?? "11:42:00+05:30",
            venue: couple.venue ?? "Banyan Courtyard, by the lake",
            city: couple.city ?? "Udaipur",
            country: couple.country ?? "India",
            mapsLink: couple.mapsLink ?? "https://maps.app.goo.gl/gZBDMec4ipVWYYxJA",
            hashtag: isAutoHashtag ? auto : rawHashtag,
            hashtagCustom: !isAutoHashtag,
        },
        hero: {
            eyebrow: hero.eyebrow ?? "The wedding of",
            subtitle: hero.subtitle ?? "An invitation, with our families",
            scrollHint: hero.scrollHint ?? "Scroll to walk through our story",
        },
        story: {
            laptop: {
                chapter: lap.chapter ?? "Chapter One",
                title: lap.title ?? "How it began — at a desk.",
                intro: lap.intro ?? `${groom} was twenty-three, two cups of chai deep, and writing the function that would one day find her.`,
                groomAge: lap.groomAge ?? "28",
                groomRoleLabel: lap.groomRoleLabel ?? "Software Engineer, Pune",
            },
            boy: { chapterLabel: boy.chapterLabel ?? "Chapter II · The Groom", quote: boy.quote ?? "I rehearsed my vows on the 4:42 local — and forgot them all when she walked in." },
            girl: { chapterLabel: girl.chapterLabel ?? "Chapter III · The Bride", quote: girl.quote ?? "He proposed on a postcard. I said yes on a voice note. We've been clumsy and certain ever since." },
            together: {
                caption: tog.caption ?? "The world rearranged itself.",
                subtext: tog.subtext ?? "Two cities, two grandmothers, two stubborn hearts — kept finding each other until they stopped needing to.",
            },
            countdown: {
                numerals: (Array.isArray(cd.numerals) && cd.numerals.length === 3) ? cd.numerals : ["7", "4", "1"],
                finalText: cd.finalText ?? "And then their orbits met.",
            },
            photos: {
                groomLaptop: (story.photos && story.photos.groomLaptop) || "",
                groomPortrait: (story.photos && story.photos.groomPortrait) || "",
                bridePortrait: (story.photos && story.photos.bridePortrait) || "",
            },
            extraPortraits: Array.isArray(story.extraPortraits) ? story.extraPortraits.map((s) => ({
                id: s.id ?? `extra-${Math.random().toString(36).slice(2, 8)}`,
                chapterLabel: s.chapterLabel ?? "",
                name: s.name ?? "",
                devanagari: s.devanagari ?? "",
                quote: s.quote ?? "",
                photo: s.photo ?? "",
                side: s.side === "right" ? "right" : "left",
            })) : [],
            photoStrip: {
                kicker: ps.kicker ?? "Seven Years · Six Frames",
                title: ps.title ?? "How they got here.",
                frames: frames.map((f) => ({ src: f.src ?? "", year: f.year ?? "", caption: f.caption ?? "" })),
            },
        },
        scratch: {
            eyebrow: scratch.eyebrow ?? "An interactive moment",
            title: scratch.title ?? "Scratch to find the auspicious date.",
            instruction: scratch.instruction ?? "The pandit chose this wedding. Brush away the gold to see the day the seven steps begin.",
            revealEyebrow: scratch.revealEyebrow ?? "The Sacred Date",
            revealTime: scratch.revealTime ?? "Friday · Wedding 11:42 AM",
            revealVenue: scratch.revealVenue ?? "Banyan Courtyard · Udaipur",
            afterLine: scratch.afterLine ?? "The day is set. Now meet the rituals.",
        },
        events: Array.isArray(src.events) ? src.events : VIVAHA_DEFAULT_EVENTS,
        pause: { label: pause.label ?? "a small breath, before the patakhe" },
        pullRope: {
            eyebrow: pullRope.eyebrow ?? "Light the sky",
            title: pullRope.title ?? "Pull the rope, set off the patakhe.",
            before: pullRope.before ?? "Every Indian celebration begins with a sound. Drag the bell down and let the patakhe sing.",
            after: pullRope.after ?? "There. You've lit the whole sky. Save that feeling — we'll be doing this for real come December.",
            blessing: pullRope.blessing ?? "॥ शुभ विवाह ॥",
        },
        closing: {
            eyebrow: closing.eyebrow ?? "An invitation",
            invite: closing.invite ?? "We would be honoured to have you stand with us as the seven steps are taken. Kindly reply by the thirtieth of November so the kitchens, the cars, and the priests can hold a space for you.",
            countdownLabel: closing.countdownLabel ?? "Until the pheras",
            cta: closing.cta ?? "Accept with joy",
            whatsapp: closing.whatsapp ?? "",
            ctaHref: closing.ctaHref === "#" ? "" : (closing.ctaHref || ""),
        },
        marquee: Array.isArray(src.marquee) ? src.marquee : null,
        visibility: {
            laptop: visibility.laptop !== false,
            boy: visibility.boy !== false,
            girl: visibility.girl !== false,
            extraPortraits: visibility.extraPortraits !== false,
            countdown: visibility.countdown !== false,
            together: visibility.together !== false,
            marquee: visibility.marquee !== false,
            photoStrip: visibility.photoStrip !== false,
            scratch: visibility.scratch !== false,
            events: visibility.events !== false,
            pause: visibility.pause !== false,
            pullRope: visibility.pullRope !== false,
            closing: visibility.closing !== false,
        },
    }, saved);
}
function buildVivahaConfig(draft) {
    const cfg = cloneDraft(draft);
    const inferredCity = inferVivahaCityFromVenue(cfg.couple.venue, cfg.couple.city || "Udaipur");
    if (!cfg.couple.city || (cfg.couple.city === "Udaipur" && inferredCity !== "Udaipur")) {
        cfg.couple.city = inferredCity;
    }
    cfg.couple.venueShort = vivahaVenueShort(cfg.couple.venue, cfg.couple.city);
    const dateForLabels = new Date(cfg.couple.date + "T00:00:00");
    const labelYear = Number.isFinite(dateForLabels.getTime()) ? String(dateForLabels.getFullYear()) : "2026";
    cfg.couple.locationLabel = `${cfg.couple.city || "Udaipur"} · ${cfg.couple.country || "India"} · ${labelYear}`;
    cfg.couple.cityTzLabel = `${cfg.couple.city || "Udaipur"} · IST`;
    if (!cfg.scratch.revealVenue || cfg.scratch.revealVenue === "Banyan Courtyard · Udaipur") {
        cfg.scratch.revealVenue = cfg.couple.venueShort;
    }
    cfg.story.photoStrip.frames = (cfg.story.photoStrip.frames || []).filter((f) => f.src);
    cfg.events = (cfg.events || []).filter((e) => e && (e.title || e.label));
    if (cfg.closing.ctaHref === "#")
        cfg.closing.ctaHref = "";
    if (!Array.isArray(cfg.marquee) || !cfg.marquee.length) {
        const d = new Date(cfg.couple.date + "T00:00:00");
        let dd = "18", mm = "12", yyyy = "2026";
        if (Number.isFinite(d.getTime())) {
            dd = String(d.getDate()).padStart(2, "0");
            mm = String(d.getMonth() + 1).padStart(2, "0");
            yyyy = String(d.getFullYear());
        }
        cfg.marquee = [
            cfg.couple.bride,
            cfg.couple.groom,
            `${dd} . ${mm} . ${yyyy}`,
            cfg.couple.city,
            "with our families",
            "in joy",
            "by the lake",
        ];
    }
    return cfg;
}
function VivahaBuilder({ goTo, t, template, user, openSignIn, projectId, verifiedProject, verifiedOwnerId, recoveredDraft }) {
    const api = useBuilderApi();
    const activeTemplate = template || TemplateCatalog.get("vivaha");
    const [draft, setDraft] = React.useState(() => vivahaBaseDraft(t));
    const [activeProjectId, setActiveProjectId] = React.useState(projectId || null);
    const [tab, setTab] = React.useState("essentials");
    const [previewVersion, setPreviewVersion] = React.useState(1);
    const [savedAt, setSavedAt] = React.useState("");
    const [isPreviewMode, setIsPreviewMode] = React.useState(() => {
        try {
            return new URLSearchParams(window.location.search).get("preview") === "1";
        }
        catch (_) {
            return false;
        }
    });
    const [shareSlug, setShareSlug] = React.useState(null);
    const [publishing, setPublishing] = React.useState(false);
    const [publishAfterAuth, setPublishAfterAuth] = React.useState(false);
    const [savingDraft, setSavingDraft] = React.useState(false);
    const [musicUploading, setMusicUploading] = React.useState(false);
    const photoUploads = useBuilderPhotoUploads({ templateId: 'vivaha', projectId: activeProjectId || projectId, user });
    const mediaUploading = musicUploading || photoUploads.busy;
    const [saveAfterAuth, setSaveAfterAuth] = React.useState(false);
    const [draftMsg, setDraftMsg] = React.useState("");
    const skipNextAutosaveRef = React.useRef(true);
    const projectLoadPendingRef = React.useRef(false);
    const previewSessionRef = React.useRef(`vivaha-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`);
    const { enterPreview, returnToEditor } = useBuilderPreviewNavigation(isPreviewMode, setIsPreviewMode);
    const config = React.useMemo(() => buildVivahaConfig(draft), [draft]);
    const builderTemplatePath = activeTemplate?.builderTemplatePath || VIVAHA_BUILDER_TEMPLATE_PATH;
    const builderTemplateUrl = resolveWeddingAssetUrl(builderTemplatePath);
    const previewSrc = buildBuilderPreviewSrc(builderTemplateUrl, "vivaha", previewVersion, previewSessionRef.current);
    useBuilderPreviewPolish([previewSrc, isPreviewMode]);
    useLoadedProjectConfig({
        verifiedProject, verifiedOwnerId, recoveredDraft,
        projectId,
        templateId: "vivaha",
        user,
        setActiveProjectId,
        setDraft,
        makeDraft: (source) => vivahaBaseDraft(t, { source }),
        writeConfig: writeVivahaConfig,
        setPreviewVersion,
        setSavedAt,
        onConfigLoaded: () => { skipNextAutosaveRef.current = true; },
        loadPendingRef: projectLoadPendingRef,
    });
    useBuilderAutosave({
        uploading: mediaUploading, photoUploads,
        user,
        config,
        activeProjectId,
        templateId: "vivaha",
        writeConfig: writeVivahaConfig,
        setPreviewVersion,
        setSavedAt,
        skipNextRef: skipNextAutosaveRef,
        loadPendingRef: projectLoadPendingRef,
    });
    const update = (path, value) => setDraft((current) => setDeepDraft(current, path, value));
    const updateCoupleName = (key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.couple[key] = value;
        if (!next.couple.hashtagCustom) {
            next.couple.hashtag = vivahaAutoHashtag(next.couple.bride, next.couple.groom);
        }
        return next;
    });
    const updateHashtag = (value) => setDraft((current) => {
        const next = cloneDraft(current);
        const trimmed = (value || "").trim();
        const auto = vivahaAutoHashtag(next.couple.bride, next.couple.groom);
        next.couple.hashtag = trimmed || auto;
        next.couple.hashtagCustom = !!trimmed && trimmed !== auto;
        return next;
    });
    const swapNames = () => setDraft((current) => {
        const next = cloneDraft(current);
        [next.couple.bride, next.couple.groom] = [next.couple.groom, next.couple.bride];
        [next.couple.brideDevanagari, next.couple.groomDevanagari] = [next.couple.groomDevanagari, next.couple.brideDevanagari];
        if (!next.couple.hashtagCustom) {
            next.couple.hashtag = vivahaAutoHashtag(next.couple.bride, next.couple.groom);
        }
        return next;
    });
    const updateFrame = (index, key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.story.photoStrip.frames[index][key] = value;
        return next;
    });
    const addFrame = () => setDraft((current) => {
        if ((current.story.photoStrip.frames || []).length >= 20)
            return current;
        const next = cloneDraft(current);
        next.story.photoStrip.frames.push({ src: "", year: "", caption: "" });
        return next;
    });
    const removeFrame = (index) => setDraft((current) => {
        if (!(current.story.photoStrip.frames || []).length)
            return current;
        const next = cloneDraft(current);
        next.story.photoStrip.frames.splice(index, 1);
        return next;
    });
    const updateEvent = (index, key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.events[index][key] = value;
        return next;
    });
    const updateExtraPortrait = (index, key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        if (!next.story.extraPortraits[index])
            return current;
        next.story.extraPortraits[index][key] = value;
        return next;
    });
    const addExtraPortrait = () => setDraft((current) => {
        if ((current.story.extraPortraits || []).length >= 20)
            return current;
        const next = cloneDraft(current);
        const i = next.story.extraPortraits.length;
        const romanNumerals = ["IV", "V", "VI", "VII", "VIII", "IX", "X", "XI"];
        next.story.extraPortraits.push({
            id: `extra-${Math.random().toString(36).slice(2, 8)}`,
            chapterLabel: `Chapter ${romanNumerals[i] || (i + 4)}`,
            name: "",
            devanagari: "",
            quote: "",
            photo: "",
            side: i % 2 === 0 ? "left" : "right",
        });
        return next;
    });
    const removeExtraPortrait = (index) => setDraft((current) => {
        const next = cloneDraft(current);
        next.story.extraPortraits.splice(index, 1);
        return next;
    });
    const updateEventPhoto = (eventIndex, photoIndex, key, value) => setDraft((current) => {
        const next = cloneDraft(current);
        if (!next.events[eventIndex].photos)
            next.events[eventIndex].photos = [];
        if (!next.events[eventIndex].photos[photoIndex])
            next.events[eventIndex].photos[photoIndex] = { src: "", alt: "", caption: "" };
        next.events[eventIndex].photos[photoIndex][key] = value;
        return next;
    });
    const updateNumeral = (index, value) => setDraft((current) => {
        const next = cloneDraft(current);
        next.story.countdown.numerals[index] = value;
        return next;
    });
    const saveNow = () => {
        writeVivahaConfig(config);
        setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
        setPreviewVersion((v) => v + 1);
    };
    const persistDraft = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setSavingDraft(true);
        setDraftMsg("");
        const res = await runSaveDraft({ api, templateId: "vivaha", config, writeConfig: writeVivahaConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setSavingDraft(false);
        if (res.ok) {
            setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
            setPreviewVersion((v) => v + 1);
            setDraftMsg(res.local ? "Draft saved on this device for this UI preview." : (api.isAdminEditor ? "Draft saved for the customer." : "Draft saved in your dashboard."));
        }
        else if (res.reason === "login") {
            setDraftMsg("Sign in to save this draft.");
        }
        else {
            setDraftMsg("Could not save draft: " + res.reason);
        }
    }, [config, activeProjectId, mediaUploading]);
    const handleSaveDraft = () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (window.EA_UI_PREVIEW === true) {
            persistDraft();
            return;
        }
        if (!api?.isLoggedIn()) {
            setSaveAfterAuth(true);
            setDraftMsg("Sign in to save this draft.");
            openSignIn ? openSignIn("builder") : alert("Please sign in to save your draft.");
            return;
        }
        persistDraft();
    };
    const showRealtimePreview = (event) => { saveNow(); enterPreview(event); };
    const resetDemo = () => {
        if (photoUploads.pending())
            return;
        if (!window.confirm("Reset this design to its sample details? Your current changes will be replaced." + (activeProjectId ? " Your saved invitation will also update." : "")))
            return;
        try {
            window.localStorage.removeItem(builderDraftKey(VIVAHA_CONFIG_KEY));
        }
        catch (_) { }
        setDraft(vivahaBaseDraft(t, { ignoreSaved: true }));
        setTab("essentials");
        setIsPreviewMode(false);
        setPreviewVersion((v) => v + 1);
    };
    const publishNow = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setPublishing(true);
        const res = await runPublish({ api, templateId: "vivaha", config, writeConfig: writeVivahaConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setPublishing(false);
        if (res.ok)
            setShareSlug(res.slug);
        else if (res.reason !== "login")
            alert("Could not publish: " + res.reason);
    }, [config, activeProjectId, mediaUploading]);
    React.useEffect(() => {
        if (!publishAfterAuth || !api?.isLoggedIn())
            return;
        setPublishAfterAuth(false);
        publishNow();
    }, [publishAfterAuth, user, publishNow]);
    React.useEffect(() => {
        if (!saveAfterAuth || !api?.isLoggedIn())
            return;
        setSaveAfterAuth(false);
        persistDraft();
    }, [saveAfterAuth, user, persistDraft]);
    const handlePublish = async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (!api?.isLoggedIn()) {
            setPublishAfterAuth(true);
            openSignIn ? openSignIn("builder") : alert("Please sign in to publish your invitation.");
            return;
        }
        publishNow();
    };
    return (React.createElement("div", { className: "saas-template-builder" },
        shareSlug && React.createElement(ShareModal, { slug: shareSlug, onClose: () => setShareSlug(null) }),
        React.createElement("aside", { className: "saas-builder-side" },
            React.createElement("div", { className: "saas-template-switch" },
                React.createElement("div", null,
                    React.createElement("span", null, "Template"),
                    React.createElement("strong", null, activeTemplate?.name || "Vivaha")),
                React.createElement("button", { type: "button", onClick: () => goTo("builder", { projectId: null }) }, api.isAdminEditor ? 'Administration' : 'Change design')),
            React.createElement("label", { className: "builder-section-picker" },
                React.createElement("span", null, "Editing section"),
                React.createElement("select", { disabled: photoUploads.busy, value: tab, onChange: (e) => setTab(e.target.value) }, VIVAHA_TABS.map((item) => React.createElement("option", { key: item.id, value: item.id }, item.label)))),
            React.createElement("nav", { className: "saas-builder-tabs", "aria-label": "Builder sections" }, VIVAHA_TABS.map((item) => (React.createElement("button", { key: item.id, disabled: photoUploads.busy, "aria-current": tab === item.id ? "step" : undefined, className: tab === item.id ? "active" : "", onClick: () => setTab(item.id) }, item.label)))),
            React.createElement("fieldset", { className: "saas-builder-form", disabled: mediaUploading || savingDraft || publishing, style: { border: 0, margin: 0, minWidth: 0 } },
                React.createElement(TemplateSectionsPanel, { sections: window.EverafterLegacyOptions.definitions("vivaha", draft), value: draft.sections, onChange: sections => setDraft(current => window.EverafterLegacyOptions.prepare({ ...current, sections }, "vivaha")) }),
                tab === "essentials" && (React.createElement(BuilderPanel, { icon: "o", title: "The Couple", hint: "Live-updates the names, date and venue everywhere \u2014 including the auto-derived display strings (year tag, hero date, countdown)." },
                    React.createElement(BuildField, { label: "Bride's name", value: draft.couple.bride, onChange: (v) => updateCoupleName("bride", v) }),
                    React.createElement(BuildField, { label: "Bride \u00B7 Devanagari", value: draft.couple.brideDevanagari, onChange: (v) => update(["couple", "brideDevanagari"], v), placeholder: "\u0926\u0940\u092F\u093E" }),
                    React.createElement(BuildField, { label: "Groom's name", value: draft.couple.groom, onChange: (v) => updateCoupleName("groom", v) }),
                    React.createElement(BuildField, { label: "Groom \u00B7 Devanagari", value: draft.couple.groomDevanagari, onChange: (v) => update(["couple", "groomDevanagari"], v), placeholder: "\u0906\u0930\u0935" }),
                    React.createElement("div", { className: "builder-inline-row" },
                        React.createElement("span", null,
                            "Name order",
                            React.createElement("br", null),
                            React.createElement("strong", null,
                                draft.couple.bride,
                                " & ",
                                draft.couple.groom)),
                        React.createElement("button", { type: "button", onClick: swapNames }, "Switch")),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Wedding date", type: "date", value: draft.couple.date, onChange: (v) => update(["couple", "date"], v) }),
                        React.createElement(BuildField, { label: "Time (display)", value: draft.couple.timeLabel, onChange: (v) => update(["couple", "timeLabel"], v), placeholder: "11:42 AM" })),
                    React.createElement(BuildField, { label: "Time (technical, used by the countdown)", value: draft.couple.timeRaw, onChange: (v) => update(["couple", "timeRaw"], v), placeholder: "11:42:00+05:30" }),
                    React.createElement(BuildField, { label: "Venue (long form)", value: draft.couple.venue, onChange: (v) => update(["couple", "venue"], v) }),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "City", value: draft.couple.city, onChange: (v) => update(["couple", "city"], v) }),
                        React.createElement(BuildField, { label: "Country", value: draft.couple.country, onChange: (v) => update(["couple", "country"], v) })),
                    React.createElement(BuildField, { label: "Maps link", value: draft.couple.mapsLink, onChange: (v) => update(["couple", "mapsLink"], v), placeholder: "https://maps.app.goo.gl/..." }),
                    React.createElement(BuildField, { label: draft.couple.hashtagCustom ? "Wedding hashtag (custom)" : "Wedding hashtag (auto from names — type to override)", value: draft.couple.hashtag, onChange: updateHashtag, placeholder: vivahaAutoHashtag(draft.couple.bride, draft.couple.groom) }),
                    React.createElement("div", { style: { height: 14 } }),
                    React.createElement(BuilderPanel, { icon: "h", title: "Hero copy", hint: "The top-of-page film card. The big date/weekday/city line is auto-derived from the fields above." },
                        React.createElement(BuildField, { label: "Eyebrow ('The wedding of')", value: draft.hero.eyebrow, onChange: (v) => update(["hero", "eyebrow"], v) }),
                        React.createElement(BuildField, { label: "Top-right subtitle", value: draft.hero.subtitle, onChange: (v) => update(["hero", "subtitle"], v) }),
                        React.createElement(BuildField, { label: "Scroll hint at bottom", value: draft.hero.scrollHint, onChange: (v) => update(["hero", "scrollHint"], v) })))),
                tab === "story" && (React.createElement(BuilderPanel, { icon: "s", title: "Origin Scene \u00B7 Laptop", hint: "The opening sequence \u2014 scroll zooms into the groom's laptop screen." },
                    React.createElement(BuildField, { label: "Chapter eyebrow", value: draft.story.laptop.chapter, onChange: (v) => update(["story", "laptop", "chapter"], v) }),
                    React.createElement(BuildField, { label: "Title", value: draft.story.laptop.title, onChange: (v) => update(["story", "laptop", "title"], v) }),
                    React.createElement(BuildField, { label: "Intro paragraph", value: draft.story.laptop.intro, onChange: (v) => update(["story", "laptop", "intro"], v), multi: true, rows: 3 }),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Groom age", value: draft.story.laptop.groomAge, onChange: (v) => update(["story", "laptop", "groomAge"], v) }),
                        React.createElement(BuildField, { label: "Groom role line", value: draft.story.laptop.groomRoleLabel, onChange: (v) => update(["story", "laptop", "groomRoleLabel"], v), placeholder: "Software Engineer, Pune" })),
                    React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo (emerges from the laptop screen)", value: draft.story.photos.groomLaptop, onChange: (v) => update(["story", "photos", "groomLaptop"], v), placeholder: "Leave empty to use the bundled groom.jpg" }),
                    React.createElement("div", { style: { height: 14 } }),
                    React.createElement(BuilderPanel, { icon: "b", title: "The Groom \u00B7 portrait scene", hint: "Full-bleed cinematic image with a quote overlay." },
                        React.createElement(BuildField, { label: "Chapter label", value: draft.story.boy.chapterLabel, onChange: (v) => update(["story", "boy", "chapterLabel"], v), placeholder: "Chapter II \u00B7 The Groom" }),
                        React.createElement(BuildField, { label: "Quote", value: draft.story.boy.quote, onChange: (v) => update(["story", "boy", "quote"], v), multi: true, rows: 3 }),
                        React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Groom portrait (also used in the 'Together' split)", value: draft.story.photos.groomPortrait, onChange: (v) => update(["story", "photos", "groomPortrait"], v), placeholder: "Leave empty to use the bundled groom-portrait.jpg" })),
                    React.createElement(BuilderPanel, { icon: "g", title: "The Bride \u00B7 portrait scene", hint: "Mirror of the groom scene \u2014 petal shower behind." },
                        React.createElement(BuildField, { label: "Chapter label", value: draft.story.girl.chapterLabel, onChange: (v) => update(["story", "girl", "chapterLabel"], v), placeholder: "Chapter III \u00B7 The Bride" }),
                        React.createElement(BuildField, { label: "Quote", value: draft.story.girl.quote, onChange: (v) => update(["story", "girl", "quote"], v), multi: true, rows: 3 }),
                        React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Bride portrait (also used in the 'Together' split)", value: draft.story.photos.bridePortrait, onChange: (v) => update(["story", "photos", "bridePortrait"], v), placeholder: "Leave empty to use the bundled bride.jpg" })),
                    React.createElement(BuilderPanel, { icon: "+", title: "Extra portrait scenes", hint: "Add up to 20 extra portraits, each with its own name and caption." },
                        (draft.story.extraPortraits || []).map((scene, index) => (React.createElement(BuilderPhotoDisclosure, { key: scene.id || index, label: `Portrait ${index + 1}`, value: scene.photo, caption: scene.chapterLabel },
                            React.createElement("div", { className: "builder-repeat-head" },
                                React.createElement("button", { type: "button", onClick: () => { if (!photoUploads.pending())
                                        removeExtraPortrait(index); } }, "Remove portrait")),
                            React.createElement(BuildField, { label: "Chapter label (top-left, eyebrow)", value: scene.chapterLabel, onChange: (v) => updateExtraPortrait(index, "chapterLabel", v), placeholder: "Chapter IV \u00B7 Together" }),
                            React.createElement("div", { className: "builder-two-col" },
                                React.createElement(BuildField, { label: "Name (big italic at bottom)", value: scene.name, onChange: (v) => updateExtraPortrait(index, "name", v), placeholder: "Optional \u2014 leave empty for caption-only" }),
                                React.createElement(BuildField, { label: "Devanagari", value: scene.devanagari, onChange: (v) => updateExtraPortrait(index, "devanagari", v), placeholder: "Optional" })),
                            React.createElement(BuildField, { label: "Quote / caption", value: scene.quote, onChange: (v) => updateExtraPortrait(index, "quote", v), multi: true, rows: 3 }),
                            React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo", value: scene.photo, onChange: (v) => updateExtraPortrait(index, "photo", v), placeholder: "Upload or paste an asset path" }),
                            React.createElement(BuildSelect, { label: "Text alignment", value: scene.side, onChange: (v) => updateExtraPortrait(index, "side", v), options: [["left", "Left-aligned (like the groom scene)"], ["right", "Right-aligned (like the bride scene)"]] })))),
                        (draft.story.extraPortraits || []).length < 20 && (React.createElement("button", { className: "builder-add-btn", onClick: addExtraPortrait },
                            "Add portrait scene (",
                            (draft.story.extraPortraits || []).length,
                            " / 20)"))),
                    React.createElement(BuilderPanel, { icon: "t", title: "Together \u00B7 split \u2192 merge", hint: "Two halves meet, a medallion glows, a caption settles in." },
                        React.createElement(BuildField, { label: "Caption", value: draft.story.together.caption, onChange: (v) => update(["story", "together", "caption"], v) }),
                        React.createElement(BuildField, { label: "Subtext", value: draft.story.together.subtext, onChange: (v) => update(["story", "together", "subtext"], v), multi: true, rows: 3 })),
                    React.createElement(BuilderPanel, { icon: "c", title: "Suspense countdown", hint: "Three big numerals pulse in over a long scroll, then a final line types out." },
                        React.createElement("div", { className: "builder-two-col", style: { gridTemplateColumns: "1fr 1fr 1fr" } },
                            React.createElement(BuildField, { label: "Numeral 1", value: draft.story.countdown.numerals[0], onChange: (v) => updateNumeral(0, v) }),
                            React.createElement(BuildField, { label: "Numeral 2", value: draft.story.countdown.numerals[1], onChange: (v) => updateNumeral(1, v) }),
                            React.createElement(BuildField, { label: "Numeral 3", value: draft.story.countdown.numerals[2], onChange: (v) => updateNumeral(2, v) })),
                        React.createElement(BuildField, { label: "Final reveal line", value: draft.story.countdown.finalText, onChange: (v) => update(["story", "countdown", "finalText"], v) })))),
                tab === "photos" && (React.createElement(BuilderPanel, { icon: "p", title: "Photo strip \u00B7 sticky horizontal", hint: "Add up to 20 photographs. Guests move through them as they scroll." },
                    React.createElement(BuildField, { label: "Kicker", value: draft.story.photoStrip.kicker, onChange: (v) => update(["story", "photoStrip", "kicker"], v), placeholder: "Seven Years \u00B7 Six Frames" }),
                    React.createElement(BuildField, { label: "Title", value: draft.story.photoStrip.title, onChange: (v) => update(["story", "photoStrip", "title"], v), placeholder: "How they got here." }),
                    draft.story.photoStrip.frames.map((frame, index) => (React.createElement(BuilderPhotoDisclosure, { key: index, label: `Photograph ${index + 1}`, value: frame.src, caption: frame.caption || frame.year },
                        React.createElement("div", { className: "builder-repeat-head" }, draft.story.photoStrip.frames.length > 0 && (React.createElement("button", { type: "button", onClick: () => { if (!photoUploads.pending())
                                removeFrame(index); } }, "Remove photograph"))),
                        React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo", value: frame.src, onChange: (v) => updateFrame(index, "src", v), placeholder: "assets/photos/your-photo.jpg" }),
                        React.createElement("div", { className: "builder-two-col" },
                            React.createElement(BuildField, { label: "Year", value: frame.year, onChange: (v) => updateFrame(index, "year", v), placeholder: "2024" }),
                            React.createElement(BuildField, { label: "Caption", value: frame.caption, onChange: (v) => updateFrame(index, "caption", v), placeholder: "A voice note that ended in yes." }))))),
                    draft.story.photoStrip.frames.length < 20 && (React.createElement("button", { className: "builder-add-btn", onClick: addFrame },
                        "Add frame (",
                        draft.story.photoStrip.frames.length,
                        " / 20)")))),
                tab === "events" && (React.createElement(BuilderPanel, { icon: "e", title: "Ceremonies (Mehendi \u00B7 Haldi \u00B7 Pheras)", hint: "Each renders as a full ceremony gallery with parallax photo cards. Edit the copy plus each photo (upload from your device or paste a path)." }, draft.events.map((event, index) => (React.createElement("div", { className: "builder-repeat", key: event.id || index },
                    React.createElement("div", { className: "builder-repeat-head" },
                        React.createElement("strong", null, event.label || event.id || `Event ${index + 1}`)),
                    React.createElement(BuildField, { label: "Section eyebrow (e.g. '01 \u00B7 Mehendi & Tilak')", value: event.label, onChange: (v) => updateEvent(index, "label", v) }),
                    React.createElement(BuildField, { label: "Title", value: event.title, onChange: (v) => updateEvent(index, "title", v) }),
                    React.createElement(BuildField, { label: "Subtitle / blurb", value: event.subtitle, onChange: (v) => updateEvent(index, "subtitle", v), multi: true, rows: 3 }),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Date (display)", value: event.date, onChange: (v) => updateEvent(index, "date", v), placeholder: "16 Dec \u00B7 5:30 PM" }),
                        React.createElement(BuildField, { label: "Venue", value: event.venue, onChange: (v) => updateEvent(index, "venue", v) })),
                    React.createElement(BuildField, { label: "Maps link", value: event.mapsLink, onChange: (v) => updateEvent(index, "mapsLink", v), placeholder: "https://maps.app.goo.gl/..." }),
                    React.createElement("div", { className: "builder-section-divider", style: { marginTop: 12, paddingTop: 12, borderTop: "1px solid rgba(44,33,24,0.12)" } },
                        React.createElement("strong", { style: { display: "block", fontSize: 12, letterSpacing: "0.2em", textTransform: "uppercase", opacity: 0.7, marginBottom: 8 } },
                            "Photos (",
                            (event.photos || []).length,
                            ")"),
                        (event.photos || []).length < 20 && React.createElement("button", { type: "button", onClick: () => update(["events", index, "photos"], [...(event.photos || []), { src: "", alt: "", caption: "", span: "col-span-12 sm:col-span-6" }]) }, "Add photograph"),
                        (event.photos || []).map((ph, pi) => (React.createElement(BuilderPhotoDisclosure, { key: pi, label: `Photograph ${pi + 1}`, value: ph.src, caption: ph.caption },
                            React.createElement("button", { type: "button", onClick: () => { if (!photoUploads.pending())
                                    update(["events", index, "photos"], event.photos.filter((_, i) => i !== pi)); } }, "Remove photograph"),
                            React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: `Photo ${pi + 1}`, value: ph.src, onChange: (v) => updateEventPhoto(index, pi, "src", v), placeholder: "assets/photos/your-photo.jpg" }),
                            React.createElement(BuildField, { label: "Caption (shown on hover overlay)", value: ph.caption || "", onChange: (v) => updateEventPhoto(index, pi, "caption", v), placeholder: "Leave empty for no caption" })))))))))),
                tab === "closing" && (React.createElement(React.Fragment, null,
                    React.createElement(BuilderPanel, { icon: "r", title: "Scratch the date", hint: "The interactive scratch-to-reveal moment that uncovers the wedding date." },
                        React.createElement(BuildField, { label: "Eyebrow", value: draft.scratch.eyebrow, onChange: (v) => update(["scratch", "eyebrow"], v) }),
                        React.createElement(BuildField, { label: "Title", value: draft.scratch.title, onChange: (v) => update(["scratch", "title"], v), multi: true, rows: 2 }),
                        React.createElement(BuildField, { label: "Instruction", value: draft.scratch.instruction, onChange: (v) => update(["scratch", "instruction"], v), multi: true, rows: 3 }),
                        React.createElement(BuildField, { label: "Revealed venue line", value: draft.scratch.revealVenue, onChange: (v) => update(["scratch", "revealVenue"], v), placeholder: "Banyan Courtyard \u00B7 Udaipur" }),
                        React.createElement(BuildField, { label: "Revealed time line", value: draft.scratch.revealTime, onChange: (v) => update(["scratch", "revealTime"], v), placeholder: "Friday \u00B7 Wedding 11:42 AM" }),
                        React.createElement(BuildField, { label: "Closing line after reveal", value: draft.scratch.afterLine, onChange: (v) => update(["scratch", "afterLine"], v) })),
                    React.createElement(BuilderPanel, { icon: "p", title: "Pull rope \u00B7 patakhe", hint: "Interactive bell-pull that triggers the fireworks finale." },
                        React.createElement(BuildField, { label: "Eyebrow", value: draft.pullRope.eyebrow, onChange: (v) => update(["pullRope", "eyebrow"], v) }),
                        React.createElement(BuildField, { label: "Title", value: draft.pullRope.title, onChange: (v) => update(["pullRope", "title"], v) }),
                        React.createElement(BuildField, { label: "Before pull", value: draft.pullRope.before, onChange: (v) => update(["pullRope", "before"], v), multi: true, rows: 3 }),
                        React.createElement(BuildField, { label: "After pull", value: draft.pullRope.after, onChange: (v) => update(["pullRope", "after"], v), multi: true, rows: 3 }),
                        React.createElement(BuildField, { label: "Blessing (rendered in Devanagari)", value: draft.pullRope.blessing, onChange: (v) => update(["pullRope", "blessing"], v), placeholder: "\u0965 \u0936\u0941\u092D \u0935\u093F\u0935\u093E\u0939 \u0965" })),
                    React.createElement(BuilderPanel, { icon: "c", title: "Closing / RSVP", hint: "The final scene \u2014 couple's names, the three When/Wedding/Where cells, the live countdown, the CTA button." },
                        React.createElement(BuildField, { label: "Eyebrow", value: draft.closing.eyebrow, onChange: (v) => update(["closing", "eyebrow"], v), placeholder: "An invitation" }),
                        React.createElement(BuildField, { label: "Invite paragraph", value: draft.closing.invite, onChange: (v) => update(["closing", "invite"], v), multi: true, rows: 4 }),
                        React.createElement(BuildField, { label: "Countdown label", value: draft.closing.countdownLabel, onChange: (v) => update(["closing", "countdownLabel"], v), placeholder: "Until the pheras" }),
                        React.createElement(BuildField, { label: "WhatsApp number for RSVPs", value: draft.closing.whatsapp, onChange: (v) => update(["closing", "whatsapp"], v), placeholder: "+91 98765 43210" }),
                        React.createElement("div", { className: "builder-upload-placeholder" }, "Guests tap the closing button to RSVP on WhatsApp. Leave the CTA link empty to use this number, or paste a custom link below to override it."),
                        React.createElement("div", { className: "builder-two-col" },
                            React.createElement(BuildField, { label: "CTA button text", value: draft.closing.cta, onChange: (v) => update(["closing", "cta"], v), placeholder: "Accept with joy" }),
                            React.createElement(BuildField, { label: "CTA link", value: draft.closing.ctaHref, onChange: (v) => update(["closing", "ctaHref"], v), placeholder: "https://\u2026 or #" })),
                        React.createElement(BuildField, { label: "Pause section label", value: draft.pause.label, onChange: (v) => update(["pause", "label"], v), placeholder: "a small breath, before the patakhe" })))),
                React.createElement("div", { hidden: tab !== "music" },
                    React.createElement(BuilderPanel, { icon: "a", title: "Music" },
                        React.createElement(MusicUploadPanel, { value: draft.music, nativeMusic: undefined, templateId: "vivaha", projectId: activeProjectId || projectId, scopeKey: projectId || 'new', user: user, disabled: savingDraft || publishing || photoUploads.busy, onChange: value => update(["music"], value), onBusyChange: setMusicUploading, openSignIn: openSignIn, active: tab === "music" })))),
            React.createElement(BuilderProgressActions, { tabs: VIVAHA_TABS, tab: tab, onTabChange: setTab, onPreview: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading })),
        React.createElement("main", { className: "saas-builder-preview" },
            React.createElement("div", { className: "saas-builder-topbar" },
                React.createElement("div", { className: "builder-save-status" },
                    React.createElement("span", { className: "builder-status-dot" }),
                    React.createElement("span", null,
                        React.createElement("strong", null, activeProjectId ? "Your invitation" : "New design"),
                        React.createElement("small", { role: "status" }, draftMsg || builderSaveStatus(savedAt)))),
                window.EA_UI_PREVIEW === true && React.createElement(BuilderPreviewNotice, { compact: true }),
                React.createElement("div", { className: "saas-builder-actions" },
                    React.createElement("button", { type: "button", className: "mobile-edit-action", onClick: scrollBuilderEditorIntoView },
                        React.createElement(BuilderActionLabel, { full: "Edit details", compact: "Edit" })),
                    React.createElement("button", { type: "button", className: "desktop-reset-action", onClick: resetDemo, disabled: savingDraft || publishing || mediaUploading }, "Reset"),
                    React.createElement("button", { type: "button", onClick: handleSaveDraft, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: savingDraft ? "Saving..." : "Save draft", compact: savingDraft ? "Saving" : "Save" })),
                    React.createElement("button", { type: "button", className: "primary", onClick: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: "Preview so far", compact: "Preview so far" })),
                    React.createElement("button", { type: "button", className: "publish", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined },
                        React.createElement(BuilderActionLabel, { full: publishing ? "Publishing..." : "Publish invitation", compact: publishing ? "Publishing" : "Publish" })))),
            React.createElement("div", { className: "saas-preview-label" }, "Live preview"),
            React.createElement("div", { className: "saas-preview-workspace" }, !isPreviewMode && React.createElement(BuilderPhonePreview, { activeTemplate: activeTemplate, fallbackName: "Vivaha", previewSrc: previewSrc })),
            React.createElement("div", { className: "saas-publish-bar" },
                React.createElement("div", { className: "saas-publish-template" },
                    React.createElement("span", { className: "saas-publish-thumb" }),
                    React.createElement("div", null,
                        React.createElement("strong", null, activeTemplate?.name || "Vivaha"),
                        React.createElement("span", null, "Cinematic scroll \u00B7 Mobile optimised \u00B7 WhatsApp sharing"))),
                React.createElement("button", { type: "button", className: "saas-publish-btn", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined }, publishing ? "Publishing…" : "Publish invitation"))),
        React.createElement(BuilderPreviewWindow, { open: isPreviewMode, onClose: returnToEditor, activeTemplate: activeTemplate, fallbackName: "Vivaha", previewSrc: previewSrc })));
}
Object.assign(window, {
    Builder,
    RoyalPichwaiBuilder,
    MoonlitMehfilBuilder,
    VivahaBuilder,
    buildTemplate09Config,
    readTemplate09Config,
    writeTemplate09Config,
    buildMoonlitConfig,
    readMoonlitConfig,
    writeMoonlitConfig,
    buildVivahaConfig,
    readVivahaConfig,
    writeVivahaConfig,
});
const HAVELI_CONFIG_KEY = "everafter-haveli-dusk-config";
const HAVELI_BUILDER_TEMPLATE_PATH = TemplateCatalog.get("haveli-dusk").builderTemplatePath;
const HAVELI_ASSET_ROOT = builderAppPath("/wedding-invitations/uploads/builder-templates/Haveli Dusk/assets");
const HAVELI_DEFAULT_EVENTS = [
    { id: "mehendi", name: "Mehendi", date: "2026-12-12", time: "4:00 PM", venue: "Rang Aangan", desc: "Henna, folk songs and marigold shade", mapsLink: "" },
    { id: "haldi", name: "Haldi Ceremony", date: "2026-12-13", time: "11:30 AM", venue: "Aangan Courtyard", desc: "Turmeric, laughter and blessings", mapsLink: "" },
    { id: "sangeet", name: "Sangeet", date: "2026-12-13", time: "7:30 PM", venue: "Moonlit Courtyard", desc: "An evening of music and dance", mapsLink: "" },
    { id: "shaadi", name: "Shaadi", date: "2026-12-14", time: "8:00 PM", venue: "Suvarna Mandap", desc: "The seven vows beneath the lamps", mapsLink: "" },
    { id: "reception", name: "Reception", date: "2026-12-15", time: "7:00 PM", venue: "Sheesh Mahal Lawn", desc: "Dinner, blessings and celebration", mapsLink: "" },
];
const HAVELI_DEFAULT_PHOTOS = [
    `${HAVELI_ASSET_ROOT}/demo-1.webp`,
    `${HAVELI_ASSET_ROOT}/demo-2.webp`,
    `${HAVELI_ASSET_ROOT}/demo-3.webp`,
    `${HAVELI_ASSET_ROOT}/demo-4.webp`,
];
const HAVELI_TABS = [
    { id: "sections", label: "Sections" },
    { id: "essentials", label: "Essentials" },
    { id: "invitation", label: "Invitation" },
    { id: "events", label: "Events" },
    { id: "story", label: "Story" },
    { id: "gallery", label: "Gallery" },
    { id: "rsvp", label: "RSVP" },
    { id: "music", label: "Music" },
];
function readHaveliConfig() { return readBuilderConfig(HAVELI_CONFIG_KEY); }
function writeHaveliConfig(config) { writeBuilderConfig(HAVELI_CONFIG_KEY, config); }
function haveliBaseDraft(seed = {}, options = {}) {
    const saved = options.source || (options.ignoreSaved ? null : readHaveliConfig());
    const s = saved || {};
    const couple = s.couple || {};
    const invite = s.invite || {};
    const story = s.story || {};
    const gallery = s.gallery || {};
    const rsvp = s.rsvp || {};
    const music = s.music || {};
    const closing = s.closing || {};
    return builderNewDraftMusic({
        ...cloneDraft(s),
        couple: {
            bride: couple.bride ?? seed.coupleA ?? "Aanya",
            groom: couple.groom ?? seed.coupleB ?? "Rohan",
            date: couple.date ?? "2026-12-14",
            venue: couple.venue ?? "Suvarna Haveli, Jaipur",
            whatsapp: couple.whatsapp ?? "",
            hashtag: couple.hashtag ?? "#AanyaWedsRohan",
        },
        invite: {
            show: invite.show !== false,
            blessing: invite.blessing ?? "With the blessings of our families and the light of a hundred diyas",
            brideFather: invite.brideFather ?? "Mr. Dev Malhotra",
            brideMother: invite.brideMother ?? "Mrs. Naina Malhotra",
            groomFather: invite.groomFather ?? "Mr. Vikram Mehta",
            groomMother: invite.groomMother ?? "Mrs. Leela Mehta",
        },
        events: Array.isArray(s.events) ? s.events : HAVELI_DEFAULT_EVENTS,
        story: {
            show: story.show !== false,
            text: story.text ?? "They met on a winter evening much like this one — somewhere between a borrowed umbrella and a shared cup of chai. A hundred small moments later, under these very lamps, they found the one story they wanted to keep telling forever.",
            tags: Array.isArray(story.tags) ? story.tags : ["chai at sunrise", "old city walks", "a borrowed umbrella"],
        },
        gallery: {
            show: gallery.show !== false,
            photos: Array.isArray(gallery.photos) ? gallery.photos : HAVELI_DEFAULT_PHOTOS,
        },
        rsvp: {
            show: rsvp.show !== false,
            heading: rsvp.heading ?? "Come light a diya with us",
            subtext: rsvp.subtext ?? "We have kept a place for you beside the lamps and the music. Tell us you are coming — the haveli is waiting.",
            btnText: rsvp.btnText ?? "Yes, I will be there",
            whatsapp: rsvp.whatsapp ?? couple.whatsapp ?? "",
            form_url: rsvp.form_url ?? "",
            mode: rsvp.mode ?? "whatsapp",
        },
        music: builderMusicConfig(music, { enabled: true, src: `${HAVELI_ASSET_ROOT}/music.mp3`, name: "Haveli Raag" }),
        closing: {
            show: closing.show !== false,
            line: closing.line ?? "May every lamp we light find its way to you.",
        },
    }, saved);
}
function buildHaveliConfig(draft) {
    const config = cloneDraft(draft);
    config.events = Array.isArray(config.events)
        ? config.events.filter((event) => event.name || event.date || event.time || event.venue)
        : [];
    config.gallery.photos = (config.gallery.photos || []).filter(Boolean);
    config.calendarUrls = buildCalendarUrls(config.couple);
    return config;
}
function HaveliDuskBuilder({ goTo, t, template, user, openSignIn, projectId, verifiedProject, verifiedOwnerId, recoveredDraft }) {
    const api = useBuilderApi();
    const activeTemplate = template || TemplateCatalog.get("haveli-dusk");
    const [draft, setDraft] = React.useState(() => haveliBaseDraft(t));
    const [activeProjectId, setActiveProjectId] = React.useState(projectId || null);
    const [tab, setTab] = React.useState("essentials");
    const [previewVersion, setPreviewVersion] = React.useState(1);
    const [savedAt, setSavedAt] = React.useState("");
    const [isPreviewMode, setIsPreviewMode] = React.useState(false);
    const [shareSlug, setShareSlug] = React.useState(null);
    const [publishing, setPublishing] = React.useState(false);
    const [publishAfterAuth, setPublishAfterAuth] = React.useState(false);
    const [savingDraft, setSavingDraft] = React.useState(false);
    const [musicUploading, setMusicUploading] = React.useState(false);
    const photoUploads = useBuilderPhotoUploads({ templateId: 'haveli-dusk', projectId: activeProjectId || projectId, user });
    const mediaUploading = musicUploading || photoUploads.busy;
    const [saveAfterAuth, setSaveAfterAuth] = React.useState(false);
    const [draftMsg, setDraftMsg] = React.useState("");
    const skipNextAutosaveRef = React.useRef(true);
    const projectLoadPendingRef = React.useRef(false);
    const previewSessionRef = React.useRef(`haveli-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`);
    const { enterPreview, returnToEditor } = useBuilderPreviewNavigation(isPreviewMode, setIsPreviewMode);
    const config = React.useMemo(() => buildHaveliConfig(draft), [draft]);
    const builderTemplatePath = activeTemplate?.builderTemplatePath || HAVELI_BUILDER_TEMPLATE_PATH;
    const builderTemplateUrl = resolveWeddingAssetUrl(builderTemplatePath);
    const previewSrc = buildBuilderPreviewSrc(builderTemplateUrl, "haveli-dusk", previewVersion, previewSessionRef.current);
    useBuilderPreviewPolish([previewSrc, isPreviewMode]);
    useLoadedProjectConfig({
        verifiedProject, verifiedOwnerId, recoveredDraft,
        projectId,
        templateId: "haveli-dusk",
        user,
        setActiveProjectId,
        setDraft,
        makeDraft: (source) => haveliBaseDraft(t, { source }),
        writeConfig: writeHaveliConfig,
        setPreviewVersion,
        setSavedAt,
        onConfigLoaded: () => { skipNextAutosaveRef.current = true; },
        loadPendingRef: projectLoadPendingRef,
    });
    useBuilderAutosave({
        uploading: mediaUploading, photoUploads,
        user,
        config,
        activeProjectId,
        templateId: "haveli-dusk",
        writeConfig: writeHaveliConfig,
        setPreviewVersion,
        setSavedAt,
        skipNextRef: skipNextAutosaveRef,
        loadPendingRef: projectLoadPendingRef,
    });
    const update = (path, value) => setDraft((current) => setDeepDraft(current, path, value));
    const swapNames = () => {
        setDraft((current) => {
            const next = cloneDraft(current);
            const bride = next.couple.bride;
            next.couple.bride = next.couple.groom;
            next.couple.groom = bride;
            return next;
        });
    };
    const updateEvent = (index, key, value) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.events[index][key] = value;
            return next;
        });
    };
    const addEvent = () => {
        setDraft((current) => ({
            ...cloneDraft(current),
            events: [...current.events, { id: `event-${Date.now()}`, name: "New Ceremony", date: current.couple.date, time: "6:00 PM", venue: "", desc: "", mapsLink: "" }],
        }));
    };
    const removeEvent = (index) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.events.splice(index, 1);
            return next;
        });
    };
    const updatePhoto = (index, value) => {
        setDraft((current) => {
            const next = cloneDraft(current);
            next.gallery.photos[index] = value;
            return next;
        });
    };
    const saveNow = () => {
        writeHaveliConfig(config);
        setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
        setPreviewVersion((v) => v + 1);
    };
    const showRealtimePreview = (event) => { saveNow(); enterPreview(event); };
    const resetDemo = () => {
        if (photoUploads.pending())
            return;
        if (!window.confirm("Reset this design to its sample details? Your current changes will be replaced." + (activeProjectId ? " Your saved invitation will also update." : "")))
            return;
        try {
            window.localStorage.removeItem(builderDraftKey(HAVELI_CONFIG_KEY));
        }
        catch (_) { }
        setDraft(haveliBaseDraft(t, { ignoreSaved: true }));
        setTab("essentials");
        setIsPreviewMode(false);
        setPreviewVersion((v) => v + 1);
    };
    const persistDraft = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setSavingDraft(true);
        setDraftMsg("");
        const res = await runSaveDraft({ api, templateId: "haveli-dusk", config, writeConfig: writeHaveliConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setSavingDraft(false);
        if (res.ok) {
            setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
            setPreviewVersion((v) => v + 1);
            setDraftMsg(res.local ? "Draft saved on this device for this UI preview." : (api.isAdminEditor ? "Draft saved for the customer." : "Draft saved in your dashboard."));
        }
        else if (res.reason === "login") {
            setDraftMsg("Sign in to save this draft.");
        }
        else {
            setDraftMsg("Could not save draft: " + res.reason);
        }
    }, [config, activeProjectId, mediaUploading]);
    const handleSaveDraft = () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (window.EA_UI_PREVIEW === true) {
            persistDraft();
            return;
        }
        if (!api?.isLoggedIn()) {
            setSaveAfterAuth(true);
            setDraftMsg("Sign in to save this draft.");
            openSignIn ? openSignIn("builder") : alert("Please sign in to save your draft.");
            return;
        }
        persistDraft();
    };
    const publishNow = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setPublishing(true);
        const res = await runPublish({ api, templateId: "haveli-dusk", config, writeConfig: writeHaveliConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setPublishing(false);
        if (res.ok)
            setShareSlug(res.slug);
        else if (res.reason !== "login")
            alert("Could not publish: " + res.reason);
    }, [config, activeProjectId, mediaUploading]);
    React.useEffect(() => {
        if (!publishAfterAuth || !api?.isLoggedIn())
            return;
        setPublishAfterAuth(false);
        publishNow();
    }, [publishAfterAuth, user, publishNow]);
    React.useEffect(() => {
        if (!saveAfterAuth || !api?.isLoggedIn())
            return;
        setSaveAfterAuth(false);
        persistDraft();
    }, [saveAfterAuth, user, persistDraft]);
    const handlePublish = () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (!api?.isLoggedIn()) {
            setPublishAfterAuth(true);
            openSignIn ? openSignIn("builder") : alert("Please sign in to publish your invitation.");
            return;
        }
        publishNow();
    };
    return (React.createElement("div", { className: "saas-template-builder" },
        shareSlug && React.createElement(ShareModal, { slug: shareSlug, onClose: () => setShareSlug(null) }),
        React.createElement("aside", { className: "saas-builder-side" },
            React.createElement("div", { className: "saas-template-switch" },
                React.createElement("div", null,
                    React.createElement("span", null, "Template"),
                    React.createElement("strong", null, activeTemplate?.name || "Haveli at Dusk")),
                React.createElement("button", { type: "button", onClick: () => goTo("builder", { projectId: null }) }, api.isAdminEditor ? 'Administration' : 'Change design')),
            React.createElement("label", { className: "builder-section-picker" },
                React.createElement("span", null, "Editing section"),
                React.createElement("select", { disabled: photoUploads.busy, value: tab, onChange: (e) => setTab(e.target.value) }, HAVELI_TABS.map((item) => React.createElement("option", { key: item.id, value: item.id }, item.label)))),
            React.createElement("nav", { className: "saas-builder-tabs", "aria-label": "Builder sections" }, HAVELI_TABS.map((item) => (React.createElement("button", { key: item.id, disabled: photoUploads.busy, "aria-current": tab === item.id ? "step" : undefined, className: tab === item.id ? "active" : "", onClick: () => setTab(item.id) }, item.label)))),
            React.createElement("fieldset", { className: "saas-builder-form", disabled: mediaUploading || savingDraft || publishing, style: { border: 0, margin: 0, minWidth: 0 } },
                React.createElement(TemplateSectionsPanel, { sections: window.EverafterLegacyOptions.definitions("haveli-dusk", draft), value: draft.sections, onChange: sections => setDraft(current => window.EverafterLegacyOptions.prepare({ ...current, sections }, "haveli-dusk")) }),
                tab === "essentials" && (React.createElement(BuilderPanel, { icon: "o", title: "The Couple", hint: "Drives the intro gate, hero, invitation and calendar links." },
                    React.createElement(BuildField, { label: "Bride's name", value: draft.couple.bride, onChange: (v) => update(["couple", "bride"], v) }),
                    React.createElement(BuildField, { label: "Groom's name", value: draft.couple.groom, onChange: (v) => update(["couple", "groom"], v) }),
                    React.createElement("div", { className: "builder-inline-row" },
                        React.createElement("span", null,
                            "Name display order",
                            React.createElement("br", null),
                            React.createElement("strong", null,
                                draft.couple.bride,
                                " & ",
                                draft.couple.groom)),
                        React.createElement("button", { type: "button", onClick: swapNames }, "Switch")),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Wedding date", type: "date", value: draft.couple.date, onChange: (v) => update(["couple", "date"], v) }),
                        React.createElement(BuildField, { label: "Venue", value: draft.couple.venue, onChange: (v) => update(["couple", "venue"], v) })),
                    React.createElement(BuildField, { label: "WhatsApp number", value: draft.couple.whatsapp, onChange: (v) => update(["couple", "whatsapp"], v), placeholder: "+91 98765 43210" }),
                    React.createElement(BuildField, { label: "Wedding hashtag", value: draft.couple.hashtag, onChange: (v) => update(["couple", "hashtag"], v) }))),
                tab === "invitation" && (React.createElement(BuilderPanel, { icon: "m", title: "Invitation", hint: "The formal card on the moonlit balcony scene." },
                    React.createElement(BuildToggle, { label: "Show invitation section", checked: draft.invite.show, onChange: (v) => update(["invite", "show"], v) }),
                    React.createElement(BuildField, { label: "Opening blessing", value: draft.invite.blessing, onChange: (v) => update(["invite", "blessing"], v), multi: true, rows: 3 }),
                    React.createElement(BuildField, { label: "Bride's father", value: draft.invite.brideFather, onChange: (v) => update(["invite", "brideFather"], v) }),
                    React.createElement(BuildField, { label: "Bride's mother", value: draft.invite.brideMother, onChange: (v) => update(["invite", "brideMother"], v) }),
                    React.createElement(BuildField, { label: "Groom's father", value: draft.invite.groomFather, onChange: (v) => update(["invite", "groomFather"], v) }),
                    React.createElement(BuildField, { label: "Groom's mother", value: draft.invite.groomMother, onChange: (v) => update(["invite", "groomMother"], v) }))),
                tab === "events" && (React.createElement(BuilderPanel, { icon: "e", title: "Events", hint: "Each ceremony becomes a card in the courtyard timeline." },
                    draft.events.map((event, index) => (React.createElement("div", { className: "builder-repeat", key: event.id || index },
                        React.createElement("div", { className: "builder-repeat-head" },
                            React.createElement("strong", null, event.name || `Event ${index + 1}`),
                            React.createElement("button", { onClick: () => removeEvent(index), "aria-label": "Remove event" }, "Remove")),
                        React.createElement(BuildField, { label: "Event name", value: event.name, onChange: (v) => updateEvent(index, "name", v) }),
                        React.createElement("div", { className: "builder-two-col" },
                            React.createElement(BuildField, { label: "Date", type: "date", value: event.date, onChange: (v) => updateEvent(index, "date", v) }),
                            React.createElement(BuildField, { label: "Time", value: event.time, onChange: (v) => updateEvent(index, "time", v) })),
                        React.createElement(BuildField, { label: "Venue", value: event.venue, onChange: (v) => updateEvent(index, "venue", v) }),
                        React.createElement(BuildField, { label: "Description", value: event.desc, onChange: (v) => updateEvent(index, "desc", v), multi: true }),
                        React.createElement(BuildField, { label: "Map link", value: event.mapsLink, onChange: (v) => updateEvent(index, "mapsLink", v), placeholder: "https://maps.google.com/..." })))),
                    React.createElement("button", { className: "builder-add-btn", onClick: addEvent }, "Add ceremony"))),
                tab === "story" && (React.createElement(BuilderPanel, { icon: "s", title: "Story", hint: "The garden scene under the fairy-lit tree." },
                    React.createElement(BuildToggle, { label: "Show story section", checked: draft.story.show, onChange: (v) => update(["story", "show"], v) }),
                    React.createElement(BuildField, { label: "Your story", value: draft.story.text, onChange: (v) => update(["story", "text"], v), multi: true, rows: 6 }),
                    React.createElement(BuildField, { label: "Memory chips, comma separated", value: draft.story.tags.join(", "), onChange: (v) => update(["story", "tags"], v.split(",").map((x) => x.trim()).filter(Boolean)) }))),
                tab === "gallery" && (React.createElement(BuilderPanel, { icon: "g", title: "Gallery", hint: "Choose the photographs to hang in your haveli, or leave the gallery empty." },
                    React.createElement(BuildToggle, { label: "Show gallery", checked: draft.gallery.show, onChange: (v) => update(["gallery", "show"], v) }),
                    React.createElement(LegacyPhotoList, { photos: draft.gallery.photos, uploadScope: photoUploads, onChange: photos => update(["gallery", "photos"], photos) }))),
                tab === "rsvp" && (React.createElement(BuilderPanel, { icon: "r", title: "RSVP", hint: "The mandap scene with the golden reply button." },
                    React.createElement(BuildToggle, { label: "Show RSVP section", checked: draft.rsvp.show, onChange: (v) => update(["rsvp", "show"], v) }),
                    React.createElement(BuildSelect, { label: "RSVP mode", value: draft.rsvp.mode, onChange: (v) => update(["rsvp", "mode"], v), options: [["native", "Built-in guest RSVP"], ["whatsapp", "WhatsApp"], ["form", "External form"]] }),
                    React.createElement(BuildField, { label: "Heading", value: draft.rsvp.heading, onChange: (v) => update(["rsvp", "heading"], v) }),
                    React.createElement(BuildField, { label: "Subtext", value: draft.rsvp.subtext, onChange: (v) => update(["rsvp", "subtext"], v), multi: true, rows: 4 }),
                    React.createElement(BuildField, { label: "Button text", value: draft.rsvp.btnText, onChange: (v) => update(["rsvp", "btnText"], v) }),
                    draft.rsvp.mode === "form" ? (React.createElement(BuildField, { label: "Form URL", value: draft.rsvp.form_url, onChange: (v) => update(["rsvp", "form_url"], v) })) : draft.rsvp.mode === "whatsapp" ? (React.createElement(BuildField, { label: "WhatsApp number", value: draft.rsvp.whatsapp || draft.couple.whatsapp, onChange: (v) => update(["rsvp", "whatsapp"], v) })) : null,
                    React.createElement(BuildToggle, { label: "Show closing blessing", checked: draft.closing.show, onChange: (v) => update(["closing", "show"], v) }),
                    React.createElement(BuildField, { label: "Closing line", value: draft.closing.line, onChange: (v) => update(["closing", "line"], v) }))),
                React.createElement("div", { hidden: tab !== "music" },
                    React.createElement(BuilderPanel, { icon: "a", title: "Music" },
                        React.createElement(MusicUploadPanel, { value: draft.music, nativeMusic: haveliBaseDraft({}, { ignoreSaved: true }).music, templateId: "haveli-dusk", projectId: activeProjectId || projectId, scopeKey: projectId || 'new', user: user, disabled: savingDraft || publishing || photoUploads.busy, onChange: value => update(["music"], value), onBusyChange: setMusicUploading, openSignIn: openSignIn, active: tab === "music" })))),
            React.createElement(BuilderProgressActions, { tabs: HAVELI_TABS, tab: tab, onTabChange: setTab, onPreview: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading })),
        React.createElement("main", { className: "saas-builder-preview" },
            React.createElement("div", { className: "saas-builder-topbar" },
                React.createElement("div", { className: "builder-save-status" },
                    React.createElement("span", { className: "builder-status-dot" }),
                    React.createElement("span", null,
                        React.createElement("strong", null, activeProjectId ? "Your invitation" : "New design"),
                        React.createElement("small", { role: "status" }, draftMsg || builderSaveStatus(savedAt)))),
                window.EA_UI_PREVIEW === true && React.createElement(BuilderPreviewNotice, { compact: true }),
                React.createElement("div", { className: "saas-builder-actions" },
                    React.createElement("button", { type: "button", className: "mobile-edit-action", onClick: scrollBuilderEditorIntoView },
                        React.createElement(BuilderActionLabel, { full: "Edit details", compact: "Edit" })),
                    React.createElement("button", { type: "button", className: "desktop-reset-action", onClick: resetDemo, disabled: savingDraft || publishing || mediaUploading }, "Reset"),
                    React.createElement("button", { type: "button", onClick: handleSaveDraft, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: savingDraft ? "Saving..." : "Save draft", compact: savingDraft ? "Saving" : "Save" })),
                    React.createElement("button", { type: "button", className: "primary", onClick: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: "Preview so far", compact: "Preview so far" })),
                    React.createElement("button", { type: "button", className: "publish", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined },
                        React.createElement(BuilderActionLabel, { full: publishing ? "Publishing..." : "Publish invitation", compact: publishing ? "Publishing" : "Publish" })))),
            React.createElement("div", { className: "saas-preview-label" }, "Live preview"),
            React.createElement("div", { className: "saas-preview-workspace" }, !isPreviewMode && React.createElement(BuilderPhonePreview, { activeTemplate: activeTemplate, fallbackName: "Haveli at Dusk", previewSrc: previewSrc })),
            React.createElement("div", { className: "saas-publish-bar" },
                React.createElement("div", { className: "saas-publish-template" },
                    React.createElement("span", { className: "saas-publish-thumb" }),
                    React.createElement("div", null,
                        React.createElement("strong", null, activeTemplate?.name || "Haveli at Dusk"),
                        React.createElement("span", null, "Cinematic scenes \u00B7 Mobile optimised \u00B7 WhatsApp sharing"))),
                React.createElement("button", { type: "button", className: "saas-publish-btn", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined }, publishing ? "Publishing…" : "Publish invitation"))),
        React.createElement(BuilderPreviewWindow, { open: isPreviewMode, onClose: returnToEditor, activeTemplate: activeTemplate, fallbackName: "Haveli at Dusk", previewSrc: previewSrc })));
}
const DEARYOU_CONFIG_KEY = "everafter-dear-you-config";
const DEARYOU_BUILDER_TEMPLATE_PATH = TemplateCatalog.get("dear-you").builderTemplatePath;
const DEARYOU_DEFAULT_MEMORIES = [
    { src: "assets/memories/01-chai.jpg", caption: "Our first chai.", note: "You burnt the milk. I lied and said it was perfect. I would lie again." },
    { src: "assets/memories/02-her.jpg", caption: "You, that morning.", note: "The portrait you hated. I framed it anyway. It's on the wall behind me right now." },
    { src: "assets/memories/03-us.jpg", caption: "An hour after the worst fight of the year.", note: "Look at us. We had no idea we were already winning." },
    { src: "assets/memories/04-trip.jpg", caption: "Lake of lights.", note: "You said it looked like fireflies got rich." },
    { src: "assets/memories/05-mehendi.jpg", caption: "Henna fading. The morning after.", note: "I read every line on your hands like a map. I keep finding new roads." },
    { src: "assets/memories/06-laugh.jpg", caption: "You laughing at me. Again.", note: "I would say something stupid every day for the rest of my life if it kept that face on yours." },
    { src: "assets/memories/07-home.jpg", caption: "Home, before we knew it was home.", note: "We argued for an hour about which window seat to take." },
    { src: "assets/memories/08-rings.jpg", caption: "Two thin gold things.", note: "I haven't forgotten about these. They're in the second drawer. Waiting." },
];
const DEARYOU_DEFAULT_POLAROIDS = [
    { title: "The dosa fight", front: "Saturday · Anjappar.", back: "You were right. It's better warm. I'm saying it. Out loud." },
    { title: "17 unsent voice notes", front: "2 a.m. · Drafts folder.", back: "Each one is just me, getting it wrong, deleting, starting over." },
    { title: "The umbrella", front: "Monsoon · 5 (or 6) of them.", back: "Maybe it was always trying to leave us. Maybe we kept it together anyway." },
    { title: "Your laugh", front: "Before the joke ends.", back: "Always before the joke ends. It's the loudest sound in any room." },
    { title: "The minute", front: "Every minute, eventually.", back: "When I say I need a minute, you wait. You always wait. Even now, I think." },
    { title: "Tuesday, 9:14 PM", front: "The kitchen.", back: "I will not forget how I sounded. I am sorry I sounded like that." },
];
const DEARYOU_TABS = [
    { id: "sections", label: "Sections" },
    { id: "essentials", label: "Essentials" },
    { id: "letter", label: "Letter" },
    { id: "memories", label: "Memories" },
    { id: "polaroids", label: "Polaroids" },
    { id: "scratch", label: "Scratch" },
    { id: "doors", label: "Doors" },
    { id: "music", label: "Music" },
];
function readDearYouConfig() { return readBuilderConfig(DEARYOU_CONFIG_KEY); }
function writeDearYouConfig(config) { writeBuilderConfig(DEARYOU_CONFIG_KEY, config); }
function dearYouBaseDraft(seed = {}, options = {}) {
    const saved = options.source || (options.ignoreSaved ? null : readDearYouConfig());
    const s = saved || {};
    const letter = s.letter || {};
    const stats = s.stats || {};
    const contact = s.contact || {};
    const scratch = s.scratch || {};
    return builderNewDraftMusic({
        ...cloneDraft(s),
        from: s.from ?? seed.coupleB ?? "Rohan",
        to: s.to ?? seed.coupleA ?? "Aanya",
        stats: {
            daysTogether: stats.daysTogether != null ? stats.daysTogether : 247,
            daysApart: stats.daysApart != null ? stats.daysApart : 3,
            lastSeen: stats.lastSeen ?? "Tuesday, the kitchen, around 9:14 PM",
        },
        letter: {
            opening: letter.opening ?? "I've been writing this letter for three days.",
            tearLine: letter.tearLine ?? "I'm sorry.",
            reconcile: Array.isArray(letter.reconcile) && letter.reconcile.length === 3 ? letter.reconcile : [
                "I have replayed Tuesday a hundred times.",
                "I was wrong. Not about everything. But about the thing.",
                "I miss you in a way I cannot put down on paper, which is annoying, because I have been trying for three days.",
            ],
            closing: letter.closing ?? "Pick any one. I'm here either way.",
            signoff: letter.signoff ?? "still yours,",
            ps: letter.ps ?? "P.S. — the leftovers are still in the fridge. Untouched. Waiting.",
        },
        memories: Array.isArray(s.memories) ? s.memories : DEARYOU_DEFAULT_MEMORIES,
        polaroids: Array.isArray(s.polaroids) ? s.polaroids : DEARYOU_DEFAULT_POLAROIDS,
        scratch: {
            kicker: scratch.kicker ?? "Use your finger.",
            headline: scratch.headline ?? "Scratch the gold.",
            hidden: scratch.hidden ?? "I love you.",
            subhidden: scratch.subhidden ?? "I always have. Even on Tuesday.",
        },
        contact: {
            whatsapp: contact.whatsapp ?? "919999999999",
            phone: contact.phone ?? "919999999999",
            location: contact.location ?? "I'm at the kitchen table. The light is still on.",
        },
    }, saved);
}
function buildDearYouConfig(draft) {
    return cloneDraft(draft);
}
function DearYouBuilder({ goTo, t, template, user, openSignIn, projectId, verifiedProject, verifiedOwnerId, recoveredDraft }) {
    const api = useBuilderApi();
    const activeTemplate = template || TemplateCatalog.get("dear-you");
    const [draft, setDraft] = React.useState(() => dearYouBaseDraft(t));
    const [activeProjectId, setActiveProjectId] = React.useState(projectId || null);
    const [tab, setTab] = React.useState("essentials");
    const [previewVersion, setPreviewVersion] = React.useState(1);
    const [savedAt, setSavedAt] = React.useState("");
    const [isPreviewMode, setIsPreviewMode] = React.useState(false);
    const [shareSlug, setShareSlug] = React.useState(null);
    const [publishing, setPublishing] = React.useState(false);
    const [publishAfterAuth, setPublishAfterAuth] = React.useState(false);
    const [savingDraft, setSavingDraft] = React.useState(false);
    const [musicUploading, setMusicUploading] = React.useState(false);
    const photoUploads = useBuilderPhotoUploads({ templateId: 'dear-you', projectId: activeProjectId || projectId, user });
    const mediaUploading = musicUploading || photoUploads.busy;
    const [saveAfterAuth, setSaveAfterAuth] = React.useState(false);
    const [draftMsg, setDraftMsg] = React.useState("");
    const skipNextAutosaveRef = React.useRef(true);
    const projectLoadPendingRef = React.useRef(false);
    const previewSessionRef = React.useRef(`dear-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`);
    const { enterPreview, returnToEditor } = useBuilderPreviewNavigation(isPreviewMode, setIsPreviewMode);
    const config = React.useMemo(() => buildDearYouConfig(draft), [draft]);
    const builderTemplatePath = activeTemplate?.builderTemplatePath || DEARYOU_BUILDER_TEMPLATE_PATH;
    const builderTemplateUrl = resolveWeddingAssetUrl(builderTemplatePath);
    const previewSrc = buildBuilderPreviewSrc(builderTemplateUrl, "dear-you", previewVersion, previewSessionRef.current);
    useBuilderPreviewPolish([previewSrc, isPreviewMode]);
    useLoadedProjectConfig({
        verifiedProject, verifiedOwnerId, recoveredDraft,
        projectId,
        templateId: "dear-you",
        user,
        setActiveProjectId,
        setDraft,
        makeDraft: (source) => dearYouBaseDraft(t, { source }),
        writeConfig: writeDearYouConfig,
        setPreviewVersion,
        setSavedAt,
        onConfigLoaded: () => { skipNextAutosaveRef.current = true; },
        loadPendingRef: projectLoadPendingRef,
    });
    useBuilderAutosave({
        uploading: mediaUploading, photoUploads,
        user,
        config,
        activeProjectId,
        templateId: "dear-you",
        writeConfig: writeDearYouConfig,
        setPreviewVersion,
        setSavedAt,
        skipNextRef: skipNextAutosaveRef,
        loadPendingRef: projectLoadPendingRef,
    });
    const update = (path, value) => setDraft((current) => {
        const next = cloneDraft(current);
        let cur = next;
        for (let i = 0; i < path.length - 1; i++)
            cur = cur[path[i]];
        cur[path[path.length - 1]] = value;
        return next;
    });
    const updateMemory = (i, k, v) => setDraft((c) => { const n = cloneDraft(c); n.memories[i] = { ...n.memories[i], [k]: v }; return n; });
    const updatePolaroid = (i, k, v) => setDraft((c) => { const n = cloneDraft(c); n.polaroids[i] = { ...n.polaroids[i], [k]: v }; return n; });
    const updateReconcile = (i, v) => setDraft((c) => { const n = cloneDraft(c); n.letter.reconcile[i] = v; return n; });
    const saveNow = () => {
        writeDearYouConfig(config);
        setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
        setPreviewVersion((v) => v + 1);
    };
    const showRealtimePreview = (event) => { saveNow(); enterPreview(event); };
    const resetDemo = () => {
        if (photoUploads.pending())
            return;
        if (!window.confirm("Reset this design to its sample details? Your current changes will be replaced." + (activeProjectId ? " Your saved invitation will also update." : "")))
            return;
        try {
            window.localStorage.removeItem(builderDraftKey(DEARYOU_CONFIG_KEY));
        }
        catch (_) { }
        setDraft(dearYouBaseDraft(t, { ignoreSaved: true }));
        setTab("essentials");
        setIsPreviewMode(false);
        setPreviewVersion((v) => v + 1);
    };
    const persistDraft = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setSavingDraft(true);
        setDraftMsg("");
        const res = await runSaveDraft({ api, templateId: "dear-you", config, writeConfig: writeDearYouConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setSavingDraft(false);
        if (res.ok) {
            setSavedAt(new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" }));
            setPreviewVersion((v) => v + 1);
            setDraftMsg(res.local ? "Draft saved on this device for this UI preview." : (api.isAdminEditor ? "Draft saved for the customer." : "Draft saved in your dashboard."));
        }
        else if (res.reason === "login") {
            setDraftMsg("Sign in to save this draft.");
        }
        else {
            setDraftMsg("Could not save draft: " + res.reason);
        }
    }, [config, activeProjectId, mediaUploading]);
    const handleSaveDraft = () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (window.EA_UI_PREVIEW === true) {
            persistDraft();
            return;
        }
        if (!api?.isLoggedIn()) {
            setSaveAfterAuth(true);
            setDraftMsg("Sign in to save this draft.");
            openSignIn ? openSignIn("builder") : alert("Please sign in to save your draft.");
            return;
        }
        persistDraft();
    };
    const publishNow = React.useCallback(async () => {
        if (mediaUploading || photoUploads.pending())
            return;
        setPublishing(true);
        const res = await runPublish({ api, templateId: "dear-you", config, writeConfig: writeDearYouConfig, projectId: activeProjectId, setProjectId: setActiveProjectId });
        setPublishing(false);
        if (res.ok)
            setShareSlug(res.slug);
        else if (res.reason !== "login")
            alert("Could not publish: " + res.reason);
    }, [config, activeProjectId, mediaUploading]);
    React.useEffect(() => {
        if (!publishAfterAuth || !api?.isLoggedIn())
            return;
        setPublishAfterAuth(false);
        publishNow();
    }, [publishAfterAuth, user, publishNow]);
    React.useEffect(() => {
        if (!saveAfterAuth || !api?.isLoggedIn())
            return;
        setSaveAfterAuth(false);
        persistDraft();
    }, [saveAfterAuth, user, persistDraft]);
    const handlePublish = () => {
        if (mediaUploading || photoUploads.pending())
            return;
        if (!api?.isLoggedIn()) {
            setPublishAfterAuth(true);
            openSignIn ? openSignIn("builder") : alert("Please sign in to publish your invitation.");
            return;
        }
        publishNow();
    };
    return (React.createElement("div", { className: "saas-template-builder" },
        shareSlug && React.createElement(ShareModal, { slug: shareSlug, onClose: () => setShareSlug(null) }),
        React.createElement("aside", { className: "saas-builder-side" },
            React.createElement("div", { className: "saas-template-switch" },
                React.createElement("div", null,
                    React.createElement("span", null, "Template"),
                    React.createElement("strong", null, activeTemplate?.name || "Dear You")),
                React.createElement("button", { type: "button", onClick: () => goTo("builder", { projectId: null }) }, api.isAdminEditor ? 'Administration' : 'Change design')),
            React.createElement("label", { className: "builder-section-picker" },
                React.createElement("span", null, "Editing section"),
                React.createElement("select", { disabled: photoUploads.busy, value: tab, onChange: (e) => setTab(e.target.value) }, DEARYOU_TABS.map((item) => React.createElement("option", { key: item.id, value: item.id }, item.label)))),
            React.createElement("nav", { className: "saas-builder-tabs", "aria-label": "Builder sections" }, DEARYOU_TABS.map((item) => (React.createElement("button", { key: item.id, disabled: photoUploads.busy, "aria-current": tab === item.id ? "step" : undefined, className: tab === item.id ? "active" : "", onClick: () => setTab(item.id) }, item.label)))),
            React.createElement("fieldset", { className: "saas-builder-form", disabled: mediaUploading || savingDraft || publishing, style: { border: 0, margin: 0, minWidth: 0 } },
                React.createElement(TemplateSectionsPanel, { sections: window.EverafterLegacyOptions.definitions("dear-you", draft), value: draft.sections, onChange: sections => setDraft(current => window.EverafterLegacyOptions.prepare({ ...current, sections }, "dear-you")) }),
                tab === "essentials" && (React.createElement(BuilderPanel, { icon: "o", title: "The Couple", hint: "From / To names, the day count, and the moment of the last fight." },
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Your name (the apologizer)", value: draft.from, onChange: (v) => update(["from"], v) }),
                        React.createElement(BuildField, { label: "Their name (the one you miss)", value: draft.to, onChange: (v) => update(["to"], v) })),
                    React.createElement("div", { className: "builder-two-col" },
                        React.createElement(BuildField, { label: "Days together", type: "number", value: draft.stats.daysTogether, onChange: (v) => update(["stats", "daysTogether"], parseInt(v, 10) || 0) }),
                        React.createElement(BuildField, { label: "Days apart", type: "number", value: draft.stats.daysApart, onChange: (v) => update(["stats", "daysApart"], parseInt(v, 10) || 0) })),
                    React.createElement(BuildField, { label: "Last seen", value: draft.stats.lastSeen, onChange: (v) => update(["stats", "lastSeen"], v), placeholder: "Tuesday, the kitchen, around 9:14 PM" }))),
                tab === "letter" && (React.createElement(BuilderPanel, { icon: "l", title: "The Letter", hint: "Opening line, reconciliation paragraph, signoff. The cinematic spine of the page." },
                    React.createElement(BuildField, { label: "Opening line", value: draft.letter.opening, onChange: (v) => update(["letter", "opening"], v), multi: true, rows: 2 }),
                    React.createElement(BuildField, { label: "Tear line (the apology)", value: draft.letter.tearLine, onChange: (v) => update(["letter", "tearLine"], v), placeholder: "I'm sorry." }),
                    React.createElement(BuildField, { label: "Reconcile \u00B7 line 1 (quiet)", value: draft.letter.reconcile[0], onChange: (v) => updateReconcile(0, v), multi: true, rows: 2 }),
                    React.createElement(BuildField, { label: "Reconcile \u00B7 line 2 (honest)", value: draft.letter.reconcile[1], onChange: (v) => updateReconcile(1, v), multi: true, rows: 2 }),
                    React.createElement(BuildField, { label: "Reconcile \u00B7 line 3 (longing)", value: draft.letter.reconcile[2], onChange: (v) => updateReconcile(2, v), multi: true, rows: 3 }),
                    React.createElement(BuildField, { label: "Closing", value: draft.letter.closing, onChange: (v) => update(["letter", "closing"], v), multi: true, rows: 2 }),
                    React.createElement(BuildField, { label: "Signoff", value: draft.letter.signoff, onChange: (v) => update(["letter", "signoff"], v), placeholder: "still yours," }),
                    React.createElement(BuildField, { label: "P.S. (one funny + soft line)", value: draft.letter.ps, onChange: (v) => update(["letter", "ps"], v), multi: true, rows: 2 }))),
                tab === "memories" && (React.createElement(BuilderPanel, { icon: "m", title: "The Photo Ladder", hint: "Add any photographs you want to share, or leave this section empty." }, draft.memories.map((m, i) => (React.createElement(BuilderPhotoDisclosure, { key: i, label: `Photograph ${i + 1}`, value: m.src, caption: m.caption },
                    React.createElement("div", { className: "builder-repeat-head" },
                        React.createElement("button", { type: "button", onClick: () => { if (!photoUploads.pending())
                                update(["memories"], draft.memories.filter((_, index) => index !== i)); } }, "Remove photograph")),
                    React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Photo", value: m.src, onChange: (v) => updateMemory(i, "src", v), placeholder: "assets/memories/01-chai.jpg" }),
                    React.createElement(BuildField, { label: "Caption (handwritten)", value: m.caption, onChange: (v) => updateMemory(i, "caption", v) }),
                    React.createElement(BuildField, { label: "Note (the longer line)", value: m.note, onChange: (v) => updateMemory(i, "note", v), multi: true, rows: 2 })))))),
                tab === "memories" && draft.memories.length < 20 && React.createElement("button", { type: "button", className: "builder-add-btn", onClick: () => update(["memories"], [...draft.memories, { src: "", caption: "", note: "" }]) }, "Add photograph"),
                tab === "polaroids" && (React.createElement(BuilderPanel, { icon: "p", title: "Polaroid Wall", hint: "Choose how many memory cards to include. Each can have an optional photograph." }, draft.polaroids.map((p, i) => (React.createElement(BuilderPhotoDisclosure, { key: i, label: `Memory card ${i + 1}`, value: p.src || "", caption: p.title, populated: Boolean(p.src || p.title || p.front || p.back), emptyLabel: "Add a memory; photo optional" },
                    React.createElement("div", { className: "builder-repeat-head" },
                        React.createElement("button", { type: "button", onClick: () => { if (!photoUploads.pending())
                                update(["polaroids"], draft.polaroids.filter((_, index) => index !== i)); } }, "Remove memory card")),
                    React.createElement(BuildPhotoField, { uploadScope: photoUploads, label: "Memory card photograph (optional)", value: p.src || "", onChange: value => updatePolaroid(i, "src", value) }),
                    React.createElement(BuildField, { label: "Title", value: p.title, onChange: (v) => updatePolaroid(i, "title", v) }),
                    React.createElement(BuildField, { label: "Front \u00B7 date or location", value: p.front, onChange: (v) => updatePolaroid(i, "front", v) }),
                    React.createElement(BuildField, { label: "Back \u00B7 the memory", value: p.back, onChange: (v) => updatePolaroid(i, "back", v), multi: true, rows: 3 })))))),
                tab === "polaroids" && draft.polaroids.length < 20 && React.createElement("button", { type: "button", className: "builder-add-btn", onClick: () => update(["polaroids"], [...draft.polaroids, { src: "", title: "", front: "", back: "" }]) }, "Add memory card"),
                tab === "scratch" && (React.createElement(BuilderPanel, { icon: "s", title: "Scratch to Reveal", hint: "The interactive gold-foil card. She drags her finger \u2014 your hidden message appears." },
                    React.createElement(BuildField, { label: "Kicker (instruction)", value: draft.scratch.kicker, onChange: (v) => update(["scratch", "kicker"], v), placeholder: "Use your finger." }),
                    React.createElement(BuildField, { label: "Headline", value: draft.scratch.headline, onChange: (v) => update(["scratch", "headline"], v), placeholder: "Scratch the gold." }),
                    React.createElement(BuildField, { label: "Hidden message (big)", value: draft.scratch.hidden, onChange: (v) => update(["scratch", "hidden"], v), placeholder: "I love you." }),
                    React.createElement(BuildField, { label: "Hidden subtitle", value: draft.scratch.subhidden, onChange: (v) => update(["scratch", "subhidden"], v), multi: true, rows: 2 }))),
                tab === "doors" && (React.createElement(BuilderPanel, { icon: "d", title: "The Three Doors", hint: "The three exits she can pick. WhatsApp, phone, and the location for \"I'm coming over\"." },
                    React.createElement(BuildField, { label: "WhatsApp number (digits only)", value: draft.contact.whatsapp, onChange: (v) => update(["contact", "whatsapp"], v), placeholder: "919999999999" }),
                    React.createElement(BuildField, { label: "Phone (for tel: link)", value: draft.contact.phone, onChange: (v) => update(["contact", "phone"], v), placeholder: "919999999999" }),
                    React.createElement(BuildField, { label: "Door 3 location line", value: draft.contact.location, onChange: (v) => update(["contact", "location"], v), multi: true, rows: 2, placeholder: "I'm at the kitchen table." }))),
                React.createElement("div", { hidden: tab !== "music" },
                    React.createElement(BuilderPanel, { icon: "a", title: "Music" },
                        React.createElement(MusicUploadPanel, { value: draft.music, nativeMusic: undefined, templateId: "dear-you", projectId: activeProjectId || projectId, scopeKey: projectId || 'new', user: user, disabled: savingDraft || publishing || photoUploads.busy, onChange: value => update(["music"], value), onBusyChange: setMusicUploading, openSignIn: openSignIn, active: tab === "music" })))),
            React.createElement(BuilderProgressActions, { tabs: DEARYOU_TABS, tab: tab, onTabChange: setTab, onPreview: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading })),
        React.createElement("main", { className: "saas-builder-preview" },
            React.createElement("div", { className: "saas-builder-topbar" },
                React.createElement("div", { className: "builder-save-status" },
                    React.createElement("span", { className: "builder-status-dot" }),
                    React.createElement("span", null,
                        React.createElement("strong", null, activeProjectId ? "Your invitation" : "New design"),
                        React.createElement("small", { role: "status" }, draftMsg || builderSaveStatus(savedAt)))),
                window.EA_UI_PREVIEW === true && React.createElement(BuilderPreviewNotice, { compact: true }),
                React.createElement("div", { className: "saas-builder-actions" },
                    React.createElement("button", { type: "button", className: "mobile-edit-action", onClick: scrollBuilderEditorIntoView },
                        React.createElement(BuilderActionLabel, { full: "Edit details", compact: "Edit" })),
                    React.createElement("button", { type: "button", className: "desktop-reset-action", onClick: resetDemo, disabled: savingDraft || publishing || mediaUploading }, "Reset"),
                    React.createElement("button", { type: "button", onClick: handleSaveDraft, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: savingDraft ? "Saving..." : "Save draft", compact: savingDraft ? "Saving" : "Save" })),
                    React.createElement("button", { type: "button", className: "primary", onClick: showRealtimePreview, disabled: savingDraft || publishing || mediaUploading },
                        React.createElement(BuilderActionLabel, { full: "Preview so far", compact: "Preview so far" })),
                    React.createElement("button", { type: "button", className: "publish", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined },
                        React.createElement(BuilderActionLabel, { full: publishing ? "Publishing..." : "Publish invitation", compact: publishing ? "Publishing" : "Publish" })))),
            React.createElement("div", { className: "saas-preview-label" }, "Live preview"),
            React.createElement("div", { className: "saas-preview-workspace" }, !isPreviewMode && React.createElement(BuilderPhonePreview, { activeTemplate: activeTemplate, fallbackName: "Dear You", previewSrc: previewSrc })),
            React.createElement("div", { className: "saas-publish-bar" },
                React.createElement("div", { className: "saas-publish-template" },
                    React.createElement("span", { className: "saas-publish-thumb" }),
                    React.createElement("div", null,
                        React.createElement("strong", null, activeTemplate?.name || "Dear You"),
                        React.createElement("span", null, "Cinematic scroll \u00B7 Mobile optimised \u00B7 WhatsApp sharing"))),
                React.createElement("button", { type: "button", className: "saas-publish-btn", onClick: handlePublish, disabled: publishing || savingDraft || mediaUploading || window.EA_UI_PREVIEW === true, title: window.EA_UI_PREVIEW === true ? "Publishing is unavailable in this UI preview." : undefined }, publishing ? "Publishing…" : "Publish invitation"))),
        React.createElement(BuilderPreviewWindow, { open: isPreviewMode, onClose: returnToEditor, activeTemplate: activeTemplate, fallbackName: "Dear You", previewSrc: previewSrc })));
}
Object.assign(window, { DearYouBuilder, HaveliDuskBuilder, ShareModal });
function LegacyPhotoList({ photos = [], uploadScope, onChange }) {
    return React.createElement("div", null,
        photos.map((photo, index) => {
            const value = typeof photo === "string" ? photo : photo?.src || "";
            return React.createElement(BuilderPhotoDisclosure, { key: index, label: `Photograph ${index + 1}`, value: value, caption: typeof photo === "object" ? photo?.caption : "" },
                React.createElement(BuildPhotoField, { uploadScope: uploadScope, label: `Photograph ${index + 1}`, value: value, onChange: value => onChange(photos.map((item, i) => i === index ? (typeof item === "object" && item ? { ...item, src: value } : value) : item)) }),
                React.createElement("button", { type: "button", onClick: () => { if (!uploadScope?.pending())
                        onChange(photos.filter((_, i) => i !== index)); } }, "Remove photograph"));
        }),
        photos.length < 20 && React.createElement("button", { type: "button", className: "builder-add-btn", onClick: () => { if (!uploadScope?.pending())
                onChange([...photos, ""]); } }, "Add photograph"),
        !photos.length && React.createElement("p", null, "No photographs selected. Add one if you want to include this gallery."));
}
