Загрузка данных


/* =========================================
   ФИЗИКА И ИНТЕРАКТИВ (Гравитация и Drag)
   ========================================= */

/* Класс для элементов, которые можно таскать */
.draggable {
    cursor: grab;
    z-index: 1; /* Чтобы перетаскиваемый элемент был поверх других */
}

.draggable:active {
    cursor: grabbing;
    z-index: 100;
}

/* Стили для падающих букв */
.physics-letter {
    position: fixed; /* Фиксируем относительно экрана, чтобы они падали вниз */
    z-index: 9999;
    cursor: grab;
    user-select: none; /* Чтобы текст не выделялся при таскании */
    pointer-events: auto;
    font-weight: bold;
    text-shadow: 0 2px 5px rgba(0,0,0,0.5);
}

.physics-letter:active {
    cursor: grabbing;
}

/* Класс-заглушка для разбитого заголовка */
.shattered-placeholder {
    visibility: hidden; /* Скрываем оригинал, но оставляем его размер, чтобы сайт не схлопнулся */
}







    // ==========================================
    // 1. Drag & Drop для карточек (можно хватать и кидать)
    // ==========================================
    const makeDraggable = () => {
        const draggables = document.querySelectorAll('.skill-card, .portfolio-item, .lab-item');
        
        draggables.forEach(el => {
            el.classList.add('draggable');
            let isDragging = false;
            let startX, startY;
            let currentLeft = 0;
            let currentTop = 0;

            el.addEventListener('mousedown', (e) => {
                isDragging = true;
                startX = e.clientX;
                startY = e.clientY;
                
                // Получаем текущие координаты
                currentLeft = parseInt(window.getComputedStyle(el).left || 0, 10);
                currentTop = parseInt(window.getComputedStyle(el).top || 0, 10);
                
                // Включаем относительное позиционирование для перемещения
                if (window.getComputedStyle(el).position === 'static') {
                    el.style.position = 'relative';
                }
                el.style.transition = 'none'; // Убираем плавность при перетаскивании
            });

            window.addEventListener('mousemove', (e) => {
                if (!isDragging) return;
                const dx = e.clientX - startX;
                const dy = e.clientY - startY;
                el.style.left = `${currentLeft + dx}px`;
                el.style.top = `${currentTop + dy}px`;
            });

            window.addEventListener('mouseup', () => {
                if (isDragging) {
                    isDragging = false;
                    el.style.transition = 'transform 0.3s ease, box-shadow 0.3s ease'; // Возвращаем стили из CSS
                }
            });
        });
    };

    // ==========================================
    // 2. Механика разрушения (5 кликов) и Гравитация
    // ==========================================
    const initDestruction = () => {
        // Ищем все заголовки
        const headers = document.querySelectorAll('h1, h2');
        
        headers.forEach(header => {
            let clickCount = 0;
            let clickTimer;

            header.addEventListener('click', () => {
                clickCount++;
                clearTimeout(clickTimer);
                
                if (clickCount >= 5) {
                    shatterElement(header);
                    clickCount = 0;
                } else {
                    // Если кликаем медленно, счетчик сбрасывается через полсекунды
                    clickTimer = setTimeout(() => clickCount = 0, 500); 
                }
            });
        });
    };

    function shatterElement(element) {
        if (element.classList.contains('shattered-placeholder')) return; // Уже сломан

        const text = element.innerText;
        const rect = element.getBoundingClientRect();
        
        // Прячем оригинальный заголовок
        element.classList.add('shattered-placeholder');

        const letters = [];
        const letterWidth = rect.width / text.length; // Примерная ширина буквы

        // Создаем физические буквы
        for (let i = 0; i < text.length; i++) {
            if (text[i] === ' ') continue;

            const span = document.createElement('span');
            span.innerText = text[i];
            span.className = 'physics-letter';
            
            // Расставляем буквы точно на те места, где они были в слове
            span.style.left = `${rect.left + (i * letterWidth)}px`;
            span.style.top = `${rect.top}px`;
            
            // Копируем стили шрифта у родителя
            const computedStyle = window.getComputedStyle(element);
            span.style.fontSize = computedStyle.fontSize;
            span.style.color = computedStyle.color;
            span.style.fontFamily = computedStyle.fontFamily;

            document.body.appendChild(span);

            // Добавляем физические параметры (скорость, позиция)
            letters.push({
                el: span,
                x: parseFloat(span.style.left),
                y: parseFloat(span.style.top),
                vx: (Math.random() - 0.5) * 15, // Разлет в стороны (сильнее!)
                vy: (Math.random() * -10) - 5,  // Подскок вверх
                isDragging: false
            });
        }

        // --- ДВИЖОК ГРАВИТАЦИИ ---
        let animationId;
        const gravity = 0.8;
        const bounce = 0.6; // Сила отскока
        const ground = window.innerHeight - 50; // Уровень "пола" экрана

        function updatePhysics() {
            letters.forEach(letter => {
                if (letter.isDragging) return; // Если тащим мышкой, гравитация не работает

                letter.vy += gravity; // Падение
                letter.x += letter.vx;
                letter.y += letter.vy;

                // Удар об пол
                if (letter.y > ground) {
                    letter.y = ground;
                    letter.vy *= -bounce; // Отскок с потерей энергии
                    letter.vx *= 0.8;     // Трение об пол
                }
                
                // Удар о стены
                if (letter.x < 0 || letter.x > window.innerWidth - 30) {
                    letter.vx *= -0.8;
                }

                // Применяем координаты к элементу
                letter.el.style.left = `${letter.x}px`;
                letter.el.style.top = `${letter.y}px`;
            });
            
            animationId = requestAnimationFrame(updatePhysics);
        }
        updatePhysics(); // Запускаем цикл падения

        // --- ЛОГИКА ВОССТАНОВЛЕНИЯ (Перетаскивание букв) ---
        letters.forEach(letter => {
            letter.el.addEventListener('mousedown', (e) => {
                letter.isDragging = true;
                let startX = e.clientX;
                let startY = e.clientY;

                const onMouseMove = (moveEvent) => {
                    const dx = moveEvent.clientX - startX;
                    const dy = moveEvent.clientY - startY;
                    letter.x += dx;
                    letter.y += dy;
                    letter.el.style.left = `${letter.x}px`;
                    letter.el.style.top = `${letter.y}px`;
                    startX = moveEvent.clientX;
                    startY = moveEvent.clientY;
                };

                const onMouseUp = () => {
                    letter.isDragging = false;
                    document.removeEventListener('mousemove', onMouseMove);
                    document.removeEventListener('mouseup', onMouseUp);

                    // Проверяем: принесли ли мы букву обратно в "зону" оригинального заголовка
                    const origRect = element.getBoundingClientRect();
                    const triggerZone = 50; // Погрешность в пикселях

                    if (letter.x >= origRect.left - triggerZone && letter.x <= origRect.right + triggerZone &&
                        letter.y >= origRect.top - triggerZone && letter.y <= origRect.bottom + triggerZone) {
                        
                        // ВОССТАНАВЛИВАЕМ САЙТ!
                        cancelAnimationFrame(animationId); // Останавливаем физику
                        letters.forEach(l => l.el.remove()); // Удаляем мусор с экрана
                        element.classList.remove('shattered-placeholder'); // Показываем оригинал
                    }
                };

                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
            });
        });
    }

    // Запускаем наши новые функции
    makeDraggable();
    initDestruction();