{"title":"Lithophanes","description":"","products":[{"product_id":"four-image-lithophane-box","title":"Four Image Lithophane box","description":"\u003cdiv id=\"litho-container\" style=\"font-family: sans-serif; margin-bottom: 30px; border: 1px solid #ddd; border-radius: 8px; overflow: hidden;\"\u003e\n  \n  \u003cdiv style=\"background: #222; color: #fff; padding: 10px; font-weight: bold; text-align: center; letter-spacing: 1px;\"\u003e\n    CUSTOMIZE YOUR LIGHT BOX\n  \u003c\/div\u003e\n\n  \u003cdiv style=\"background: #f8f8f8; color: #333; padding: 25px;\"\u003e\n    \u003cp style=\"text-align: center; font-size: 14px; margin-bottom: 20px; color: #555;\"\u003e\n      \u003cb\u003eRequirement:\u003c\/b\u003e Please upload a separate photo for each of the 4 sides.\n    \u003c\/p\u003e\n\n    \u003cdiv style=\"display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-bottom: 20px;\"\u003e\n        \u003cbutton type=\"button\" id=\"btn-side-1\" onclick=\"triggerUpload(0)\" style=\"padding: 20px; cursor: pointer; border: 2px dashed #999; background: #fff; border-radius: 4px; font-weight: bold; color: #444; transition: 0.2s;\"\u003e📷 SIDE 1 (Front)\u003c\/button\u003e\n        \u003cbutton type=\"button\" id=\"btn-side-2\" onclick=\"triggerUpload(1)\" style=\"padding: 20px; cursor: pointer; border: 2px dashed #999; background: #fff; border-radius: 4px; font-weight: bold; color: #444; transition: 0.2s;\"\u003e📷 SIDE 2 (Right)\u003c\/button\u003e\n        \u003cbutton type=\"button\" id=\"btn-side-3\" onclick=\"triggerUpload(2)\" style=\"padding: 20px; cursor: pointer; border: 2px dashed #999; background: #fff; border-radius: 4px; font-weight: bold; color: #444; transition: 0.2s;\"\u003e📷 SIDE 3 (Back)\u003c\/button\u003e\n        \u003cbutton type=\"button\" id=\"btn-side-4\" onclick=\"triggerUpload(3)\" style=\"padding: 20px; cursor: pointer; border: 2px dashed #999; background: #fff; border-radius: 4px; font-weight: bold; color: #444; transition: 0.2s;\"\u003e📷 SIDE 4 (Left)\u003c\/button\u003e\n    \u003c\/div\u003e\n\n    \u003cdiv id=\"upload-warning\" style=\"text-align: center; color: #d32f2f; font-size: 13px; font-weight: bold; background: #ffebee; padding: 10px; border-radius: 4px;\"\u003e\n      * You must upload 4 photos to add to cart.\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cscript\u003e\n    const inputNames = [\"properties[Side 1 - Front]\", \"properties[Side 2 - Right]\", \"properties[Side 3 - Back]\", \"properties[Side 4 - Left]\"];\n    window.generatedInputs = [];\n    inputNames.forEach((name, i) =\u003e {\n        const inp = document.createElement('input');\n        inp.type = 'file'; inp.id = 'input-' + i; inp.name = name; inp.accept = 'image\/*'; inp.style.display = 'none';\n        document.body.appendChild(inp); \n        window.generatedInputs.push(inp);\n    });\n\u003c\/script\u003e\n\n\u003cscript\u003e\n\/\/ VARIABLES\nwindow.DETECTED_VARIANT_ID = null; \/\/ We will fill this automatically\nconst btns = [document.getElementById('btn-side-1'), document.getElementById('btn-side-2'), document.getElementById('btn-side-3'), document.getElementById('btn-side-4')];\nconst warning = document.getElementById('upload-warning');\n\n\/\/ --- 1. THE AUTO-FETCHER ---\n\/\/ Immediately ask Shopify: \"What is the ID of this product?\"\n(async function() {\n    try {\n        \/\/ Get the current URL JSON\n        const response = await fetch(window.location.pathname + '.js');\n        const productData = await response.json();\n        \n        \/\/ Grab the first variant ID\n        window.DETECTED_VARIANT_ID = productData.variants[0].id;\n        console.log(\"System Locked on ID:\", window.DETECTED_VARIANT_ID);\n        \n    } catch (e) {\n        console.error(\"ID Fetch Error:\", e);\n        \/\/ Fallback: Try to find Liquid ID if fetch fails\n        try {\n           window.DETECTED_VARIANT_ID = \"{{ product.selected_or_first_available_variant.id }}\";\n        } catch(err) {\n           console.log(\"Liquid Fallback Failed\");\n        }\n    }\n})();\n\n\/\/ --- 2. UPLOAD HANDLERS ---\nwindow.triggerUpload = (index) =\u003e { if(window.generatedInputs[index]) window.generatedInputs[index].click(); };\nwindow.generatedInputs.forEach((input, idx) =\u003e { input.addEventListener('change', (e) =\u003e handleFile(e, idx)); });\n\nfunction handleFile(e, index) {\n    const file = e.target.files[0];\n    if(!file) return;\n    const btn = btns[index];\n    const sideName = [\"Front\", \"Right\", \"Back\", \"Left\"][index];\n    btn.style.borderColor = \"#4CAF50\"; btn.style.borderStyle = \"solid\"; btn.style.backgroundColor = \"#e8f5e9\"; btn.style.color = \"#2e7d32\";\n    btn.innerHTML = `✅ \u003cb\u003e${sideName} READY\u003c\/b\u003e\u003cbr\u003e\u003cspan style='font-size:11px; font-weight:normal;'\u003e${file.name}\u003c\/span\u003e`;\n}\n\n\/\/ --- 3. CART LOGIC ---\nsetTimeout(() =\u003e {\n    const themeBtn = document.querySelector('button[name=\"add\"], .product-form__submit, .add-to-cart');\n    if(themeBtn) {\n        const myBtn = document.createElement('button');\n        myBtn.innerText = \"Loading System...\"; \/\/ Initial State\n        myBtn.className = themeBtn.className;\n        myBtn.style.cssText = themeBtn.style.cssText;\n        myBtn.style.width = \"100%\"; myBtn.style.marginTop = \"10px\";\n        myBtn.disabled = true; myBtn.style.opacity = \"0.5\"; myBtn.style.cursor = \"not-allowed\";\n\n        themeBtn.style.display = \"none\";\n        themeBtn.parentNode.insertBefore(myBtn, themeBtn);\n\n        \/\/ Click Handler\n        myBtn.addEventListener('click', (e) =\u003e {\n            e.preventDefault(); e.stopPropagation();\n            \n            \/\/ FINAL CHECK: Do we have an ID?\n            if(!window.DETECTED_VARIANT_ID) {\n                alert(\"System Error: Product ID missing. Please refresh the page.\");\n                return;\n            }\n\n            let missing = 0;\n            window.generatedInputs.forEach(i =\u003e { if(i.files.length === 0) missing++; });\n            if(missing \u003e 0) { alert(`Please upload all 4 photos.`); return; }\n\n            myBtn.innerText = \"Adding to Cart...\"; myBtn.disabled = true;\n            \n            const form = document.createElement('form');\n            form.method = \"POST\"; form.action = \"\/cart\/add\"; form.enctype = \"multipart\/form-data\"; form.style.display = \"none\";\n\n            const idInput = document.createElement('input');\n            idInput.type = \"hidden\"; idInput.name = \"id\"; idInput.value = window.DETECTED_VARIANT_ID; \/\/ USE FETCHED ID\n            form.appendChild(idInput);\n\n            window.generatedInputs.forEach(input =\u003e form.appendChild(input));\n            document.body.appendChild(form);\n            form.submit();\n        });\n\n        \/\/ Validation Loop\n        setInterval(() =\u003e {\n            if(myBtn.innerText !== \"Adding to Cart...\") {\n                \/\/ If we still don't have an ID, stay in Loading state\n                if(!window.DETECTED_VARIANT_ID) {\n                     myBtn.innerText = \"Loading System...\";\n                     return;\n                }\n\n                let count = 0;\n                window.generatedInputs.forEach(i =\u003e { if(i.files.length \u003e 0) count++; });\n                \n                if(count === 4) {\n                    myBtn.disabled = false; myBtn.style.opacity = \"1\"; myBtn.style.cursor = \"pointer\"; myBtn.innerText = \"Add to Cart\";\n                    warning.style.display = \"none\";\n                } else {\n                    myBtn.disabled = true; myBtn.style.opacity = \"0.5\"; myBtn.innerText = `Upload ${4-count} More Photos`;\n                    warning.innerHTML = `* You must upload \u003cb\u003e${4-count}\u003c\/b\u003e more photo(s).`; warning.style.display = \"block\";\n                }\n            }\n        }, 500);\n    }\n}, 500);\n\u003c\/script\u003e","brand":"3D Railroad Prints ","offers":[{"title":"Default Title","offer_id":50590552719646,"sku":null,"price":65.99,"currency_code":"USD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0980\/1515\/0366\/files\/rn-image_picker_lib_temp_8bce16a0-321d-4f9d-b22f-0ea66e3f5ceb.jpg?v=1770494466"},{"product_id":"the-four-seasons-lantern","title":"The Four-Seasons lantern","description":"\u003cp\u003e our premium, centerpiece light designed to shine from every angle. By day, it sits as a classic, matte-black lantern with elegant textured white panels. By night, it comes alive—filling your room with the warm, nostalgic glow of your four favorite memories.\u003c\/p\u003e\n\u003cp\u003e​Perfect for coffee tables, mantels, or bedsides, this lantern turns your digital photos into a physical family heirloom.\u003c\/p\u003e\n\u003cp\u003e​Why You’ll Love It:\u003c\/p\u003e\n\u003cp\u003e​4 Custom Panels: Upload four distinct photos—one for each side. (Perfect for showing a pet's growth, a wedding timeline, or grandchildren).\u003c\/p\u003e\n\u003cp\u003e​Classic Design: Features a timeless lantern silhouette with a sturdy handle and matte black finish that fits any decor.\u003c\/p\u003e\n\u003cp\u003e​High-Definition Detail: Printed with our signature high-res settings to capture every smile and detail.\u003c\/p\u003e\n\u003cp\u003e​Plug-and-Glow: Comes with a cord and switch—no batteries required.\u003c\/p\u003e","brand":"​Forever Illuminated 3D","offers":[{"title":"Default Title","offer_id":50594817671454,"sku":null,"price":74.99,"currency_code":"USD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0980\/1515\/0366\/files\/rn-image_picker_lib_temp_3e2a2207-69f1-4fb6-a94f-76f03090a564.gif?v=1770606670"}],"url":"https:\/\/foreverilluminated3d.com\/collections\/lithophanes.oembed","provider":"​Forever Illuminated 3D","version":"1.0","type":"link"}