diff --git a/public/css/style.css b/public/css/style.css index 7f3fc27..74a7fef 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -612,7 +612,7 @@ input:checked+.slider:before { backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); overflow: hidden; - transition: all 0.3s ease; + transition: border-color 0.3s ease, background 0.3s ease, box-shadow 0.3s ease; } .chart-card:hover { diff --git a/public/js/app.js b/public/js/app.js index 2179149..6d21b40 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -232,10 +232,13 @@ const endRect = dom.globeCard.getBoundingClientRect(); const scaleX = savedGlobeRect.width / endRect.width; const scaleY = savedGlobeRect.height / endRect.height; - const dx = (savedGlobeRect.left + savedGlobeRect.width / 2) - (endRect.left + endRect.width / 2); - const dy = (savedGlobeRect.top + savedGlobeRect.height / 2) - (endRect.top + endRect.height / 2); + + // Using top-left for math (transformOrigin: 0 0) + const dx = savedGlobeRect.left - endRect.left; + const dy = savedGlobeRect.top - endRect.top; dom.globeCard.style.willChange = 'transform, box-shadow'; + dom.globeCard.style.transformOrigin = '0 0'; dom.globeCard.style.transition = 'none'; dom.globeCard.style.transform = `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`; dom.globeCard.style.boxShadow = '0 0 0 0 transparent, 0 0 0 0 transparent'; @@ -243,7 +246,6 @@ dom.globeCard.offsetHeight; // Force reflow dom.globeCard.style.transition = 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s ease'; - // Use explicit values instead of empty string for better transition reliability dom.globeCard.style.transform = 'translate(0px, 0px) scale(1)'; dom.globeCard.style.boxShadow = ''; @@ -252,6 +254,8 @@ dom.globeCard.removeEventListener('transitionend', onTransitionEnd); dom.globeCard.style.transition = ''; dom.globeCard.style.willChange = ''; + dom.globeCard.style.transformOrigin = ''; + dom.globeCard.style.transform = ''; }; dom.globeCard.addEventListener('transitionend', onTransitionEnd); } @@ -289,17 +293,21 @@ const expandedRect = dom.globeCard.getBoundingClientRect(); const scaleX = savedGlobeRect.width / expandedRect.width; const scaleY = savedGlobeRect.height / expandedRect.height; - const dx = (savedGlobeRect.left + savedGlobeRect.width / 2) - (expandedRect.left + expandedRect.width / 2); - const dy = (savedGlobeRect.top + savedGlobeRect.height / 2) - (expandedRect.top + expandedRect.height / 2); - - // Ensure we are at a known state before starting transition - dom.globeCard.style.transform = 'translate(0px, 0px) scale(1)'; - dom.globeCard.offsetHeight; // Force reflow + // Match origin used in expand + const dx = savedGlobeRect.left - expandedRect.left; + const dy = savedGlobeRect.top - expandedRect.top; + + // Force setup the expanded state with origin + dom.globeCard.style.transformOrigin = '0 0'; + dom.globeCard.style.transform = 'translate(0px, 0px) scale(1)'; + dom.globeCard.style.boxShadow = ''; // Reset to what CSS says + dom.globeCard.offsetHeight; // Critical sync reflow + dom.globeCard.style.willChange = 'transform, box-shadow'; dom.globeCard.style.transition = 'transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s ease'; - // Apply target values + // Apply target values immediately after reflow dom.globeCard.style.transform = `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`; dom.globeCard.style.boxShadow = '0 0 0 0 transparent, 0 0 0 0 transparent';