(function(){
// ─── 赤原式ヒートマップ計測スクリプト v2 (Phase L) ───────────────────────────
var VID='v_1794779053847_v0w89bi';
var PAGE_ID=6150005;
var FUNNEL_ID=2640003;
var CHANNEL=null;
var PAGE_TYPE='homepage';
var BASE=window.location.origin;
var TL=null;
var VISIT_ID="av_tbHt63rIqlKq_l0pO8n1wjQW";
var ATTRIBUTION_PROOF="eyJ2ZXJzaW9uIjoxLCJ2aXNpdG9ySWQiOiJ2XzE3OTQ3NzkwNTM4NDdfdjB3ODliaSIsInZpc2l0SWQiOiJhdl90Ykh0NjNySXFsS3FfbDBwTzhuMXdqUVciLCJ0cmFja2luZ1Rva2VuIjpudWxsLCJmdW5uZWxJZCI6MjY0MDAwMywicGFnZUlkIjo2MTUwMDA1LCJjaGFubmVsIjpudWxsLCJleHBpcmVzQXQiOjE3OTQ3ODA4NjExMDd9.Uy9htV6OuNGlNp9oIgXJKpf3Or2wrfLaN0475fQjTZ4";
var EXTERNAL_ATTRIBUTION_PROOF="eyJ2ZXJzaW9uIjoxLCJ2aXNpdG9ySWQiOiJ2XzE3OTQ3NzkwNTM4NDdfdjB3ODliaSIsInZpc2l0SWQiOiJhdl90Ykh0NjNySXFsS3FfbDBwTzhuMXdqUVciLCJ0cmFja2luZ1Rva2VuIjpudWxsLCJmdW5uZWxJZCI6MjY0MDAwMywicGFnZUlkIjo2MTUwMDA1LCJjaGFubmVsIjpudWxsLCJleHBpcmVzQXQiOjE3OTczNzEwNjExMDh9.pA-APdSuZe3tHdMGGtOGV-j8E0VEfhnEPinaK-RYKpg";
var ATTRIBUTION_EXPIRES_AT=1794780861107;
var CONSENT_REQUIRED=false;
var CONSENT_NOTICE="アクセス解析とサービス改善のため、匿名化した閲覧情報を利用します。";
var CONSENT_KEY='funnelia_tracking_consent_'+PAGE_ID;
var trackingAllowed=!CONSENT_REQUIRED||localStorage.getItem(CONSENT_KEY)==='granted';
function updateAnalyticsConsent(granted){if(typeof window.gtag==='function'){window.gtag('consent','update',{analytics_storage:granted?'granted':'denied'});}}
function showConsentBanner(){
if(!CONSENT_REQUIRED||localStorage.getItem(CONSENT_KEY))return;
var box=document.createElement('div');box.setAttribute('role','dialog');box.setAttribute('aria-label','計測に関する選択');box.style.cssText='position:fixed;z-index:2147483647;left:16px;right:16px;bottom:16px;max-width:680px;margin:auto;padding:16px;background:#111827;color:#fff;border-radius:12px;box-shadow:0 12px 36px rgba(0,0,0,.3);font:14px/1.6 system-ui,sans-serif';
var text=document.createElement('p');text.textContent=CONSENT_NOTICE;text.style.margin='0 0 12px';
var actions=document.createElement('div');actions.style.cssText='display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap';
var decline=document.createElement('button');decline.type='button';decline.textContent='利用しない';decline.style.cssText='padding:8px 12px;border:1px solid #9ca3af;background:transparent;color:#fff;border-radius:7px;cursor:pointer';
var accept=document.createElement('button');accept.type='button';accept.textContent='同意して利用する';accept.style.cssText='padding:8px 12px;border:0;background:#2563eb;color:#fff;border-radius:7px;cursor:pointer';
decline.onclick=function(){localStorage.setItem(CONSENT_KEY,'denied');trackingAllowed=false;updateAnalyticsConsent(false);box.remove();};
accept.onclick=function(){localStorage.setItem(CONSENT_KEY,'granted');trackingAllowed=true;updateAnalyticsConsent(true);box.remove();propagateAttribution();trackPageView();};
actions.appendChild(decline);actions.appendChild(accept);box.appendChild(text);box.appendChild(actions);document.body.appendChild(box);
}
function readGaClientId(){var match=document.cookie.match(/(?:^|;\s*)_ga=GA\d+\.\d+\.(\d+\.\d+)/);return match?match[1]:null;}
var GA4_CLIENT_ID=readGaClientId();
// セッションID生成(タブごとにユニーク)
var SESS_ID='sess_'+Date.now()+'_'+Math.random().toString(36).slice(2,9);
function attribution(){return {visitorId:VID,visitId:VISIT_ID,trackingToken:TL,attributionProof:ATTRIBUTION_PROOF,attributionExpiresAt:ATTRIBUTION_EXPIRES_AT,pageId:PAGE_ID,funnelId:FUNNEL_ID,channel:CHANNEL,ga4ClientId:GA4_CLIENT_ID};}
function appendAttribution(url){
try{var target=new URL(url,window.location.href);if(target.origin!==window.location.origin)return url;target.searchParams.set('vid',VISIT_ID);target.searchParams.set('ap',ATTRIBUTION_PROOF);if(TL)target.searchParams.set('tl',TL);return target.toString();}catch(_){return url;}
}
function setHidden(form,name,value){
var field=form.querySelector('input[name="'+name+'"]');
if(!field){field=document.createElement('input');field.type='hidden';field.name=name;form.appendChild(field);}
field.value=value;
}
function propagateAttribution(){
document.querySelectorAll('a[href]').forEach(function(anchor){var href=anchor.getAttribute('href');if(href)anchor.setAttribute('href',appendAttribution(href));});
document.querySelectorAll('form').forEach(function(form){setHidden(form,'fvid',VID);setHidden(form,'vid',VISIT_ID);setHidden(form,'ap',ATTRIBUTION_PROOF);setHidden(form,'apx',EXTERNAL_ATTRIBUTION_PROOF);if(TL)setHidden(form,'tl',TL);});
}
// UTMパラメータ抽出
var urlParams=new URLSearchParams(window.location.search);
var UTM_SOURCE=urlParams.get('utm_source')||'';
var UTM_MEDIUM=urlParams.get('utm_medium')||'';
var UTM_CAMPAIGN=urlParams.get('utm_campaign')||'';
// 100分割スクロール深度配列(各インデックス = 1%帯域の滞在秒数)
var depthArray=new Array(100).fill(0);
var lastDepthIdx=0;
var lastTick=Date.now();
var maxScroll=0;
var pageStartTime=Date.now();
var prevDepthArray=new Array(100).fill(0);
// 現在のスクロール深度インデックス(0-99)を返す
function getDepthIdx(){
var scrollH=Math.max(document.body.scrollHeight,1);
var viewH=window.innerHeight;
var scrollY=window.scrollY||window.pageYOffset||0;
var pct=Math.min(99,Math.round(scrollY/Math.max(scrollH-viewH,1)*99));
return pct;
}
// 5秒ごとに深度配列を差分送信
function tickDepth(){
var now=Date.now();
var elapsed=(now-lastTick)/1000;
lastTick=now;
var idx=getDepthIdx();
lastDepthIdx=idx;
depthArray[idx]=(depthArray[idx]||0)+elapsed;
var ms=Math.round(window.scrollY/Math.max(document.body.scrollHeight-window.innerHeight,1)*100);
if(ms>maxScroll)maxScroll=ms;
}
// 差分配列を計算して送信
function sendScrollDiff(){
if(!trackingAllowed)return;
tickDepth();
var diff=depthArray.map(function(v,i){return Math.round((v-(prevDepthArray[i]||0))*10)/10;});
var hasData=diff.some(function(v){return v>0;});
if(!hasData)return;
prevDepthArray=depthArray.slice();
fetch(BASE+'/api/track/scroll',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify(Object.assign({sessionId:SESS_ID,depthArray:diff,maxScroll:maxScroll},attribution()))}).catch(function(){});
}
// 5秒インターバルで差分送信
var scrollInterval=setInterval(sendScrollDiff,5000);
// スクロールイベントで深度追跡
window.addEventListener('scroll',function(){
var idx=getDepthIdx();
if(idx!==lastDepthIdx){
var now=Date.now();
var elapsed=(now-lastTick)/1000;
lastTick=now;
depthArray[lastDepthIdx]=(depthArray[lastDepthIdx]||0)+elapsed;
lastDepthIdx=idx;
}
var ms=Math.round(window.scrollY/Math.max(document.body.scrollHeight-window.innerHeight,1)*100);
if(ms>maxScroll)maxScroll=ms;
},{passive:true});
// ページビュー記録
function trackPageView(){
if(!trackingAllowed)return;
fetch(BASE+'/api/track',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify(Object.assign({eventType:'pageview',referrer:document.referrer||''},attribution()))}).catch(function(){});
// セッション初期化
fetch(BASE+'/api/track/session',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify(Object.assign({sessionId:SESS_ID,utmSource:UTM_SOURCE,utmMedium:UTM_MEDIUM,utmCampaign:UTM_CAMPAIGN,referrer:document.referrer||''},attribution()))}).catch(function(){});
}
// クリック記録
document.addEventListener('click',function(e){
if(!trackingAllowed)return;
var xPct=Math.round(e.clientX/window.innerWidth*10000)/100;
var yPct=Math.round((e.clientY+window.scrollY)/Math.max(document.body.scrollHeight,1)*10000)/100;
var scrollDepth=Math.round(window.scrollY/Math.max(document.body.scrollHeight-window.innerHeight,1)*10000)/100;
fetch(BASE+'/api/heatmap',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify(Object.assign({xPct:xPct,yPct:yPct,scrollDepth:scrollDepth,eventType:'click'},attribution()))}).catch(function(){});
},true);
// 離脱イベント(sendBeacon使用)
window.addEventListener('beforeunload',function(){
if(!trackingAllowed)return;
clearInterval(scrollInterval);
tickDepth();
var totalTime=Math.round((Date.now()-pageStartTime)/1000);
var payload=JSON.stringify(Object.assign({sessionId:SESS_ID,exitDepth:maxScroll,totalTime:totalTime},attribution()));
if(navigator.sendBeacon){
navigator.sendBeacon(BASE+'/api/track/exit',new Blob([payload],{type:'application/json'}));
}else{
fetch(BASE+'/api/track/exit',{method:'POST',headers:{'Content-Type':'application/json'},body:payload,keepalive:true}).catch(function(){});
}
});
// サンクスページ検出 → 成約イベント送信
if(PAGE_TYPE==='thanks'||window.location.pathname.indexOf('thanks')!==-1||window.location.search.indexOf('thanks')!==-1){
if(trackingAllowed){
fetch(BASE+'/api/track/convert',{method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify(Object.assign({sessionId:SESS_ID},attribution()))}).catch(function(){});
}
}
// DOM準備完了後にページビュー記録
document.addEventListener('submit',function(){
propagateAttribution();
if(!trackingAllowed)return;
fetch(BASE+'/api/track',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(Object.assign({eventType:'form_submit',referrer:document.referrer||''},attribution()))}).catch(function(){});
},true);
if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',function(){if(trackingAllowed){propagateAttribution();trackPageView();}else{updateAnalyticsConsent(false);showConsentBanner();}});}else{if(trackingAllowed){propagateAttribution();trackPageView();}else{updateAnalyticsConsent(false);showConsentBanner();}}
})();