document.addEventListener("DOMContentLoaded", function () { // SP時のみ電話番号にリンク (function () { var ua = navigator.userAgent; if (ua.indexOf("iPhone") < 0 && ua.indexOf("Android") < 0) return; var nodes = document.querySelectorAll(".tel-link"); nodes.forEach(function (el) { var str = (el.textContent || "").trim(); if (!str) return; var num = str.replace(/-/g, ""); var a = document.createElement("a"); a.href = "tel:" + num; a.textContent = str; el.replaceChildren(a); }); })(); // 外部リンクを別ウィンドウ (function () { var host = location.hostname; var links = document.querySelectorAll('a[href^="https"], a[href^="http"]'); links.forEach(function (a) { try { var url = new URL(a.href); if (url.hostname && url.hostname.indexOf(host) === -1) a.target = "_blank"; } catch (e) {} }); })(); // ★ pagetop 表示/非表示(300px)+クリックで先頭へ(rAF版のみ残す) (function () { var btn = document.getElementById("PageTop"); if (!btn) return; var link = btn.querySelector("a"); var visible = false; var ticking = false; var evaluate = function () { ticking = false; var shouldShow = window.pageYOffset > 300; if (shouldShow !== visible) { visible = shouldShow; if (visible) btn.classList.add("is-show"); else btn.classList.remove("is-show"); } }; var onScroll = function () { if (!ticking) { ticking = true; requestAnimationFrame(evaluate); } }; evaluate(); window.addEventListener("scroll", onScroll, { passive: true }); if (link) { link.addEventListener("click", function (e) { e.preventDefault(); if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { window.scrollTo(0, 0); } else { window.scrollTo({ top: 0, behavior: "smooth" }); } }); } })(); // スクロールで要素を表示 (function () { var els = document.getElementsByClassName("js-animation"); if (!els || !els.length) return; var showTiming = window.innerHeight > 768 ? 200 : 40; var onScroll = function () { var scrollY = window.pageYOffset; var windowH = window.innerHeight; for (var i = 0; i < els.length; i++) { var rect = els[i].getBoundingClientRect(); var elemY = scrollY + rect.top; if (scrollY + windowH - showTiming > elemY) { els[i].classList.add("is-show"); } else if (scrollY + windowH < elemY) { els[i].classList.remove("is-show"); } } }; onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); window.addEventListener("resize", onScroll); })(); // Mainvisual:スクロールでブラー/減彩/減光 + scroll_downフェード (function () { var mv = document.getElementById("Mainvisual"); if (!mv) return; var img = mv.querySelector("picture img"); var scrollDown = mv.querySelector(".scroll_down"); if (!img) return; var maxBlur = 10; var maxDesat = 0.85; var minBrightness = 0.9; var ticking = false; var clamp = function (v, min, max) { return Math.max(min, Math.min(max, v)); }; // 進行度:メインビジュアルの上端がビューポート上端を越え始めたら0→1で増加 var calcProgress = function () { var rect = mv.getBoundingClientRect(); // rect.top が 0(画面上端)→ -rect.height(全て通過)で変化 var p = clamp(-rect.top / (rect.height || 1), 0, 1); // 微小な負値ガタつき対策 if (p < 0.001) p = 0; return p; }; var apply = function (progress) { var blur = progress * maxBlur; var sat = 1 - progress * (1 - maxDesat); var bright = 1 - progress * (1 - minBrightness); img.style.filter = "blur(" + blur.toFixed(2) + "px) saturate(" + sat.toFixed(3) + ") brightness(" + bright.toFixed(3) + ")"; if (scrollDown) scrollDown.style.opacity = String(1 - progress); }; var update = function () { ticking = false; apply(calcProgress()); }; var onScroll = function () { if (!ticking) { ticking = true; requestAnimationFrame(update); } }; // 初期は必ずブラー0で描画 → 次フレームで計算反映 img.style.filter = "none"; if (scrollDown) scrollDown.style.opacity = "1"; // 画像ロードやレイアウト確定後に初回評価 var init = function () { requestAnimationFrame(update); }; if (document.readyState === "complete") { init(); } else { window.addEventListener("load", init, { once: true }); requestAnimationFrame(init); // 早い環境でも保険 } window.addEventListener("scroll", onScroll, { passive: true }); window.addEventListener("resize", onScroll); window.addEventListener("orientationchange", onScroll); })(); });