/* ============================
   郑州晟算科技有限公司 - 交互脚本 v3
   自定义光标 · 启动加载屏 · 3D倾斜 · 磁性按钮 · 乱序解码
   ============================ */

(function () {
  "use strict";

  /* ========================================
     1. 自定义光标
     ======================================== */
  const isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;

  if (!isTouchDevice) {
    const dot = document.createElement("div");
    dot.className = "cursor-dot";
    const ring = document.createElement("div");
    ring.className = "cursor-ring";
    document.body.appendChild(dot);
    document.body.appendChild(ring);

    let dotX = 0, dotY = 0;
    let ringX = 0, ringY = 0;
    let mouseX = 0, mouseY = 0;
    let isVisible = false;
    let cursorActivated = false;

    document.addEventListener("mousemove", function (e) {
      mouseX = e.clientX;
      mouseY = e.clientY;
      if (!isVisible) {
        isVisible = true;
        dot.style.opacity = "1";
        ring.style.opacity = "1";
        // 确认自定义光标工作后才隐藏系统光标
        if (!cursorActivated) {
          cursorActivated = true;
          document.body.classList.add("custom-cursor-active");
        }
      }
    });

    document.addEventListener("mouseleave", function () {
      isVisible = false;
      dot.style.opacity = "0";
      ring.style.opacity = "0";
    });

    document.addEventListener("mousedown", function () {
      ring.classList.add("clicking");
    });

    document.addEventListener("mouseup", function () {
      ring.classList.remove("clicking");
    });

    // 检测可交互元素
    const hoverables = document.querySelectorAll("a, button, .card, .teaser-card, .feature-card, .belief-card, .philosophy-item, input, textarea, select, .nav-cta, .structure-item, .vision-item");
    hoverables.forEach(function (el) {
      el.addEventListener("mouseenter", function () { ring.classList.add("hovering"); });
      el.addEventListener("mouseleave", function () { ring.classList.remove("hovering"); });
    });

    function animateCursor() {
      // 点：即时跟随
      dotX += (mouseX - dotX) * 0.35;
      dotY += (mouseY - dotY) * 0.35;
      dot.style.left = dotX + "px";
      dot.style.top = dotY + "px";

      // 环：延迟跟随
      ringX += (mouseX - ringX) * 0.12;
      ringY += (mouseY - ringY) * 0.12;
      ring.style.left = ringX + "px";
      ring.style.top = ringY + "px";

      requestAnimationFrame(animateCursor);
    }
    animateCursor();
  }

  /* ========================================
     2. 启动加载屏(太空模式下由space.js接管)
     ======================================== */
  const isFirstVisit = !sessionStorage.getItem("visited");
  if (!window.SPACE_MODE && isFirstVisit) {
    const loadingScreen = document.createElement("div");
    loadingScreen.className = "loading-screen";
    loadingScreen.innerHTML =
      '<div class="loading-logo">SHENG<span>SUAN</span></div>' +
      '<div class="loading-terminal">' +
        '<div class="terminal-header">' +
          '<div class="terminal-dot"></div>' +
          '<div class="terminal-dot"></div>' +
          '<div class="terminal-dot"></div>' +
          '<div class="terminal-title">shengsuan@tech ~ boot</div>' +
        '</div>' +
        '<div class="terminal-body">' +
          '<div class="terminal-line" style="animation-delay:0.1s"><span class="terminal-prompt">></span><span class="terminal-text">Detecting software chaos... </span><span class="terminal-text ok">[76%]</span></div>' +
          '<div class="terminal-line" style="animation-delay:0.4s"><span class="terminal-prompt">></span><span class="terminal-text">Loading fix modules... </span><span class="terminal-text ok">[OK]</span></div>' +
          '<div class="terminal-line" style="animation-delay:0.7s"><span class="terminal-prompt">></span><span class="terminal-text">Mounting patches... </span><span class="terminal-text ok">[3 loaded]</span></div>' +
          '<div class="terminal-line" style="animation-delay:1.0s"><span class="terminal-prompt">></span><span class="terminal-text">Rendering scene... </span><span class="terminal-text ok">[OK]</span></div>' +
          '<div class="terminal-line" style="animation-delay:1.3s"><span class="terminal-prompt">></span><span class="terminal-text typing" style="color:var(--cyan)">Welcome, fixer. Let\'s repair some software.</span></div>' +
        '</div>' +
      '</div>';
    document.body.appendChild(loadingScreen);

    setTimeout(function () {
      loadingScreen.classList.add("hide");
      sessionStorage.setItem("visited", "true");
      setTimeout(function () {
        if (loadingScreen.parentNode) loadingScreen.parentNode.removeChild(loadingScreen);
      }, 700);
    }, 2000);
  } else {
    sessionStorage.setItem("visited", "true");
  }

  /* ========================================
     3. 滚动进度条
     ======================================== */
  const progressBar = document.createElement("div");
  progressBar.className = "scroll-progress";
  progressBar.style.width = "0%";
  document.body.appendChild(progressBar);

  window.addEventListener("scroll", function () {
    const scrollTop = window.scrollY;
    const docHeight = document.documentElement.scrollHeight - window.innerHeight;
    const scrollPercent = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
    progressBar.style.width = scrollPercent + "%";
  }, { passive: true });

  /* ========================================
     4. 粒子背景(太空模式下禁用,由space.js接管)
     ======================================== */
  let canvas = document.getElementById("particlesCanvas");
  if (window.SPACE_MODE) {
    if (canvas) canvas.remove();
  } else {
  if (!canvas) {
    canvas = document.createElement("canvas");
    canvas.id = "particlesCanvas";
    document.body.prepend(canvas);
  }
  const ctx = canvas.getContext("2d");
  let particles = [];
  const PARTICLE_COUNT = 50;
  let pmouseX = 0, pmouseY = 0;

  function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
  }
  resizeCanvas();
  window.addEventListener("resize", resizeCanvas);

  for (let i = 0; i < PARTICLE_COUNT; i++) {
    particles.push({
      x: Math.random() * canvas.width,
      y: Math.random() * canvas.height,
      vx: (Math.random() - 0.5) * 0.4,
      vy: (Math.random() - 0.5) * 0.4,
      size: Math.random() * 1.5 + 0.5,
      opacity: Math.random() * 0.35 + 0.08
    });
  }

  document.addEventListener("mousemove", function (e) {
    pmouseX = e.clientX;
    pmouseY = e.clientY;
  });

  function drawParticles() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    for (let i = 0; i < particles.length; i++) {
      const p = particles[i];
      p.x += p.vx;
      p.y += p.vy;

      if (p.x < 0) p.x = canvas.width;
      if (p.x > canvas.width) p.x = 0;
      if (p.y < 0) p.y = canvas.height;
      if (p.y > canvas.height) p.y = 0;

      const dx = pmouseX - p.x;
      const dy = pmouseY - p.y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (dist < 180 && dist > 0) {
        const force = (180 - dist) / 180 * 0.5;
        p.vx += (dx / dist) * force * 0.03;
        p.vy += (dy / dist) * force * 0.03;
      }

      p.vx *= 0.999;
      p.vy *= 0.999;

      ctx.beginPath();
      ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
      ctx.fillStyle = "rgba(0, 230, 118, " + p.opacity + ")";
      ctx.fill();
    }

    for (let j = 0; j < particles.length; j++) {
      for (let k = j + 1; k < particles.length; k++) {
        const a = particles[j], b = particles[k];
        const d = Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
        if (d < 120) {
          ctx.beginPath();
          ctx.moveTo(a.x, a.y);
          ctx.lineTo(b.x, b.y);
          ctx.strokeStyle = "rgba(0, 230, 118, " + (0.06 * (1 - d / 120)) + ")";
          ctx.lineWidth = 0.5;
          ctx.stroke();
        }
      }
    }

    requestAnimationFrame(drawParticles);
  }
  drawParticles();
  } /* end else (非太空模式才运行粒子) */

  /* ========================================
     5. 导航栏
     ======================================== */
  const header = document.querySelector(".header");
  window.addEventListener("scroll", function () {
    if (window.scrollY > 10) {
      header.classList.add("scrolled");
    } else {
      header.classList.remove("scrolled");
    }
  }, { passive: true });

  const menuToggle = document.querySelector(".menu-toggle");
  const nav = document.querySelector(".nav");
  if (menuToggle && nav) {
    menuToggle.addEventListener("click", function () {
      menuToggle.classList.toggle("active");
      nav.classList.toggle("active");
    });
    nav.querySelectorAll("a").forEach(function (link) {
      link.addEventListener("click", function () {
        menuToggle.classList.remove("active");
        nav.classList.remove("active");
      });
    });
  }

  /* ========================================
     6. 滚动显现
     ======================================== */
  const revealElements = document.querySelectorAll(".reveal");
  if ("IntersectionObserver" in window && revealElements.length > 0) {
    const observer = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          observer.unobserve(entry.target);
        }
      });
    }, { threshold: 0.1, rootMargin: "0px 0px -30px 0px" });
    revealElements.forEach(function (el) { observer.observe(el); });
  } else {
    revealElements.forEach(function (el) { el.classList.add("visible"); });
  }

  /* ========================================
     7. 打字机效果
     ======================================== */
  const typewriterEl = document.querySelector("#typewriter");
  if (typewriterEl) {
    let words;
    try {
      words = typewriterEl.getAttribute("data-words")
        ? JSON.parse(typewriterEl.getAttribute("data-words"))
        : [typewriterEl.textContent.trim()];
    } catch (e) {
      words = [typewriterEl.textContent.trim()];
    }

    let wordIndex = 0;
    let charIndex = 0;
    let isDeleting = false;
    const typeSpeed = 80;
    const deleteSpeed = 40;
    const pauseTime = 2000;

    function type() {
      const currentWord = words[wordIndex];
      if (isDeleting) {
        typewriterEl.textContent = currentWord.substring(0, charIndex - 1);
        charIndex--;
        if (charIndex === 0) {
          isDeleting = false;
          wordIndex = (wordIndex + 1) % words.length;
          setTimeout(type, 300);
          return;
        }
        setTimeout(type, deleteSpeed);
      } else {
        typewriterEl.textContent = currentWord.substring(0, charIndex + 1);
        charIndex++;
        if (charIndex === currentWord.length) {
          setTimeout(function () {
            isDeleting = true;
            type();
          }, pauseTime);
          return;
        }
        setTimeout(type, typeSpeed);
      }
    }

    const cursor = document.createElement("span");
    cursor.className = "typewriter-cursor";
    cursor.textContent = "_";
    typewriterEl.parentNode.insertBefore(cursor, typewriterEl.nextSibling);
    setTimeout(type, 500);
  }

  /* ========================================
     8. 3D 倾斜卡片
     ======================================== */
  const tiltCards = document.querySelectorAll(".card, .teaser-card, .feature-card, .belief-card, .philosophy-item, .teaser-main, .teaser-side-item, .about-visual-block");

  tiltCards.forEach(function (card) {
    card.addEventListener("mousemove", function (e) {
      const rect = card.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      const centerX = rect.width / 2;
      const centerY = rect.height / 2;
      const rotateX = (y - centerY) / centerY * -8;
      const rotateY = (x - centerX) / centerX * 8;

      card.style.transform = "perspective(800px) rotateX(" + rotateX + "deg) rotateY(" + rotateY + "deg) translateZ(10px)";

      // 更新光斑位置
      let glow = card.querySelector(".card-glow");
      if (!glow) {
        glow = document.createElement("div");
        glow.className = "card-glow";
        card.appendChild(glow);
      }
      glow.style.left = (x - 100) + "px";
      glow.style.top = (y - 100) + "px";
    });

    card.addEventListener("mouseleave", function () {
      card.style.transform = "perspective(800px) rotateX(0) rotateY(0) translateZ(0)";
      card.style.transition = "transform 0.6s ease";
      setTimeout(function () {
        card.style.transition = "";
      }, 600);
    });
  });

  /* ========================================
     9. 磁性按钮
     ======================================== */
  const magneticBtns = document.querySelectorAll(".btn, .nav-cta");
  magneticBtns.forEach(function (btn) {
    btn.classList.add("magnetic");

    btn.addEventListener("mousemove", function (e) {
      const rect = btn.getBoundingClientRect();
      const x = e.clientX - rect.left - rect.width / 2;
      const y = e.clientY - rect.top - rect.height / 2;
      const strength = 0.3;
      btn.style.transform = "translate(" + x * strength + "px, " + y * strength + "px)";
    });

    btn.addEventListener("mouseleave", function () {
      btn.style.transform = "translate(0, 0)";
      btn.style.transition = "transform 0.4s cubic-bezier(0.22, 1, 0.36, 1)";
      setTimeout(function () {
        btn.style.transition = "";
      }, 400);
    });
  });

  /* ========================================
     10. 文字乱序解码 (Scramble)
     ======================================== */
  const CHARS = "!<>-_\\/[]{}—=+*^?#________";
  const scrambleElements = document.querySelectorAll("[data-scramble]");

  if (scrambleElements.length > 0 && "IntersectionObserver" in window) {
    const scrambleObserver = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting && !entry.target.classList.contains("scrambled")) {
          entry.target.classList.add("scrambled");
          scrambleText(entry.target);
          scrambleObserver.unobserve(entry.target);
        }
      });
    }, { threshold: 0.5 });

    scrambleElements.forEach(function (el) {
      scrambleObserver.observe(el);
    });
  }

  function scrambleText(el) {
    const originalText = el.textContent;
    const length = originalText.length;
    let frame = 0;
    const totalFrames = length * 3;
    const revealed = new Array(length).fill(false);

    function update() {
      let output = "";
      let done = true;

      for (let i = 0; i < length; i++) {
        if (revealed[i]) {
          output += originalText[i];
          continue;
        }

        if (frame > i * 2 + Math.random() * 10) {
          revealed[i] = true;
          output += originalText[i];
        } else {
          done = false;
          output += CHARS[Math.floor(Math.random() * CHARS.length)];
        }
      }

      el.textContent = output;
      frame++;

      if (!done) {
        requestAnimationFrame(update);
      } else {
        el.textContent = originalText;
      }
    }

    requestAnimationFrame(update);
  }

  /* ========================================
     11. 视差滚动 (Orbs - 排除hero-orb避免与CSS动画冲突)
     ======================================== */
  const orbs = document.querySelectorAll(".cta-orb, .page-hero-orb");
  if (orbs.length > 0) {
    window.addEventListener("scroll", function () {
      const scrollY = window.scrollY;
      orbs.forEach(function (orb, index) {
        const speed = 0.05 + (index % 3) * 0.03;
        orb.style.transform = "translateY(" + scrollY * speed + "px)";
      });
    }, { passive: true });
  }

  /* ========================================
     11.5 编译进度条动画
     ======================================== */
  const progressFills = document.querySelectorAll(".build-progress-fill[data-progress]");
  if (progressFills.length > 0 && "IntersectionObserver" in window) {
    const progressObserver = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) {
          const fill = entry.target;
          const target = fill.getAttribute("data-progress");
          setTimeout(function () {
            fill.style.width = target + "%";
          }, 200);
          progressObserver.unobserve(fill);
        }
      });
    }, { threshold: 0.5 });
    progressFills.forEach(function (fill) {
      fill.style.width = "0%";
      progressObserver.observe(fill);
    });
  }

  /* ========================================
     11.6 失控数字滚动
     ======================================== */
  const chaosNums = document.querySelectorAll("[data-chaos-count]");
  if (chaosNums.length > 0 && "IntersectionObserver" in window) {
    const chaosObserver = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) {
          animateChaosNum(entry.target);
          chaosObserver.unobserve(entry.target);
        }
      });
    }, { threshold: 0.5 });
    chaosNums.forEach(function (el) { chaosObserver.observe(el); });
  }

  function animateChaosNum(el) {
    const target = parseFloat(el.getAttribute("data-chaos-count"));
    const decimals = el.getAttribute("data-decimals") ? parseInt(el.getAttribute("data-decimals")) : 0;
    const duration = 1600;
    let startTime = null;

    function step(timestamp) {
      if (!startTime) startTime = timestamp;
      const progress = Math.min((timestamp - startTime) / duration, 1);
      const eased = progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress);
      const current = eased * target;
      el.textContent = decimals > 0 ? current.toFixed(decimals) : Math.floor(current).toLocaleString();
      if (progress < 1) {
        requestAnimationFrame(step);
      } else {
        el.textContent = decimals > 0 ? target.toFixed(decimals) : target.toLocaleString();
      }
    }
    requestAnimationFrame(step);
  }

  /* ========================================
     12.5 KPR风格滚动场景引擎
     ======================================== */
  const scrollScenes = document.querySelectorAll(".scroll-scene");
  if (scrollScenes.length > 0) {
    const sceneData = [];
    scrollScenes.forEach(function (scene) {
      sceneData.push({
        el: scene,
        lines: scene.querySelectorAll(".scene-line"),
        pctEls: scene.querySelectorAll("[data-scene-pct]"),
        giantTexts: scene.querySelectorAll(".bg-giant-text")
      });
    });

    let sceneTicking = false;
    function updateScenes() {
      const vh = window.innerHeight;
      sceneData.forEach(function (data) {
        const rect = data.el.getBoundingClientRect();
        const scrollable = rect.height - vh;
        if (scrollable <= 0) return;
        const progress = Math.min(Math.max(-rect.top / scrollable, 0), 1);

        // 进度百分比
        const pct = Math.floor(progress * 100);
        data.pctEls.forEach(function (el) {
          el.textContent = (pct < 10 ? "0" : "") + pct + "%";
        });

        // 大字背景视差
        data.giantTexts.forEach(function (gt) {
          const shift = (progress - 0.5) * 120;
          gt.style.transform = "translate(-50%, -50%) translateX(" + shift + "px)";
        });

        // 逐行揭示
        const n = data.lines.length;
        data.lines.forEach(function (line, i) {
          const lineStart = (i / n) * 0.9;
          const lineEnd = ((i + 1) / n) * 0.9 + 0.05;
          if (progress >= lineStart && progress < lineEnd) {
            line.classList.add("active");
            line.classList.remove("exit");
          } else if (progress >= lineEnd) {
            line.classList.remove("active");
            line.classList.add("exit");
          } else {
            line.classList.remove("active", "exit");
          }
        });
      });
      sceneTicking = false;
    }

    window.addEventListener("scroll", function () {
      if (!sceneTicking) {
        requestAnimationFrame(updateScenes);
        sceneTicking = true;
      }
    }, { passive: true });
    updateScenes();
  }

  /* ========================================
     12.6 持续加密乱码(永不解码)
     ======================================== */
  const SCRAMBLE_CHARS = "01!<>-_/[]{}=+*^?#@%&$ABCDEF";
  const loopEncrypted = document.querySelectorAll("[data-scramble-loop]");
  if (loopEncrypted.length > 0) {
    const encStates = [];
    loopEncrypted.forEach(function (el) {
      const len = parseInt(el.getAttribute("data-length") || el.textContent.length, 10);
      encStates.push({ el: el, len: len });
    });

    let encFrame = 0;
    function loopScramble() {
      encFrame++;
      // 每3帧更新一次，降低频率更有"电流感"
      if (encFrame % 3 === 0) {
        encStates.forEach(function (s) {
          let out = "";
          for (let i = 0; i < s.len; i++) {
            out += SCRAMBLE_CHARS[Math.floor(Math.random() * SCRAMBLE_CHARS.length)];
          }
          s.el.textContent = out;
        });
      }
      requestAnimationFrame(loopScramble);
    }
    // 仅在视口内时运行
    const encObserver = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting && !entry.target.dataset.looping) {
          entry.target.dataset.looping = "1";
        }
      });
    });
    loopEncrypted.forEach(function (el) { encObserver.observe(el); });
    loopScramble();
  }

  /* ========================================
     12.7 数据流下落线条生成(带裁剪层,防页面弹跳)
     ======================================== */
  const streamContainers = document.querySelectorAll("[data-streams]");
  streamContainers.forEach(function (container) {
    // 裁剪层:防止线条溢出改变文档高度导致底部弹跳
    const layer = document.createElement("div");
    layer.style.cssText = "position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0";
    const count = parseInt(container.getAttribute("data-streams"), 10) || 5;
    for (let i = 0; i < count; i++) {
      const stream = document.createElement("div");
      stream.className = "data-stream";
      stream.style.left = (10 + Math.random() * 80) + "%";
      stream.style.height = (60 + Math.random() * 120) + "px";
      stream.style.animationDelay = (Math.random() * 3) + "s";
      stream.style.animationDuration = (2.5 + Math.random() * 2) + "s";
      layer.appendChild(stream);
    }
    container.insertBefore(layer, container.firstChild);
  });

  /* ========================================
     12. 联系表单
     ======================================== */
  const contactForm = document.querySelector("#contactForm");
  if (contactForm) {
    contactForm.addEventListener("submit", function (e) {
      e.preventDefault();
      const successMsg = document.querySelector(".form-success");
      if (successMsg) {
        successMsg.classList.add("show");
        successMsg.scrollIntoView({ behavior: "smooth", block: "center" });
      }
      contactForm.reset();
      setTimeout(function () {
        if (successMsg) successMsg.classList.remove("show");
      }, 6000);
    });
  }

  /* ========================================
     13. 当前页面高亮导航
     ======================================== */
  const currentPage = window.location.pathname.split("/").pop() || "index.html";
  const navLinks = document.querySelectorAll(".nav-link");
  navLinks.forEach(function (link) {
    const href = link.getAttribute("href");
    if (href === currentPage || (currentPage === "" && href === "index.html")) {
      link.classList.add("active");
    }
  });

  /* ========================================
     14. 腐化标题特效 —— 标题本身就是bug
     ======================================== */
  const corruptEl = document.querySelector(".corrupt-title[data-text]");
  if (corruptEl) {
    const original = corruptEl.getAttribute("data-text");
    const GLITCH_CHARS = "▓█◆#@$%&!?◢◤╳╱╲─│┌┐└┘01";
    // 拆分字符
    corruptEl.innerHTML = "";
    const charSpans = [];
    for (let ci = 0; ci < original.length; ci++) {
      const span = document.createElement("span");
      span.className = "corrupt-char";
      span.textContent = original[ci];
      span.setAttribute("data-orig", original[ci]);
      corruptEl.appendChild(span);
      charSpans.push(span);
    }

    const wrap = corruptEl.closest(".corrupt-wrap");

    // 持续轻微腐化: 随机字符短暂变为乱码
    setInterval(function () {
      if (Math.random() > 0.45) {
        const idx = Math.floor(Math.random() * charSpans.length);
        const span = charSpans[idx];
        span.textContent = GLITCH_CHARS[Math.floor(Math.random() * GLITCH_CHARS.length)];
        span.classList.add("glitching");
        setTimeout(function () {
          span.textContent = span.getAttribute("data-orig");
          span.classList.remove("glitching");
        }, 60 + Math.random() * 120);
      }
    }, 140);

    // 偶发重度腐化: 多个字符同时崩溃 + 屏幕震颤
    setInterval(function () {
      if (Math.random() > 0.6) {
        const burst = 2 + Math.floor(Math.random() * 3);
        for (let b = 0; b < burst; b++) {
          const span = charSpans[Math.floor(Math.random() * charSpans.length)];
          span.textContent = GLITCH_CHARS[Math.floor(Math.random() * GLITCH_CHARS.length)];
          span.classList.add("glitching");
          (function (s) {
            setTimeout(function () {
              s.textContent = s.getAttribute("data-orig");
              s.classList.remove("glitching");
            }, 120 + Math.random() * 200);
          })(span);
        }
        if (wrap) {
          wrap.classList.remove("shake");
          void wrap.offsetWidth; // 重置动画
          wrap.classList.add("shake");
        }
      }
    }, 4200);
  }
})();
