{"id":7,"date":"2026-03-17T13:39:37","date_gmt":"2026-03-17T13:39:37","guid":{"rendered":"https:\/\/projects.parisforino.com\/gallery\/?page_id=7"},"modified":"2026-04-15T19:22:43","modified_gmt":"2026-04-15T19:22:43","slug":"commercial","status":"publish","type":"page","link":"https:\/\/projects.parisforino.com\/gallery\/","title":{"rendered":"Commercial"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"7\" class=\"elementor elementor-7\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ef40be7 e-flex e-con-boxed e-con e-parent\" data-id=\"ef40be7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ef36ed8 mansory-custom elementor-widget elementor-widget-shortcode\" data-id=\"ef36ed8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">\n    <style>\n        :root { --gap: 16px; }\n\n        .gallery-masonry {\n            width: 100%;\n            column-gap: var(--gap);\n            column-count: 5;\n            opacity: 0;\n            transform: translateY(18px);\n            transition: opacity 0.45s ease, transform 0.45s ease;\n        }\n\n        .gallery-masonry.gallery-ready {\n            opacity: 1;\n            transform: translateY(0);\n        }\n\n        .gallery-item {\n            break-inside: avoid;\n            margin-bottom: 20px;\n            transition: transform 0.3s ease;\n            cursor: pointer;\n            background: rgba(0,0,0,0.04);\n        }\n\n        .gallery-item img {\n            display: block;\n            width: 100%;\n            opacity: 0;\n            transform: translateY(10px);\n            transition: opacity 0.45s ease, transform 0.45s ease;\n            will-change: opacity, transform;\n        }\n\n        .gallery-item img.img-ready {\n            opacity: 1;\n            transform: translateY(0);\n        }\n\n        .gallery-item.hidden-on-grid { display: none !important; }\n\n        .gallery-masonry.dimmed img { opacity: 0.1; }\n        .gallery-masonry.dimmed img.active-property { opacity: 1 !important; }\n\n        #customLightboxOverlay {\n            position: fixed;\n            top: 0; left: 0;\n            width: 100vw; height: 100vh;\n            background-color: #ffffff;\n            display: none;\n            flex-direction: column;\n            justify-content: center;\n            align-items: center;\n            z-index: 99999;\n            opacity: 0;\n            transition: opacity 0.3s ease-in-out;\n        }\n\n        #customLightboxOverlay.active {\n            display: flex;\n            opacity: 1;\n            pointer-events: auto;\n        }\n\n        #lightboxTitleDisplay {\n            position: absolute;\n            top: 50px;\n            left: 50%;\n            transform: translateX(-50%);\n            text-transform: uppercase;\n            font-family: KMR-Waldenburg-SemiBold, Arial, sans-serif;\n            font-size: 14px;\n            font-weight: bold;\n            color: #000;\n            letter-spacing: 0.15em;\n            text-align: center;\n            width: 80%;\n        }\n\n        #lightboxImageContent {\n            max-width: 98%;\n            max-height: 70%;\n            object-fit: contain;\n            margin-top: 40px;\n            margin-bottom: 20px;\n            transition: opacity 0.3s ease-in-out;\n        }\n\n        #lightboxImageContent.is-loading { opacity: 0; }\n        #lightboxImageContent.is-loaded { opacity: 1; }\n\n        #customLightboxOverlay #lightboxCloseBtn {\n            position: absolute;\n            top: 25px;\n            right: 25px;\n            cursor: pointer;\n            z-index: 100000;\n            width: 70px;\n            height: 70px;\n        }\n        \n        #lightboxCloseBtn img {\n            width: 100%;\n            height: auto;\n            display: block;\n        }\n\n        #lightboxThumbnailsContainer {\n            display: flex !important;\n            justify-content: center;\n            align-items: flex-end;\n            gap: 15px;\n            max-width: 95%;\n            height: 65px;\n            overflow-x: auto;\n            margin: 0 auto 10px auto;\n        }\n\n        .lightbox-thumbnail {\n            width: auto !important;\n            height: 45px !important;\n            flex-shrink: 0;\n            opacity: 0.2;\n            cursor: pointer;\n            transition: all 0.2s ease;\n            object-fit: contain;\n        }\n\n        .lightbox-thumbnail.active-thumb { opacity: 1 !important; }\n\n        #propertyTitleDisplay {\n            position: fixed;\n            bottom: 50px;\n            left: 50%;\n            transform: translateX(-50%);\n            text-transform: uppercase;\n            font-family: KMR-Waldenburg-SemiBold, Arial, sans-serif;\n            font-size: 14px;\n            color: #000;\n            opacity: 0;\n            transition: opacity 0.3s ease;\n            pointer-events: none;\n            z-index: 10000;\n        }\n\n        @media (max-width: 1200px) {\n            .gallery-masonry { column-count: 4; }\n        }\n\n        @media (max-width: 800px) {\n            .gallery-masonry { column-count: 3; }\n        }\n        \n        @media (max-width: 600px) { \n            .gallery-masonry { column-count: 2; } \n            \n            #lightboxTitleDisplay {\n                top: 30px;\n                font-size: 11px;\n                width: 70%;\n            }\n\n            #customLightboxOverlay #lightboxCloseBtn {\n                top: 20px;\n                right: 20px;\n                width: 40px;\n                height: 40px;\n            }\n\n            #lightboxImageContent {\n                max-height: 60%;\n                margin-top: 20px;\n            }\n        }\n    <\/style>\n\n    <div class=\"gallery-masonry\" id=\"mansory-container\"><\/div>\n\n    <script>\n    (function () {\n        let allGalleryImages = [];\n        let propertyTitleDisplay = null;\n        let lightboxOverlay = null;\n        let lightboxImage = null;\n        let lightboxThumbnailsContainer = null;\n        let lightboxTitleDisplay = null;\n        let filteredImages = [];\n        let currentImageIndex = -1;\n\n        const getFullSizeSrc = (img) => img.dataset.fullsize || img.src;\n\n        const handlePropertyHover = (property, isEntering) => {\n            const container = document.querySelector(\".gallery-masonry\");\n\n            if (isEntering && property) {\n                if (container) container.classList.add(\"dimmed\");\n\n                allGalleryImages.forEach((img) => {\n                    img.classList.toggle(\"active-property\", img.alt === property);\n                });\n\n                if (propertyTitleDisplay) {\n                    propertyTitleDisplay.textContent = property;\n                    propertyTitleDisplay.style.opacity = 1;\n                }\n            } else {\n                if (container) container.classList.remove(\"dimmed\");\n\n                allGalleryImages.forEach((img) => {\n                    img.classList.remove(\"active-property\");\n                });\n\n                if (propertyTitleDisplay) {\n                    propertyTitleDisplay.style.opacity = 0;\n                }\n            }\n        };\n\n        const updateLightbox = (index) => {\n            if (filteredImages.length === 0) return;\n\n            if (index < 0) index = filteredImages.length - 1;\n            else if (index >= filteredImages.length) index = 0;\n\n            currentImageIndex = index;\n            \n            document.querySelectorAll(\".lightbox-thumbnail\").forEach((thumb, idx) => {\n                thumb.classList.toggle(\"active-thumb\", idx === index);\n\n                if (idx === index) {\n                    thumb.scrollIntoView({ behavior: \"smooth\", inline: \"center\" });\n                }\n            });\n\n            const imgData = filteredImages[index];\n            lightboxTitleDisplay.textContent = imgData.alt;\n            lightboxImage.classList.add(\"is-loading\");\n            lightboxImage.classList.remove(\"is-loaded\");\n\n            const tempImage = new Image();\n            tempImage.onload = () => {\n                lightboxImage.src = getFullSizeSrc(imgData);\n                lightboxImage.classList.remove(\"is-loading\");\n                lightboxImage.classList.add(\"is-loaded\");\n            };\n            tempImage.onerror = () => {\n                lightboxImage.src = getFullSizeSrc(imgData);\n                lightboxImage.classList.remove(\"is-loading\");\n                lightboxImage.classList.add(\"is-loaded\");\n            };\n            tempImage.src = getFullSizeSrc(imgData);\n        };\n\n        window.openLightbox = (clickedImage) => {\n            const property = clickedImage.alt;\n            filteredImages = allGalleryImages.filter(img => img.alt === property);\n\n            lightboxThumbnailsContainer.innerHTML = \"\";\n\n            filteredImages.forEach((img, i) => {\n                const t = document.createElement(\"img\");\n                t.src = img.src;\n                t.classList.add(\"lightbox-thumbnail\");\n\n                t.onclick = (e) => {\n                    e.stopPropagation();\n                    updateLightbox(i);\n                };\n\n                t.onmouseover = () => updateLightbox(i);\n                lightboxThumbnailsContainer.appendChild(t);\n            });\n\n            const startIdx = filteredImages.indexOf(clickedImage);\n            updateLightbox(startIdx);\n\n            lightboxOverlay.classList.add(\"active\");\n            document.body.style.overflow = \"hidden\";\n        };\n\n        window.initPropertyLightbox = function () {\n            if (!document.getElementById(\"propertyTitleDisplay\")) {\n                const t = document.createElement(\"div\");\n                t.id = \"propertyTitleDisplay\";\n                document.body.appendChild(t);\n            }\n            propertyTitleDisplay = document.getElementById(\"propertyTitleDisplay\");\n\n            if (!document.getElementById(\"customLightboxOverlay\")) {\n                const html = `\n                <div id=\"customLightboxOverlay\">\n                    <span id=\"lightboxCloseBtn\"><img decoding=\"async\" src=\"https:\/\/website-1823c791.cdj.sga.mybluehost.me\/img\/close.png\" alt=\"Close\"><\/span>\n                    <div id=\"lightboxTitleDisplay\"><\/div>\n                    <img id=\"lightboxImageContent\" class=\"is-loading\" alt=\"\">\n                    <div id=\"lightboxThumbnailsContainer\"><\/div>\n                <\/div>`;\n                document.body.insertAdjacentHTML(\"beforeend\", html);\n            }\n\n            lightboxOverlay = document.getElementById(\"customLightboxOverlay\");\n            lightboxImage = document.getElementById(\"lightboxImageContent\");\n            lightboxThumbnailsContainer = document.getElementById(\"lightboxThumbnailsContainer\");\n            lightboxTitleDisplay = document.getElementById(\"lightboxTitleDisplay\");\n\n            const closeBtn = document.getElementById(\"lightboxCloseBtn\");\n            if (closeBtn) {\n                closeBtn.onclick = () => {\n                    lightboxOverlay.classList.remove(\"active\");\n                    document.body.style.overflow = \"\";\n                };\n            }\n            \n            document.addEventListener(\"keydown\", (e) => {\n                if (!lightboxOverlay || !lightboxOverlay.classList.contains(\"active\")) return;\n\n                if (e.key === \"ArrowLeft\") {\n                    updateLightbox(currentImageIndex - 1);\n                } else if (e.key === \"ArrowRight\") {\n                    updateLightbox(currentImageIndex + 1);\n                } else if (e.key === \"Escape\") {\n                    lightboxOverlay.classList.remove(\"active\");\n                    document.body.style.overflow = \"\";\n                }\n            });\n        };\n\n        window.handlePropertyHover = handlePropertyHover;\n        window.setAllGalleryImages = (imgs) => {\n            allGalleryImages = imgs;\n        };\n    })();\n\n    document.addEventListener(\"DOMContentLoaded\", () => {\n        const MAX_TOTAL_IMAGES = 65;\n        const MAX_PER_PROJECT = 5;\n\n        function shuffle(array) {\n            for (let i = array.length - 1; i > 0; i--) {\n                const j = Math.floor(Math.random() * (i + 1));\n                [array[i], array[j]] = [array[j], array[i]];\n            }\n            return array;\n        }\n\n        function preloadImage(src) {\n            return new Promise((resolve) => {\n                const image = new Image();\n                image.onload = resolve;\n                image.onerror = resolve;\n                image.src = src;\n\n                if (image.complete) {\n                    resolve();\n                }\n            });\n        }\n\n        async function loadImages() {\n            try {\n                const res = await fetch(\"https:\/\/website-1823c791.cdj.sga.mybluehost.me\/c.php\");\n                const data = await res.json();\n                const container = document.getElementById(\"mansory-container\");\n\n                if (!container || !Array.isArray(data)) return;\n\n                const shuffledData = shuffle(data);\n                const projectCounts = {};\n                let totalVisible = 0;\n                const allImgs = [];\n                const visibleImgs = [];\n                const fragment = document.createDocumentFragment();\n\n                shuffledData.forEach(d => {\n                    const project = d.project || 'Uncategorized';\n                    projectCounts[project] = projectCounts[project] || 0;\n\n                    let isVisible = false;\n                    if (projectCounts[project] < MAX_PER_PROJECT && totalVisible < MAX_TOTAL_IMAGES) {\n                        isVisible = true;\n                        projectCounts[project]++;\n                        totalVisible++;\n                    }\n\n                    const div = document.createElement(\"div\");\n                    div.className = \"gallery-item\";\n\n                    if (!isVisible) {\n                        div.classList.add(\"hidden-on-grid\");\n                    }\n\n                    const img = document.createElement(\"img\");\n                    img.src = d.url_mini;\n                    img.dataset.fullsize = d.url;\n                    img.alt = d.project || \"\";\n\n                    img.onmouseover = () => window.handlePropertyHover(d.project, true);\n                    img.onmouseout = () => window.handlePropertyHover(d.project, false);\n                    img.onclick = () => window.openLightbox(img);\n\n                    div.appendChild(img);\n                    fragment.appendChild(div);\n\n                    allImgs.push(img);\n                    if (isVisible) {\n                        visibleImgs.push(img);\n                    }\n                });\n\n                await Promise.allSettled(\n                    visibleImgs.map(img => preloadImage(img.src))\n                );\n\n                container.appendChild(fragment);\n                window.setAllGalleryImages(allImgs);\n                window.initPropertyLightbox();\n\n                requestAnimationFrame(() => {\n                    container.classList.add(\"gallery-ready\");\n\n                    visibleImgs.forEach((img, index) => {\n                        setTimeout(() => {\n                            img.classList.add(\"img-ready\");\n                        }, Math.min(index * 20, 400));\n                    });\n                });\n\n            } catch (err) {\n                console.error(\"Error:\", err);\n            }\n        }\n\n        loadImages();\n    });\n    <\/script>\n\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b5c2716 e-flex e-con-boxed e-con e-parent\" data-id=\"b5c2716\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6ccad9b elementor-widget__width-inherit elementor-widget elementor-widget-shortcode\" data-id=\"6ccad9b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">\n    <style>\n        \/* Contenedor que respeta el ancho del padre (la galer\u00eda) *\/\n        .directory-container-aligned {\n            width: 100%;\n            max-width: 100%;\n            margin: 0 auto;\n            display: block;\n            overflow: hidden;\n        }\n\n        #portfolio-iframe {\n            display: block;\n            width: 100% !important; \/* Ocupa el 100% del contenedor de la galer\u00eda *\/\n            min-width: 100%;\n            border: none;\n            \/* Altura base de 1800px, pero ajustable por el script inferior *\/\n            height: 1800px; \n            transition: height 0.3s ease;\n        }\n    <\/style>\n\n    <div class=\"directory-container-aligned\">\n        <iframe \n            src=\"https:\/\/projects.parisforino.com\/portfolio-index-embeded.php\" \n            id=\"portfolio-iframe\"\n            frameborder=\"0\" \n            scrolling=\"no\">\n        <\/iframe>\n    <\/div>\n\n    <script>\n        (function() {\n            const iframe = document.getElementById('portfolio-iframe');\n            \n            \/\/ Escuchar el postMessage desde Bluehost para ajustar el alto real\n            window.addEventListener('message', function(e) {\n                if (e.data && e.data.setHeight) {\n                    iframe.style.height = (e.data.setHeight + 10) + 'px';\n                }\n            }, false);\n        })();\n    <\/script>\n\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-7","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/pages\/7","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/comments?post=7"}],"version-history":[{"count":116,"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/pages\/7\/revisions"}],"predecessor-version":[{"id":596,"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/pages\/7\/revisions\/596"}],"wp:attachment":[{"href":"https:\/\/projects.parisforino.com\/gallery\/wp-json\/wp\/v2\/media?parent=7"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}