Jump to content

MediaWiki:Common.js: Difference between revisions

The comprehensive free global encyclopedia of CEOs, corporate leadership, and business excellence
Add JavaScript-based responsive image resizing for CEO profiles - auto-adjusts on window resize
FIX: 1) Moved cloud up 30px for proper centering 2) Removed backface-visibility:hidden so text never disappears, just fades to 25% opacity when behind
 
(3 intermediate revisions by the same user not shown)
Line 13: Line 13:
});
});


/* 3D CEO Cloud - Horizontal Ellipsoid - Wikipedia Style */
/* 3D CEO Cloud - FIXED centering and visibility */
$(document).ready(function() {
$(document).ready(function() {
     var placeholder = document.getElementById('ceocloud-placeholder');
     var placeholder = document.getElementById('ceocloud-placeholder');
     if (!placeholder) {
     if (!placeholder) return;
        console.log('CEO Cloud: placeholder not found');
        return;
    }


    // Get CEO data from the parser function
     var ceoDataEl = document.getElementById('ceo-data');
     var ceoDataEl = document.getElementById('ceo-data');
     if (!ceoDataEl) {
     if (!ceoDataEl) return;
        console.log('CEO Cloud: ceo-data element not found');
        return;
    }


     var ceoDataJson = ceoDataEl.getAttribute('data-ceos');
     var ceoDataJson = ceoDataEl.getAttribute('data-ceos');
     if (!ceoDataJson) {
     if (!ceoDataJson) return;
        console.log('CEO Cloud: data-ceos attribute empty');
        return;
    }


     var tags = JSON.parse(ceoDataJson);
     var tags;
     if (!tags || tags.length === 0) {
    try {
         console.log('CEO Cloud: no tags found');
        tags = JSON.parse(ceoDataJson);
     } catch(e) {
         console.log('CEO Cloud: JSON parse error');
         return;
         return;
     }
     }
    if (!tags || tags.length === 0) return;


     console.log('CEO Cloud: Initializing with ' + tags.length + ' CEOs');
     console.log('CEO Cloud: Initializing with ' + tags.length + ' CEOs');


     // Create cloud container with proper centering
     // Create cloud container
     var cloud = document.createElement('div');
     var cloud = document.createElement('div');
     cloud.style.position = 'relative';
     cloud.style.cssText = 'position:relative;width:100%;height:500px;overflow:hidden;cursor:grab;';
    cloud.style.width = '100%';
    cloud.style.height = '500px';
    cloud.style.overflow = 'hidden';
    cloud.style.cursor = 'grab';


     // Create inner sphere container
     // Create sphere container - FIXED: moved up by 30px to compensate for visual offset
     var sphere = document.createElement('div');
     var sphere = document.createElement('div');
     sphere.style.position = 'absolute';
     sphere.style.cssText = 'position:absolute;left:50%;top:calc(50% - 30px);width:1px;height:1px;transform-style:preserve-3d;will-change:transform;';
    sphere.style.left = '50%';
    sphere.style.top = '50%';
    sphere.style.width = '1px';
    sphere.style.height = '1px';
    sphere.style.transformStyle = 'preserve-3d';
    sphere.style.transition = 'transform 0.3s ease-out';
 
    // Horizontal ellipsoid parameters - much wider than tall
    var radiusX = 380;  // Width
    var radiusY = 120;  // Height (much smaller for horizontal spread)
    var radiusZ = 280;  // Depth


     var phi = Math.PI * (3 - Math.sqrt(5)); // Golden angle in radians
    // Ellipsoid parameters
    var radiusX = 320;
    var radiusY = 100;
    var radiusZ = 240;
     var phi = Math.PI * (3 - Math.sqrt(5));
     var ceoElements = [];
     var ceoElements = [];
    var numTags = tags.length;


     tags.forEach(function(tag, i) {
     // Pre-calculate positions and create elements
         // Fibonacci sphere distribution
    for (var i = 0; i < numTags; i++) {
         var y = 1 - (i / (tags.length - 1)) * 2; // y goes from 1 to -1
         var tag = tags[i];
         var radiusAtY = Math.sqrt(1 - y * y); // radius at y
         var y = 1 - (i / (numTags - 1)) * 2;
         var theta = phi * i; // golden angle increment
         var radiusAtY = Math.sqrt(1 - y * y);
 
         var theta = phi * i;
         var x = Math.cos(theta) * radiusAtY;
         var x = Math.cos(theta) * radiusAtY;
         var z = Math.sin(theta) * radiusAtY;
         var z = Math.sin(theta) * radiusAtY;


        // Scale to ellipsoid - WIDE horizontally
         var posX = x * radiusX;
         var posX = x * radiusX;
         var posY = y * radiusY;
         var posY = y * radiusY;
         var posZ = z * radiusZ;
         var posZ = z * radiusZ;


        // Create link element
         var link = document.createElement('a');
         var link = document.createElement('a');
         link.href = tag.url;
         link.href = tag.url;
         link.textContent = tag.text;
         link.textContent = tag.text;
         link.style.position = 'absolute';
        // FIXED: Removed backface-visibility:hidden so text is always visible
        link.style.left = '0';
         link.style.cssText = 'position:absolute;left:0;top:0;color:#fff;text-decoration:none;font-size:' + tag.size + 'px;font-weight:400;font-family:"Linux Libertine",Georgia,serif;white-space:nowrap;text-shadow:0 2px 10px rgba(0,0,0,0.9);cursor:pointer;transform-style:preserve-3d;user-select:none;will-change:transform,opacity;transform:translate3d(' + posX + 'px,' + posY + 'px,' + posZ + 'px) translate(-50%,-50%);';
        link.style.top = '0';
          
        link.style.color = '#ffffff';
        link.style.textDecoration = 'none';
        link.style.fontSize = tag.size + 'px';
        link.style.fontWeight = '400';
        link.style.fontFamily = '"Linux Libertine", Georgia, "Times New Roman", Times, serif';
        link.style.whiteSpace = 'nowrap';
        link.style.transition = 'all 0.3s ease, transform 0.2s ease';
        link.style.textShadow = '0 2px 10px rgba(0,0,0,0.9), 0 0 30px rgba(0,0,0,0.6)';
        link.style.cursor = 'pointer';
        link.style.transformStyle = 'preserve-3d';
        link.style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, ' + posZ + 'px) translate(-50%, -50%)';
        link.style.backfaceVisibility = 'hidden';
         link.style.userSelect = 'none';
 
        // Store original position and data
         link.dataset.x = posX;
         link.dataset.x = posX;
         link.dataset.y = posY;
         link.dataset.y = posY;
         link.dataset.z = posZ;
         link.dataset.z = posZ;
         link.dataset.originalSize = tag.size;
         link.dataset.size = tag.size;


         // Hover effects with depth perception
         // Hover effects
         link.addEventListener('mouseenter', function() {
         link.onmouseenter = function() {
             this.style.color = '#fbbf24';
             this.style.color = '#fbbf24';
             this.style.fontWeight = '700';
             this.style.fontWeight = '700';
            var scale = 1.4;
             this.style.fontSize = (parseFloat(this.dataset.size) * 1.4) + 'px';
             this.style.fontSize = (parseFloat(this.dataset.originalSize) * scale) + 'px';
             this.style.textShadow = '0 3px 20px rgba(251,191,36,1),0 0 50px rgba(251,191,36,0.8)';
             this.style.textShadow = '0 3px 20px rgba(251, 191, 36, 1), 0 0 50px rgba(251, 191, 36, 0.8), 0 0 80px rgba(251, 191, 36, 0.4)';
             this.style.zIndex = '1000';
             this.style.zIndex = '1000';
            this.style.filter = 'brightness(1.3)';
         };
         });
         link.onmouseleave = function() {
 
             this.style.color = '#fff';
         link.addEventListener('mouseleave', function() {
             this.style.color = '#ffffff';
             this.style.fontWeight = '400';
             this.style.fontWeight = '400';
             this.style.fontSize = this.dataset.originalSize + 'px';
             this.style.fontSize = this.dataset.size + 'px';
             this.style.textShadow = '0 2px 10px rgba(0,0,0,0.9), 0 0 30px rgba(0,0,0,0.6)';
             this.style.textShadow = '0 2px 10px rgba(0,0,0,0.9)';
             this.style.zIndex = 'auto';
             this.style.zIndex = '';
            this.style.filter = 'brightness(1)';
         };
         });
 
        // Click animation
        link.addEventListener('click', function(e) {
            this.style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, ' + (posZ + 100) + 'px) translate(-50%, -50%) scale(1.5)';
            this.style.transition = 'all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)';
        });
 
        ceoElements.push({
            element: link,
            x: posX,
            y: posY,
            z: posZ
        });


        ceoElements.push({ el: link, x: posX, y: posY, z: posZ });
         sphere.appendChild(link);
         sphere.appendChild(link);
     });
     }


     cloud.appendChild(sphere);
     cloud.appendChild(sphere);
     placeholder.innerHTML = ''; // Clear placeholder
     placeholder.innerHTML = '';
     placeholder.appendChild(cloud);
     placeholder.appendChild(cloud);


     // Animation variables
     // Animation state
     var angleX = 10; // Start with slight tilt
     var angleX = 10, angleY = 0;
     var angleY = 0;
     var targetAngleX = 10, targetAngleY = 0;
    var zoom = 1.7, targetZoom = 1.7;
     var autoRotate = true;
     var autoRotate = true;
    var targetAngleX = 10;
     var rotationSpeed = 0.15;
    var targetAngleY = 0;
     var frameCount = 0;
     var rotationSpeed = 0.15; // Slower, smoother rotation
     var zoom = 1;
    var targetZoom = 1;


     // Update depth-based opacity and size
     // FIXED: Proper depth calculation - text always visible, just faded when behind
     function updateDepth() {
     function updateDepth() {
         var transform = sphere.style.transform;
         var rad = angleY * Math.PI / 180;
         var matrix = new WebKitCSSMatrix(window.getComputedStyle(sphere).transform);
         var cosRad = Math.cos(rad);
        var sinRad = Math.sin(rad);


         ceoElements.forEach(function(ceo) {
         for (var i = 0; i < ceoElements.length; i++) {
            // Calculate Z position after rotation
             var ceo = ceoElements[i];
            var x = parseFloat(ceo.x);
             // Calculate rotated Z position
             var y = parseFloat(ceo.y);
             var newZ = ceo.z * cosRad - ceo.x * sinRad;
            var z = parseFloat(ceo.z);
           
 
             // Normalize to 0-1 range (front to back)
             // Simple rotation math for depth
             var depthFactor = (newZ + radiusZ) / (radiusZ * 2);
             var rad = angleY * Math.PI / 180;
             depthFactor = Math.max(0, Math.min(1, depthFactor));
            var newZ = z * Math.cos(rad) - x * Math.sin(rad);
           
 
            // FIXED: Text at back (depthFactor near 0) still visible but faded
             // Depth-based effects
            // Front text: opacity 1.0, Back text: opacity 0.25
             var depthFactor = (newZ + radiusZ) / (radiusZ * 2); // 0 to 1
             var opacity = 0.25 + depthFactor * 0.75;
             var opacity = 0.3 + (depthFactor * 0.7); // 0.3 to 1.0
           
             var scale = 0.7 + (depthFactor * 0.3); // 0.7 to 1.0
             ceo.el.style.opacity = opacity;
 
             ceo.el.style.zIndex = Math.round(depthFactor * 100);
             ceo.element.style.opacity = opacity;
         }
             ceo.element.style.filter = 'brightness(' + (0.6 + depthFactor * 0.4) + ')';
 
            // Update z-index for proper layering
            ceo.element.style.zIndex = Math.round(depthFactor * 100);
         });
     }
     }


    // Main animation loop
     function animate() {
     function animate() {
         if (autoRotate) {
         if (autoRotate) {
Line 197: Line 142:
         zoom += (targetZoom - zoom) * 0.1;
         zoom += (targetZoom - zoom) * 0.1;


        // Update transform
         sphere.style.transform = 'scale(' + zoom + ') rotateX(' + angleX + 'deg) rotateY(' + angleY + 'deg)';
         sphere.style.transform = 'scale(' + zoom + ') rotateX(' + angleX + 'deg) rotateY(' + angleY + 'deg)';


         updateDepth();
         // Update depth every 3 frames for performance
        frameCount++;
        if (frameCount % 3 === 0) {
            updateDepth();
        }
 
         requestAnimationFrame(animate);
         requestAnimationFrame(animate);
     }
     }


    // Initial depth calculation
    updateDepth();
     animate();
     animate();


     // Interactive controls
     // Mouse drag controls
     var isDragging = false;
     var isDragging = false, prevX = 0, prevY = 0;
    var previousMouseX = 0;
    var previousMouseY = 0;


     cloud.addEventListener('mousedown', function(e) {
     cloud.onmousedown = function(e) {
         if (e.target.tagName.toLowerCase() !== 'a') {
         if (e.target.tagName !== 'A') {
             isDragging = true;
             isDragging = true;
             autoRotate = false;
             autoRotate = false;
             previousMouseX = e.clientX;
             prevX = e.clientX;
             previousMouseY = e.clientY;
             prevY = e.clientY;
             cloud.style.cursor = 'grabbing';
             cloud.style.cursor = 'grabbing';
             e.preventDefault();
             e.preventDefault();
         }
         }
     });
     };


     document.addEventListener('mousemove', function(e) {
     document.onmousemove = function(e) {
         if (isDragging) {
         if (isDragging) {
             var deltaX = e.clientX - previousMouseX;
             targetAngleY += (e.clientX - prevX) * 0.5;
            var deltaY = e.clientY - previousMouseY;
             targetAngleX = Math.max(-40, Math.min(40, targetAngleX - (e.clientY - prevY) * 0.3));
 
             prevX = e.clientX;
            targetAngleY += deltaX * 0.5;
             prevY = e.clientY;
            targetAngleX -= deltaY * 0.3;
 
            // Limit vertical rotation
             targetAngleX = Math.max(-40, Math.min(40, targetAngleX));
 
             previousMouseX = e.clientX;
             previousMouseY = e.clientY;
         }
         }
     });
     };


     document.addEventListener('mouseup', function() {
     document.onmouseup = function() {
         if (isDragging) {
         if (isDragging) {
             isDragging = false;
             isDragging = false;
             cloud.style.cursor = 'grab';
             cloud.style.cursor = 'grab';
             setTimeout(function() {
             setTimeout(function() { autoRotate = true; }, 2000);
                autoRotate = true;
            }, 2000); // Resume auto-rotation after 2 seconds
         }
         }
     });
     };


     // Mouse wheel zoom
     // Mouse wheel zoom
     cloud.addEventListener('wheel', function(e) {
     cloud.onwheel = function(e) {
         e.preventDefault();
         e.preventDefault();
        var delta = e.deltaY > 0 ? -0.1 : 0.1;
         targetZoom = Math.max(0.8, Math.min(2.5, targetZoom + (e.deltaY > 0 ? -0.1 : 0.1)));
         targetZoom = Math.max(0.5, Math.min(1.5, targetZoom + delta));
 
         autoRotate = false;
         autoRotate = false;
         clearTimeout(cloud.zoomTimeout);
         clearTimeout(cloud.zoomTimeout);
         cloud.zoomTimeout = setTimeout(function() {
         cloud.zoomTimeout = setTimeout(function() { autoRotate = true; }, 1500);
            autoRotate = true;
     };
        }, 1500);
     });


     // Touch support for mobile
     // Touch support
    var touchStartX = 0;
     cloud.ontouchstart = function(e) {
    var touchStartY = 0;
 
     cloud.addEventListener('touchstart', function(e) {
         if (e.touches.length === 1) {
         if (e.touches.length === 1) {
             isDragging = true;
             isDragging = true;
             autoRotate = false;
             autoRotate = false;
             touchStartX = e.touches[0].clientX;
             prevX = e.touches[0].clientX;
             touchStartY = e.touches[0].clientY;
             prevY = e.touches[0].clientY;
            previousMouseX = touchStartX;
            previousMouseY = touchStartY;
             e.preventDefault();
             e.preventDefault();
         }
         }
     });
     };


     document.addEventListener('touchmove', function(e) {
     document.ontouchmove = function(e) {
         if (isDragging && e.touches.length === 1) {
         if (isDragging && e.touches.length === 1) {
             var deltaX = e.touches[0].clientX - previousMouseX;
             targetAngleY += (e.touches[0].clientX - prevX) * 0.5;
            var deltaY = e.touches[0].clientY - previousMouseY;
             targetAngleX = Math.max(-40, Math.min(40, targetAngleX - (e.touches[0].clientY - prevY) * 0.3));
 
             prevX = e.touches[0].clientX;
            targetAngleY += deltaX * 0.5;
             prevY = e.touches[0].clientY;
            targetAngleX -= deltaY * 0.3;
             targetAngleX = Math.max(-40, Math.min(40, targetAngleX));
 
             previousMouseX = e.touches[0].clientX;
             previousMouseY = e.touches[0].clientY;
         }
         }
     });
     };


     document.addEventListener('touchend', function() {
     document.ontouchend = function() {
         if (isDragging) {
         if (isDragging) {
             isDragging = false;
             isDragging = false;
             setTimeout(function() {
             setTimeout(function() { autoRotate = true; }, 2000);
                autoRotate = true;
            }, 2000);
        }
    });
 
    // Keyboard controls
    document.addEventListener('keydown', function(e) {
        if (placeholder.contains(document.activeElement) || document.activeElement === document.body) {
            switch(e.key) {
                case 'ArrowLeft':
                    targetAngleY -= 10;
                    autoRotate = false;
                    e.preventDefault();
                    break;
                case 'ArrowRight':
                    targetAngleY += 10;
                    autoRotate = false;
                    e.preventDefault();
                    break;
                case 'ArrowUp':
                    targetAngleX = Math.max(-40, targetAngleX - 10);
                    autoRotate = false;
                    e.preventDefault();
                    break;
                case 'ArrowDown':
                    targetAngleX = Math.min(40, targetAngleX + 10);
                    autoRotate = false;
                    e.preventDefault();
                    break;
                case '+':
                case '=':
                    targetZoom = Math.min(1.5, targetZoom + 0.1);
                    autoRotate = false;
                    e.preventDefault();
                    break;
                case '-':
                case '_':
                    targetZoom = Math.max(0.5, targetZoom - 0.1);
                    autoRotate = false;
                    e.preventDefault();
                    break;
                case ' ':
                    autoRotate = !autoRotate;
                    e.preventDefault();
                    break;
            }
         }
         }
     });
     };
 
    // Double-click to focus on CEO
    sphere.addEventListener('dblclick', function(e) {
        if (e.target.tagName.toLowerCase() === 'a') {
            e.preventDefault();
            targetZoom = 1.3;
            autoRotate = false;
 
            setTimeout(function() {
                window.location.href = e.target.href;
            }, 300);
        }
    });


     // Add control hints
     // Control hints
     var hints = document.createElement('div');
     var hints = document.createElement('div');
     hints.style.position = 'absolute';
     hints.style.cssText = 'position:absolute;bottom:10px;left:50%;transform:translateX(-50%);color:rgba(255,255,255,0.6);font-size:12px;text-align:center;pointer-events:none;font-family:sans-serif;';
    hints.style.bottom = '10px';
     hints.innerHTML = '🖱️ Drag to rotate • 🔍 Scroll to zoom';
    hints.style.left = '50%';
    hints.style.transform = 'translateX(-50%)';
    hints.style.color = 'rgba(255,255,255,0.6)';
    hints.style.fontSize = '12px';
    hints.style.textAlign = 'center';
    hints.style.pointerEvents = 'none';
    hints.style.fontFamily = 'sans-serif';
     hints.innerHTML = '🖱️ Drag to rotate • 🔍 Scroll to zoom • ⌨️ Arrow keys to navigate • Space to pause';
     cloud.appendChild(hints);
     cloud.appendChild(hints);


     console.log('CEO Cloud: Successfully initialized with horizontal ellipsoid');
     console.log('CEO Cloud: Initialization complete');
});
});


/* ============================================
/* ============================================
   RESPONSIVE CEO PROFILE IMAGES
   RESPONSIVE CEO PROFILE IMAGES
  Auto-resize images based on window size
   ============================================ */
   ============================================ */
$(document).ready(function() {
$(document).ready(function() {
    // Only run on Main Page
     if (!$('body').hasClass('page-Main_Page')) return;
     if (!$('body').hasClass('page-Main_Page')) return;


     function resizeCEOImages() {
     function resizeCEOImages() {
        // Get window width
         var windowWidth = $(window).width();
         var windowWidth = $(window).width();
        // Calculate optimal image width based on screen size
         var imageWidth;
         var imageWidth;
       
         if (windowWidth > 1200) {
         if (windowWidth > 1200) {
            // Desktop: 3 columns, each ~33%
             imageWidth = Math.floor((windowWidth - 100) / 3 * 0.7);
             imageWidth = Math.floor((windowWidth - 100) / 3 * 0.7); // 70% of column width
         } else if (windowWidth > 768) {
         } else if (windowWidth > 768) {
            // Tablet: 2 columns
             imageWidth = Math.floor((windowWidth - 80) / 2 * 0.7);
             imageWidth = Math.floor((windowWidth - 80) / 2 * 0.7);
         } else if (windowWidth > 480) {
         } else if (windowWidth > 480) {
            // Mobile landscape: 1 column
             imageWidth = Math.floor((windowWidth - 40) * 0.8);
             imageWidth = Math.floor((windowWidth - 40) * 0.8);
         } else {
         } else {
            // Mobile portrait: 1 column, smaller
             imageWidth = Math.floor((windowWidth - 40) * 0.9);
             imageWidth = Math.floor((windowWidth - 40) * 0.9);
         }
         }


        // Clamp between 150px and 400px
         imageWidth = Math.max(150, Math.min(400, imageWidth));
         imageWidth = Math.max(150, Math.min(400, imageWidth));


        // Find all CEO profile images (images inside featured CEO cards)
         $('table[style*="width: 33%"] img, table[style*="width: 25%"] img').each(function() {
         $('table[style*="width: 33%"] img, table[style*="width: 25%"] img').each(function() {
             var $img = $(this);
             var $img = $(this);
            // Skip if it's not a CEO profile image
             var src = $img.attr('src');
             var src = $img.attr('src');
             if (!src || src.indexOf('File:') === -1) return;
             if (!src || src.indexOf('File:') === -1) return;


            // Get original src URL without size parameters
            var originalSrc = src;
            // Build new URL with desired width
            // MediaWiki thumb format: /thumb/.../{width}px-filename.jpg
             if (src.indexOf('/thumb/') !== -1) {
             if (src.indexOf('/thumb/') !== -1) {
                 // Replace the width in the URL
                 $img.attr('src', src.replace(/\/\d+px-/, '/' + imageWidth + 'px-'));
                var newSrc = src.replace(/\/\d+px-/, '/' + imageWidth + 'px-');
                $img.attr('src', newSrc);
             }
             }


            // Update img attributes for proper display
             $img.css({ 'max-width': '100%', 'height': 'auto', 'width': 'auto', 'display': 'block', 'margin': '0 auto' });
             $img.css({
             $img.removeAttr('width').removeAttr('height');
                'max-width': '100%',
             $img.parent('a').css({ 'display': 'block', 'text-align': 'center' });
                'height': 'auto',
                'width': 'auto',
                'display': 'block',
                'margin': '0 auto'
            });
 
            // Remove fixed width attribute if present
             $img.removeAttr('width');
            $img.removeAttr('height');
 
            // Update parent link styling
             $img.parent('a').css({
                'display': 'block',
                'text-align': 'center'
            });
         });
         });
        console.log('CEO images resized to: ' + imageWidth + 'px (window: ' + windowWidth + 'px)');
     }
     }


    // Resize on page load
     resizeCEOImages();
     resizeCEOImages();


    // Resize on window resize (with debouncing)
     var resizeTimer;
     var resizeTimer;
     $(window).on('resize', function() {
     $(window).on('resize', function() {
         clearTimeout(resizeTimer);
         clearTimeout(resizeTimer);
         resizeTimer = setTimeout(function() {
         resizeTimer = setTimeout(resizeCEOImages, 250);
            resizeCEOImages();
        }, 250); // Wait 250ms after resize stops
     });
     });


    // Also trigger on orientation change (mobile)
     $(window).on('orientationchange', function() {
     $(window).on('orientationchange', function() {
         setTimeout(resizeCEOImages, 300);
         setTimeout(resizeCEOImages, 300);
     });
     });
    console.log('CEO Profile Images: Responsive resizing enabled');
});
});

Latest revision as of 12:24, 29 November 2025

/* Common.js - Site-wide JavaScript */

/* Add copyright footer at the very bottom of page - single occurrence only */
$(document).ready(function() {
    // Remove any existing copyright footers first to prevent duplicates
    $('#footer-info-copyright, .ceo-copyright-footer').remove();

    // Create the copyright footer
    var copyright = '<div class="ceo-copyright-footer" id="footer-info-copyright" style="text-align: center; padding: 20px; background: #f8f9fa; border-top: 1px solid #ddd; margin-top: 40px; font-size: 0.85em; line-height: 1.6;">Text is available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="nofollow">Creative Commons Attribution-ShareAlike 4.0 License</a>; additional terms may apply. By using this site, you agree to the <a href="/wiki/CEO.wiki:Terms_of_Use">Terms of Use</a>, <a href="/wiki/CEO.wiki:Privacy_Policy">Privacy Policy</a>, and all <a href="/wiki/CEO.wiki:General_disclaimer">disclaimers</a>. CEO.wiki is operated as an independent collaborative encyclopedia project and is not affiliated with Wikipedia or the Wikimedia Foundation. See our <a href="/wiki/CEO.wiki:Takedown_Request_Policy">Takedown Request Policy</a> for content concerns.</div>';

    // Append to the very bottom of the body
    $('body').append(copyright);
});

/* 3D CEO Cloud - FIXED centering and visibility */
$(document).ready(function() {
    var placeholder = document.getElementById('ceocloud-placeholder');
    if (!placeholder) return;

    var ceoDataEl = document.getElementById('ceo-data');
    if (!ceoDataEl) return;

    var ceoDataJson = ceoDataEl.getAttribute('data-ceos');
    if (!ceoDataJson) return;

    var tags;
    try {
        tags = JSON.parse(ceoDataJson);
    } catch(e) {
        console.log('CEO Cloud: JSON parse error');
        return;
    }
    if (!tags || tags.length === 0) return;

    console.log('CEO Cloud: Initializing with ' + tags.length + ' CEOs');

    // Create cloud container
    var cloud = document.createElement('div');
    cloud.style.cssText = 'position:relative;width:100%;height:500px;overflow:hidden;cursor:grab;';

    // Create sphere container - FIXED: moved up by 30px to compensate for visual offset
    var sphere = document.createElement('div');
    sphere.style.cssText = 'position:absolute;left:50%;top:calc(50% - 30px);width:1px;height:1px;transform-style:preserve-3d;will-change:transform;';

    // Ellipsoid parameters
    var radiusX = 320;
    var radiusY = 100;
    var radiusZ = 240;
    var phi = Math.PI * (3 - Math.sqrt(5));
    var ceoElements = [];
    var numTags = tags.length;

    // Pre-calculate positions and create elements
    for (var i = 0; i < numTags; i++) {
        var tag = tags[i];
        var y = 1 - (i / (numTags - 1)) * 2;
        var radiusAtY = Math.sqrt(1 - y * y);
        var theta = phi * i;
        var x = Math.cos(theta) * radiusAtY;
        var z = Math.sin(theta) * radiusAtY;

        var posX = x * radiusX;
        var posY = y * radiusY;
        var posZ = z * radiusZ;

        var link = document.createElement('a');
        link.href = tag.url;
        link.textContent = tag.text;
        // FIXED: Removed backface-visibility:hidden so text is always visible
        link.style.cssText = 'position:absolute;left:0;top:0;color:#fff;text-decoration:none;font-size:' + tag.size + 'px;font-weight:400;font-family:"Linux Libertine",Georgia,serif;white-space:nowrap;text-shadow:0 2px 10px rgba(0,0,0,0.9);cursor:pointer;transform-style:preserve-3d;user-select:none;will-change:transform,opacity;transform:translate3d(' + posX + 'px,' + posY + 'px,' + posZ + 'px) translate(-50%,-50%);';
        
        link.dataset.x = posX;
        link.dataset.y = posY;
        link.dataset.z = posZ;
        link.dataset.size = tag.size;

        // Hover effects
        link.onmouseenter = function() {
            this.style.color = '#fbbf24';
            this.style.fontWeight = '700';
            this.style.fontSize = (parseFloat(this.dataset.size) * 1.4) + 'px';
            this.style.textShadow = '0 3px 20px rgba(251,191,36,1),0 0 50px rgba(251,191,36,0.8)';
            this.style.zIndex = '1000';
        };
        link.onmouseleave = function() {
            this.style.color = '#fff';
            this.style.fontWeight = '400';
            this.style.fontSize = this.dataset.size + 'px';
            this.style.textShadow = '0 2px 10px rgba(0,0,0,0.9)';
            this.style.zIndex = '';
        };

        ceoElements.push({ el: link, x: posX, y: posY, z: posZ });
        sphere.appendChild(link);
    }

    cloud.appendChild(sphere);
    placeholder.innerHTML = '';
    placeholder.appendChild(cloud);

    // Animation state
    var angleX = 10, angleY = 0;
    var targetAngleX = 10, targetAngleY = 0;
    var zoom = 1.7, targetZoom = 1.7;
    var autoRotate = true;
    var rotationSpeed = 0.15;
    var frameCount = 0;

    // FIXED: Proper depth calculation - text always visible, just faded when behind
    function updateDepth() {
        var rad = angleY * Math.PI / 180;
        var cosRad = Math.cos(rad);
        var sinRad = Math.sin(rad);

        for (var i = 0; i < ceoElements.length; i++) {
            var ceo = ceoElements[i];
            // Calculate rotated Z position
            var newZ = ceo.z * cosRad - ceo.x * sinRad;
            
            // Normalize to 0-1 range (front to back)
            var depthFactor = (newZ + radiusZ) / (radiusZ * 2);
            depthFactor = Math.max(0, Math.min(1, depthFactor));
            
            // FIXED: Text at back (depthFactor near 0) still visible but faded
            // Front text: opacity 1.0, Back text: opacity 0.25
            var opacity = 0.25 + depthFactor * 0.75;
            
            ceo.el.style.opacity = opacity;
            ceo.el.style.zIndex = Math.round(depthFactor * 100);
        }
    }

    // Main animation loop
    function animate() {
        if (autoRotate) {
            targetAngleY += rotationSpeed;
        }

        // Smooth interpolation
        angleX += (targetAngleX - angleX) * 0.1;
        angleY += (targetAngleY - angleY) * 0.1;
        zoom += (targetZoom - zoom) * 0.1;

        // Update transform
        sphere.style.transform = 'scale(' + zoom + ') rotateX(' + angleX + 'deg) rotateY(' + angleY + 'deg)';

        // Update depth every 3 frames for performance
        frameCount++;
        if (frameCount % 3 === 0) {
            updateDepth();
        }

        requestAnimationFrame(animate);
    }

    // Initial depth calculation
    updateDepth();
    animate();

    // Mouse drag controls
    var isDragging = false, prevX = 0, prevY = 0;

    cloud.onmousedown = function(e) {
        if (e.target.tagName !== 'A') {
            isDragging = true;
            autoRotate = false;
            prevX = e.clientX;
            prevY = e.clientY;
            cloud.style.cursor = 'grabbing';
            e.preventDefault();
        }
    };

    document.onmousemove = function(e) {
        if (isDragging) {
            targetAngleY += (e.clientX - prevX) * 0.5;
            targetAngleX = Math.max(-40, Math.min(40, targetAngleX - (e.clientY - prevY) * 0.3));
            prevX = e.clientX;
            prevY = e.clientY;
        }
    };

    document.onmouseup = function() {
        if (isDragging) {
            isDragging = false;
            cloud.style.cursor = 'grab';
            setTimeout(function() { autoRotate = true; }, 2000);
        }
    };

    // Mouse wheel zoom
    cloud.onwheel = function(e) {
        e.preventDefault();
        targetZoom = Math.max(0.8, Math.min(2.5, targetZoom + (e.deltaY > 0 ? -0.1 : 0.1)));
        autoRotate = false;
        clearTimeout(cloud.zoomTimeout);
        cloud.zoomTimeout = setTimeout(function() { autoRotate = true; }, 1500);
    };

    // Touch support
    cloud.ontouchstart = function(e) {
        if (e.touches.length === 1) {
            isDragging = true;
            autoRotate = false;
            prevX = e.touches[0].clientX;
            prevY = e.touches[0].clientY;
            e.preventDefault();
        }
    };

    document.ontouchmove = function(e) {
        if (isDragging && e.touches.length === 1) {
            targetAngleY += (e.touches[0].clientX - prevX) * 0.5;
            targetAngleX = Math.max(-40, Math.min(40, targetAngleX - (e.touches[0].clientY - prevY) * 0.3));
            prevX = e.touches[0].clientX;
            prevY = e.touches[0].clientY;
        }
    };

    document.ontouchend = function() {
        if (isDragging) {
            isDragging = false;
            setTimeout(function() { autoRotate = true; }, 2000);
        }
    };

    // Control hints
    var hints = document.createElement('div');
    hints.style.cssText = 'position:absolute;bottom:10px;left:50%;transform:translateX(-50%);color:rgba(255,255,255,0.6);font-size:12px;text-align:center;pointer-events:none;font-family:sans-serif;';
    hints.innerHTML = '🖱️ Drag to rotate • 🔍 Scroll to zoom';
    cloud.appendChild(hints);

    console.log('CEO Cloud: Initialization complete');
});

/* ============================================
   RESPONSIVE CEO PROFILE IMAGES
   ============================================ */
$(document).ready(function() {
    if (!$('body').hasClass('page-Main_Page')) return;

    function resizeCEOImages() {
        var windowWidth = $(window).width();
        var imageWidth;
        
        if (windowWidth > 1200) {
            imageWidth = Math.floor((windowWidth - 100) / 3 * 0.7);
        } else if (windowWidth > 768) {
            imageWidth = Math.floor((windowWidth - 80) / 2 * 0.7);
        } else if (windowWidth > 480) {
            imageWidth = Math.floor((windowWidth - 40) * 0.8);
        } else {
            imageWidth = Math.floor((windowWidth - 40) * 0.9);
        }

        imageWidth = Math.max(150, Math.min(400, imageWidth));

        $('table[style*="width: 33%"] img, table[style*="width: 25%"] img').each(function() {
            var $img = $(this);
            var src = $img.attr('src');
            if (!src || src.indexOf('File:') === -1) return;

            if (src.indexOf('/thumb/') !== -1) {
                $img.attr('src', src.replace(/\/\d+px-/, '/' + imageWidth + 'px-'));
            }

            $img.css({ 'max-width': '100%', 'height': 'auto', 'width': 'auto', 'display': 'block', 'margin': '0 auto' });
            $img.removeAttr('width').removeAttr('height');
            $img.parent('a').css({ 'display': 'block', 'text-align': 'center' });
        });
    }

    resizeCEOImages();

    var resizeTimer;
    $(window).on('resize', function() {
        clearTimeout(resizeTimer);
        resizeTimer = setTimeout(resizeCEOImages, 250);
    });

    $(window).on('orientationchange', function() {
        setTimeout(resizeCEOImages, 300);
    });
});