<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Eden³ Gear-Clock — v9.16b (Tolerance toggle + arcs • Fix #41)</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<style>
:root{
--bg:#0b1220;--ink:#e5e7eb;--mut:#94a3b8;--panel:#0f172a;--line:#1f2937;
--accent:#22d3ee;--gold:#fbbf24;--goldDark:#78350f;--silver:#cbd5e1;
--kn1:#f59e0b;--kn2:#0ea5e9;--hist:#fbbf24;
--futureG:#16a34a;--futureGd:#166534;--futureR:#dc2626;--futureRd:#991b1b;
}
html,body{height:100%}
body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--ink)}
header{background:#0e7490;color:#fff;padding:10px 14px}
h1{font-size:16px;margin:0}.sub{font-size:12px;color:#bae6fd}
main{display:grid;grid-template-columns:360px 540px 1fr;gap:10px;padding:10px;max-width:2400px;margin:0 auto}
#eventPanel,#panel{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:12px;height:88vh;overflow:auto}
#vizWrap{background:#111827;border:1px solid var(--line);border-radius:10px;padding:2px;display:flex;align-items:center;justify-content:center;overflow:visible}
#viz{width:100%;height:88vh;max-height:980px;touch-action:none;cursor:crosshair;display:block}
.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
input[type=range]{width:320px}
.pill{display:inline-block;background:#0b1220;border:1px solid #334155;border-radius:999px;padding:2px 8px;font-size:12px}
.buttonRow button, .inputRow button, .row button{background:#0369a1;color:#fff;border:0;border-radius:8px;padding:6px 10px;cursor:pointer}
.inputRow input{width:160px;background:#0b1220;border:1px solid #334155;color:#e5e7eb;border-radius:8px;padding:6px}
.legend{border-top:1px solid #233046;padding-top:6px;font-size:12px;color:#cbd5e1}
.legend .row{gap:8px}
.legend .sw{display:inline-block;width:12px;height:12px;vertical-align:middle;margin-right:6px;border-radius:2px}
.sw.gold{background:var(--gold);border:1px solid var(--goldDark)}
.sw.silver{background:var(--silver);border:1px solid #64748b}
.sw.kn1{background:var(--kn1)}
.sw.kn2{background:var(--kn2)}
.sw.hist{background:var(--hist);border:1px solid var(--goldDark)}
.sw.futureG{background:var(--futureG);border:1px solid var(--futureGd)}
.sw.futureR{background:var(--futureR);border:1px solid var(--futureRd)}
.sw.core{background:#e5e7eb;border:1px solid #9ca3af}
.ringLabel{fill:#e5e7eb;font-size:10px;text-anchor:middle}
.numLabel{fill:#f59e0b;font-size:10px;font-weight:700}
.diamond{fill:var(--gold);stroke:var(--goldDark);stroke-width:1}
.near{fill:var(--silver);opacity:.85}
.histRect{fill:var(--hist);stroke:var(--goldDark);stroke-width:1.3;rx:1.6}
.knockLine1{stroke:var(--kn1);stroke-width:1.6}
.knockLine2{stroke:var(--kn2);stroke-width:1.6}
.leader{stroke:#6b7280;stroke-width:0.9;opacity:0.9}
.clickable{cursor:pointer}
/* Left list */
#eventPanel h2{margin:0 0 8px 0;font-size:14px}
#eventList{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:4px}
#eventList li{border:1px solid #334155;border-radius:8px;padding:6px 8px;background:#0b1220;color:#e5e7eb;display:flex;gap:8px;align-items:center;cursor:pointer}
#eventList li.active{outline:2px solid #f59e0b;background:#0a192f}
.badge{background:#1f2937;color:#f59e0b;border:1px solid #f59e0b;border-radius:6px;font-weight:700;font-size:12px;padding:2px 6px;min-width:26px;text-align:center}
.name{font-size:13px;flex:1}
.tag{font-size:11px;border:1px solid #374151;background:#0a192f;border-radius:999px;padding:1px 6px;color:#a7f3d0}
.sep{margin:8px 0;border-top:1px dashed #334155}
/* Cog styling */
.tooth{stroke:#475569;stroke-width:1}
.cogCircle{stroke:#64748b;stroke-width:1.2;fill:none}
/* Footnote */
.foot{margin-top:8px;padding:8px;border:1px dashed #334155;border-radius:8px;background:#0b1220;color:#9ca3af;font-size:12px;line-height:1.35}
.foot .mode{display:flex;gap:10px;align-items:center;margin-top:6px}
.arcNeutral{stroke:#94a3b8;stroke-width:3;opacity:.35;fill:none}
.arcGreen{stroke:#16a34a;stroke-width:3;opacity:.35;fill:none}
.arcRed{stroke:#dc2626;stroke-width:3;opacity:.35;fill:none}
</style>
</head>
<body>
<header>
<h1>Eden³ Gear-Clock — <span class="sub">v9.16b • Tolerance toggle + arcs • Fix #41</span></h1>
</header>
<main>
<aside id="eventPanel">
<h2>Core + Revelation Events</h2>
<ol id="eventList"></ol>
</aside>
<aside id="panel">
<div class="row">
<label>t (since Creation):</label>
<input id="slider" type="range" min="0" max="7000" step="0.1" value="4033.5"/>
<span id="tLabel" class="pill">4033.5</span>
<span id="eraLabel" class="pill">AD 33.5</span>
<span id="cycleLabel" class="pill">Cycle 1</span>
</div>
<div class="row">
<button id="nowBtn">Now</button>
<button id="resBtn">Resurrection</button>
<button id="startBtn">Start (0)</button>
<button id="endBtn">End (7000)</button>
<button id="forceRedraw">Force redraw</button>
</div>
<div class="row">
<button class="jump" data-delta="-2000">-2000</button>
<button class="jump" data-delta="-1000">-1000</button>
<button class="jump" data-delta="1000">+1000</button>
<button class="jump" data-delta="2000">+2000</button>
</div>
<div class="inputRow">
<label for="calInput">Calendar year (AD / negative for BC):</label>
<input id="calInput" type="number" step="0.1" value="2025"/>
<button id="calGo">Go</button>
<span class="pill">Astronomical: 0 = 1 BC</span>
</div>
<div class="row"><label><input id="toggleCore42" type="checkbox" checked/> core 42</label></div>
<div class="row"><label><input id="toggleFuture" type="checkbox" checked/> revelation/future</label></div>
<div class="row"><label><input id="toggleHistorical" type="checkbox" checked/> historical pins</label></div>
<div class="row"><label><input id="toggleBeats" type="checkbox" checked/> gate–veil locks</label></div>
<div class="row"><label><input id="toggleKnocks" type="checkbox" checked/> classic knocks</label></div>
<div class="row"><label><input id="toggleNear" type="checkbox" checked/> near-locks</label></div>
<div class="legend">
<div style="font-weight:700;margin-bottom:6px">Legend</div>
<div class="row"><span class="sw gold"></span>Gate–Veil locks (gold diamonds)</div>
<div class="row"><span class="sw silver"></span>Near‑locks cloud (silver)</div>
<div class="row"><span class="sw kn1"></span>Knock 1 (orange)</div>
<div class="row"><span class="sw kn2"></span>Knock 2 (blue)</div>
<div class="row"><span class="sw hist"></span>Historical (gold rectangles)</div>
<div class="row"><span class="sw core"></span>Core 42 (white dots + orange numbers)</div>
<div class="row"><span class="sw futureG"></span>Future (green squares)</div>
<div class="row"><span class="sw futureR"></span>Future (red squares)</div>
<div class="foot">
<div><strong>Footnote on tolerance</strong>: Default window <em>±8.4y</em> (Δθ ≤ 0.035 rad). Tight: <em>±4.8y</em> (0.02). Loose: <em>±11.9y</em> (0.05). Knock lines are ~8–12y and ~2–4y pre‑event. All windows slide if the Resurrection anchor shifts.</div>
<div class="mode">
<span>Window:</span>
<label><input type="radio" name="tol" value="tight"> Tight</label>
<label><input type="radio" name="tol" value="normal" checked> Normal</label>
<label><input type="radio" name="tol" value="loose"> Loose</label>
</div>
</div>
</div>
</aside>
<div id="vizWrap"><svg id="viz" viewBox="0 0 1200 1200" preserveAspectRatio="xMidYMid meet"></svg></div>
</main>
<script>(function(){
var W=1200,H=1200,CX=W/2,CY=H/2,rTimeline=520;
var P_G=1000,P_V=600,P_L=850;
var svg=document.getElementById('viz');
function makeEl(n,a,p){var e=document.createElementNS('http://www.w3.org/2000/svg',n);for(var k in a)e.setAttribute(k,String(a[k]));(p||svg).appendChild(e);return e;}
function makeText(x,y,txt,cls,p){var t=document.createElementNS('http://www.w3.org/2000/svg','text');t.setAttribute('x',x);t.setAttribute('y',y);t.setAttribute('text-anchor','middle');t.setAttribute('class',cls||'label');t.textContent=txt;(p||svg).appendChild(t);return t;}
function polar(th,r){return [CX+r*Math.cos(th), CY-r*Math.sin(th)];}
function tWrap(t){return ((t%7000)+7000)%7000;}
function tToTheta(t){return (1-(tWrap(t)/7000))*2*Math.PI;}
function ang(t,P){return 2*Math.PI*(t%P)/P;}
function eraText(t){var y=Math.round(t-4000);return (y>=1?('AD '+y):(y===0?'1 BC':((-y+1)+' BC')));}
function cycleText(t){return "Cycle "+(Math.floor(t/7000)+1);}
function calendarToT(y){return y+4000;}
// Tolerance state
var tolRad=0.035; // normal
function setTol(mode){
tolRad = mode==='tight'? 0.02 : mode==='loose'? 0.05 : 0.035;
refreshOverlays();
}
Array.from(document.querySelectorAll('input[name="tol"]')).forEach(r=>{
r.addEventListener('change', ()=> setTol(r.value));
});
// Layers
var cogLayer=makeEl('g',{},svg);
var ringsLayer=makeEl('g',{},svg);
var arcLayer =makeEl('g',{},svg); // tolerance arcs
var overlayLayer=makeEl('g',{},svg);
var handLayer=makeEl('g',{},svg);
var numLayer=makeEl('g',{},svg);
// Cogs with teeth
var cogPeriods=[7,12,21,40,50,70,72,120,144,490,1000,1260,1335,2300,7000,144000];
var cogs=[];
function drawCogs(){
while(cogLayer.firstChild) cogLayer.removeChild(cogLayer.firstChild);
cogs=[];
for(var i=0;i<cogPeriods.length;i++){
var P=cogPeriods[i], r=180+i*18;
var g=makeEl('g',{'data-P':P},cogLayer);
makeEl('circle',{cx:CX,cy:CY,r:r,class:'cogCircle'},g);
var teeth= P<=144? P: 72;
for(var j=0;j<teeth;j++){
var th=2*Math.PI*j/teeth, p1=polar(th,r-3), p2=polar(th,r+3);
makeEl('line',{x1:p1[0],y1:p1[1],x2:p2[0],y2:p2[1],class:'tooth'},g);
}
var p=polar(-Math.PI/2,r+10);
makeText(p[0],p[1], 'P='+P,'ringLabel', g);
cogs.push({P:P,r:r,g:g});
}
}
drawCogs();
// 7x rings + outer timeline
var gatesGroup,veilsGroup,layersGroup;
function buildSeven(radius,prefix,color){
var g=makeEl('g',{},ringsLayer);
makeEl('circle',{cx:CX,cy:CY,r:radius,stroke:color,'stroke-width':1.4,fill:'none'},g);
for(var i=0;i<7;i++){
var th=i*2*Math.PI/7,p1=polar(th,radius-6),p2=polar(th,radius+6);
makeEl('line',{x1:p1[0],y1:p1[1],x2:p2[0],y2:p2[1],stroke:color,'stroke-width':1.2},g);
var p=polar(th,radius+16); makeText(p[0],p[1],prefix+(i+1),'ringLabel',g);
}
return g;
}
function drawRings(){
while(ringsLayer.firstChild) ringsLayer.removeChild(ringsLayer.firstChild);
makeEl('circle',{cx:CX,cy:CY,r:rTimeline,stroke:'#e5e7eb','stroke-width':1.8,fill:'none'},ringsLayer);
makeText(CX,42,'0 → 7000 timeline','ringLabel',ringsLayer);
gatesGroup=buildSeven(350,'G','#60a5fa');
veilsGroup=buildSeven(400,'V','#a78bfa');
layersGroup=buildSeven(450,'L','#f87171');
}
drawRings();
// Overlays
var beatsLayer=makeEl('g',{},overlayLayer);
var nearLayer =makeEl('g',{},overlayLayer);
var coreLayer =makeEl('g',{},overlayLayer);
var pinsLayer =makeEl('g',{},overlayLayer);
var histLayer =makeEl('g',{},overlayLayer);
var knocksLayer=makeEl('g',{},overlayLayer);
var todayLayer=makeEl('g',{},overlayLayer);
var coreEvents=[
{"label":"1. Creation (G1)","t":0.0},{"label":"2. Fall","t":1.0},{"label":"3. Cain & Abel","t":130.0},
{"label":"4. Enoch Taken","t":987.0},{"label":"5. Noah Born","t":1056.0},{"label":"6. Flood (G2)","t":1656.0},
{"label":"7. Noahic Covenant","t":1657.0},{"label":"8. Babel (G3)","t":1757.0},{"label":"9. Call of Abram","t":2083.0},
{"label":"10. Abrahamic Covenant","t":2084.0},{"label":"11. Isaac Born","t":2108.0},{"label":"12. Jacob → Israel","t":2199.0},
{"label":"13. Joseph in Egypt","t":2298.0},{"label":"14. Israel Enters Egypt","t":2315.0},{"label":"15. Oppression","t":2400.0},
{"label":"16. Exodus","t":2513.0},{"label":"17. Sinai / Law (G4)","t":2513.5},{"label":"18. Tabernacle","t":2514.0},
{"label":"19. Jordan Crossing","t":2553.0},{"label":"20. Conquest","t":2563.0},{"label":"21. Judges","t":2583.0},
{"label":"22. Saul","t":2909.0},{"label":"23. Davidic Covenant","t":2949.0},{"label":"24. Solomon","t":2989.0},
{"label":"25. First Temple","t":3009.0},{"label":"26. Kingdom Divided","t":3033.0},{"label":"27. Elijah–Elisha","t":3100.0},
{"label":"28. Assyrian Exile","t":3283.0},{"label":"29. Josiah Reforms","t":3370.0},{"label":"30. Babylon Exile/Temple Down","t":3416.0},
{"label":"31. Return under Cyrus","t":3468.0},{"label":"32. Second Temple","t":3490.0},{"label":"33. Ezra–Nehemiah","t":3530.0},
{"label":"34. Intertestamental","t":3650.0},{"label":"35. Birth of Christ","t":4000.0},{"label":"36. Ministry","t":4029.0},
{"label":"37. Cross & Resurrection (G5)","t":4033.5},{"label":"38. Pentecost (G6)","t":4033.6369},
{"label":"39. Jerusalem 70 AD","t":4070.0},{"label":"40. Revelation to John","t":4097.0},
{"label":"41. Tribulation Window","t":5930.0}, /* FIXED from 6900 → 5930 */
{"label":"42. New Creation (G7)","t":7000.0}
];
var futurePins=[
{"label":"Sealing 144k (future)","t":5960.0,"tone":"green","tag":"Rev"},
{"label":"Two Witnesses Begin (future)","t":5970.0,"tone":"green","tag":"Rev"},
{"label":"Trumpets Window (future)","t":5980.0,"tone":"red","tag":"Rev"},
{"label":"Two Witnesses Ascend (future)","t":5993.0,"tone":"green","tag":"Rev"},
{"label":"Bowls Window (future)","t":6000.0,"tone":"red","tag":"Rev"},
{"label":"Fall of Babylon (future)","t":6015.0,"tone":"red","tag":"Rev"},
{"label":"Gathering in Clouds (future)","t":6020.0,"tone":"green","tag":"Rev"},
{"label":"Return / Armageddon (future)","t":6030.0,"tone":"red","tag":"Rev"},
{"label":"Millennial Reign (ongoing)","t":6500.0,"tone":"green","tag":"Rev"},
{"label":"Great White Throne (future)","t":6995.0,"tone":"red","tag":"Rev"},
{"label":"New Jerusalem (future)","t":7000.0,"tone":"green","tag":"Rev"}
];
var historicalPins=[
{"label":"Israel re-established (1948)","t":5948.0,"tag":"Hist"},
{"label":"Jerusalem reunified (1967)","t":5967.0,"tag":"Hist"}
];
function clearLayer(g){while(g.firstChild)g.removeChild(g.firstChild);}
// Tolerance arcs for future pins
var arcLayer = document.querySelector('#viz g:nth-of-type(3)') || makeEl('g',{},svg);
function arcPath(r, th1, th2){
// small arc from th1 to th2 in screen coordinates (SVG uses CW from +x; we use CCW from +x inverted Y)
var p1=polar(th1, r), p2=polar(th2, r);
var large = Math.abs(th2-th1) > Math.PI ? 1 : 0;
var sweep = (th2>th1)? 0:1; // adjust for our theta orientation
return "M "+p1[0]+" "+p1[1]+" A "+r+" "+r+" 0 "+large+" "+sweep+" "+p2[0]+" "+p2[1];
}
function drawArcs(){
while(arcLayer.firstChild) arcLayer.removeChild(arcLayer.firstChild);
var tolYears = tolRad * (7000/(2*Math.PI)); // convert angle to years in Gate/Veil frame approx
for(var i=0;i<futurePins.length;i++){
var f=futurePins[i];
var t1 = f.t - tolYears, t2 = f.t + tolYears;
var th1=tToTheta(t2), th2=tToTheta(t1); // reversed since theta decreases as t increases
var cls = f.tone==='green' ? 'arcGreen' : 'arcRed';
var path = makeEl('path', {d: arcPath(rTimeline, th1, th2), class: cls}, arcLayer);
}
}
// Overlays logic (respect tolRad)
function angErr(t){var aG=ang(t,1000), aV=ang(t,600); var d=Math.abs(aG-aV); return Math.min(d, 2*Math.PI - d);}
function isNearBeat(t){return angErr(t) < tolRad;}
function priorKnocks(tEv, maxBack, maxCount){
var out=[], step=0.5;
for(var dt=step; dt<=maxBack && out.length<maxCount; dt+=step){
var cand=tEv-dt; if(cand<0) break;
if(isNearBeat(cand)){ if(out.length===0 || Math.abs(out[out.length-1]-cand)>2.0) out.push(cand); }
}
return out;
}
function drawBeatsLayer(){
clearLayer(beatsLayer);
if(!document.getElementById('toggleBeats').checked) return;
for(var t=0; t<=7000; t+=3000){
var th=tToTheta(t); var p=polar(th,470);
var sz=7, d=`M ${p[0]} ${p[1]-sz} L ${p[0]+sz} ${p[1]} L ${p[0]} ${p[1]+sz} L ${p[0]-sz} ${p[1]} Z`;
makeEl('path',{d:d, class:'diamond'},beatsLayer);
}
}
function drawNearLayer(){
clearLayer(nearLayer);
if(!document.getElementById('toggleNear').checked) return;
for(var tt=0; tt<=7000; tt+=10){
if(isNearBeat(tt) && (tt%3000)>50){
var th2=tToTheta(tt); var q=polar(th2,475);
makeEl('circle',{cx:q[0],cy:q[1],r:3, class:'near'},nearLayer);
}
}
}
function drawKnocksLayer(){
clearLayer(knocksLayer);
if(!document.getElementById('toggleKnocks').checked) return;
var allSets=[].concat(coreEvents, futurePins, historicalPins);
for(var i=0;i<allSets.length;i++){
var ev=allSets[i];
var knocks=priorKnocks(ev.t, 200, 2);
for(var k=0;k<knocks.length;k++){
var th=tToTheta(knocks[k]);
var r1=rTimeline-26, r2=rTimeline+10;
var A=polar(th,r1), B=polar(th,r2);
makeEl('line',{x1:A[0],y1:A[1],x2:B[0],y2:B[1],class:(k===0?'knockLine1':'knockLine2')},knocksLayer);
}
}
}
function drawTodayPin(){
clearLayer(todayLayer);
var y=new Date().getFullYear();
var t=calendarToT(y);
var th=tToTheta(t), q=polar(th, rTimeline-12);
makeEl('circle',{cx:q[0],cy:q[1],r:5,fill:'#22d3ee',stroke:'#075985','stroke-width':1.5}, todayLayer);
}
function makeClickable(el, fn){ el.classList.add('clickable'); el.addEventListener('click', fn); }
// Core dots with numbers
function drawCoreLayer(){
clearLayer(coreLayer); clearLayer(numLayer);
if(!document.getElementById('toggleCore42').checked) return;
for(var i=0;i<coreEvents.length;i++){
(function(i){
var ev=coreEvents[i], th=tToTheta(ev.t), p=polar(th,rTimeline);
var dot=makeEl('circle',{cx:p[0],cy:p[1],r:(ev.t===4000?6:4),fill:'#e5e7eb'},coreLayer);
if(ev.t===4033.5){
makeEl('circle',{cx:p[0],cy:p[1],r:12,fill:'none',stroke:varGold(),'stroke-width':3,opacity:.6},coreLayer);
makeEl('line',{x1:p[0]-6,y1:p[1],x2:p[0]+6,y2:p[1],stroke:varGold(),'stroke-width':2},coreLayer);
makeEl('line',{x1:p[0],y1:p[1]-6,x2:p[0],y2:p[1]+6,stroke:varGold(),'stroke-width':2},coreLayer);
}
var q=polar(th, rTimeline+16);
var num=makeText(q[0], q[1], String(i+1), 'numLabel', numLayer);
makeClickable(dot, function(){ jumpTo(ev.t, 'core', i); });
makeClickable(num, function(){ jumpTo(ev.t, 'core', i); });
})(i);
}
}
function varGold(){ return getComputedStyle(document.documentElement).getPropertyValue('--gold')||'#fbbf24'; }
// Future pins
function drawPinsLayer(){
clearLayer(pinsLayer);
if(!document.getElementById('toggleFuture').checked) return;
for(var j=0;j<futurePins.length;j++){
(function(j){
var f=futurePins[j], th=tToTheta(f.t), q=polar(th,rTimeline);
var rect=makeEl('rect',{x:q[0]-4,y:q[1]-4,width:8,height:8,rx:1.6},pinsLayer);
rect.setAttribute('fill', f.tone==='green'?'#16a34a':'#dc2626');
rect.setAttribute('stroke', f.tone==='green'?'#166534':'#991b1b');
makeClickable(rect, function(){ jumpTo(f.t, 'rev', j); });
})(j);
}
}
// Historical pins
function drawHistoricalLayer(){
clearLayer(histLayer);
if(!document.getElementById('toggleHistorical').checked) return;
for(var k=0;k<historicalPins.length;k++){
(function(k){
var h=historicalPins[k], th=tToTheta(h.t), q=polar(th, rTimeline);
var rect=makeEl('rect',{x:q[0]-5,y:q[1]-5,width:10,height:10,rx:1.8, class:'histRect'},histLayer);
makeClickable(rect, function(){ jumpTo(h.t, 'hist', k); });
})(k);
}
}
function refreshOverlays(){
drawArcs();
drawBeatsLayer(); drawNearLayer();
drawCoreLayer(); drawPinsLayer(); drawHistoricalLayer();
drawKnocksLayer(); drawTodayPin();
}
// Hand
function buildHand(){ while(handLayer.firstChild) handLayer.removeChild(handLayer.firstChild); return makeEl('line',{x1:CX,y1:CY,x2:CX,y2:CY-rTimeline,stroke:'#e5e7eb','stroke-width':1.8},handLayer); }
var hand=buildHand();
// Left list
var listEl=document.getElementById('eventList');
function buildUnifiedList(){
listEl.innerHTML='';
// Core
for(var i=0;i<coreEvents.length;i++){
var li=document.createElement('li'); li.dataset.kind='core'; li.dataset.idx=String(i);
var badge=document.createElement('span'); badge.className='badge'; badge.textContent=String(i+1);
var name=document.createElement('span'); name.className='name'; name.textContent=coreEvents[i].label.replace(/^\\d+\\.\\s*/,'')+' (t≈'+coreEvents[i].t+')';
var tg=document.createElement('span'); tg.className='tag'; tg.textContent='Core';
li.appendChild(badge); li.appendChild(name); li.appendChild(tg);
li.addEventListener('click', function(){ jumpTo(coreEvents[parseInt(this.dataset.idx,10)].t, 'core', parseInt(this.dataset.idx,10)); });
listEl.appendChild(li);
}
var hr=document.createElement('div'); hr.className='sep'; listEl.appendChild(hr);
// Revelation
for(var j=0;j<futurePins.length;j++){
var li2=document.createElement('li'); li2.dataset.kind='rev'; li2.dataset.idx=String(j);
var badge2=document.createElement('span'); badge2.className='badge'; badge2.textContent='R';
var name2=document.createElement('span'); name2.className='name'; name2.textContent=futurePins[j].label+' (t≈'+futurePins[j].t+')';
var tg2=document.createElement('span'); tg2.className='tag'; tg2.textContent='Revelation';
li2.appendChild(badge2); li2.appendChild(name2); li2.appendChild(tg2);
li2.addEventListener('click', function(){ jumpTo(futurePins[parseInt(this.dataset.idx,10)].t, 'rev', parseInt(this.dataset.idx,10)); });
listEl.appendChild(li2);
}
}
function highlightList(kind, idx){
var items=listEl.querySelectorAll('li'); items.forEach(el=>el.classList.remove('active'));
var sel=listEl.querySelector('li[data-kind="'+kind+'"][data-idx="'+idx+'"]');
if(sel){ sel.classList.add('active'); sel.scrollIntoView({block:'nearest', behavior:'smooth'}); }
}
// Controls
var slider=document.getElementById('slider');
var tLabel=document.getElementById('tLabel');
var calInput=document.getElementById('calInput'); var calGo=document.getElementById('calGo');
var nowBtn=document.getElementById('nowBtn'); var resBtn=document.getElementById('resBtn');
var startBtn=document.getElementById('startBtn'); var endBtn=document.getElementById('endBtn');
var cycleLabel=document.getElementById('cycleLabel'); var eraLabel=document.getElementById('eraLabel');
function setT(t){
if(isNaN(t)) return;
var wrapped=tWrap(t);
slider.value=wrapped;
tLabel.textContent=t.toFixed(1);
eraLabel.textContent=eraText(t);
cycleLabel.textContent=cycleText(t);
update(t);
var best = {kind:'core', idx:0, d:9e9};
for(var i=0;i<coreEvents.length;i++){ var d=Math.abs(coreEvents[i].t - t); if(d<best.d){ best={kind:'core', idx:i, d:d}; } }
for(var j=0;j<futurePins.length;j++){ var d2=Math.abs(futurePins[j].t - t); if(d2<best.d){ best={kind:'rev', idx:j, d:d2}; } }
highlightList(best.kind, best.idx);
}
function jumpTo(t, kind, idx){ setT(t); highlightList(kind, idx); }
function update(t){
// Rotate 7-fold rings
gatesGroup.setAttribute('transform','rotate('+(-(t/P_G)*360)+' '+CX+' '+CY+')');
veilsGroup.setAttribute('transform','rotate('+(-(t/P_V)*360)+' '+CX+' '+CY+')');
layersGroup.setAttribute('transform','rotate('+(-(t/P_L)*360)+' '+CX+' '+CY+')');
// Rotate cogs
for(var i=0;i<cogs.length;i++){
var P=cogs[i].P; cogs[i].g.setAttribute('transform','rotate('+(-(t/P)*360)+' '+CX+' '+CY+')');
}
// Hand
while(handLayer.firstChild) handLayer.removeChild(handLayer.firstChild);
var th=tToTheta(t), p=polar(th,rTimeline);
makeEl('line',{x1:CX,y1:CY,x2:p[0],y2:p[1],stroke:'#e5e7eb','stroke-width':1.8},handLayer);
}
// Drag-to-rotate
var dragging=false;
function clientToWrapped(e){
var x=e.clientX, y=e.clientY;
if(e.touches && e.touches.length){ x=e.touches[0].clientX; y=e.touches[0].clientY; }
var pt=svg.createSVGPoint(); pt.x=x; pt.y=y;
var m=svg.getScreenCTM().inverse(); var p=pt.matrixTransform(m);
var dx=p.x - CX, dy=CY - p.y;
var theta=Math.atan2(dy, dx); if(theta<0) theta += 2*Math.PI;
return (1 - (theta/(2*Math.PI))) * 7000;
}
function onDown(e){ dragging=true; setT(clientToWrapped(e)); e.preventDefault(); }
function onMove(e){ if(!dragging) return; setT(clientToWrapped(e)); e.preventDefault(); }
function onUp(){ dragging=false; }
svg.addEventListener('mousedown', onDown); window.addEventListener('mousemove', onMove); window.addEventListener('mouseup', onUp);
svg.addEventListener('touchstart', onDown, {passive:false}); window.addEventListener('touchmove', onMove, {passive:false}); window.addEventListener('touchend', onUp);
// Slider & buttons
slider.addEventListener('input', function(){ setT(parseFloat(slider.value||'0')); });
slider.addEventListener('change', function(){ setT(parseFloat(slider.value||'0')); });
document.querySelectorAll('.jump').forEach(btn=>btn.addEventListener('click',()=>{ setT(parseFloat(slider.value||'0') + parseFloat(btn.dataset.delta)); }));
calGo.addEventListener('click',()=>{ setT(calendarToT(parseFloat(calInput.value||'2025'))); });
nowBtn.addEventListener('click',()=>{ setT(calendarToT(new Date().getFullYear())); });
document.getElementById('startBtn').addEventListener('click',()=>{ setT(0); });
document.getElementById('endBtn').addEventListener('click',()=>{ setT(7000); });
resBtn.addEventListener('click',()=>{ setT(4033.5); });
document.getElementById('toggleCore42').addEventListener('change', ()=>{ refreshOverlays(); });
document.getElementById('toggleFuture').addEventListener('change', ()=>{ refreshOverlays(); });
document.getElementById('toggleHistorical').addEventListener('change', ()=>{ refreshOverlays(); });
document.getElementById('toggleBeats').addEventListener('change', ()=>{ refreshOverlays(); });
document.getElementById('toggleKnocks').addEventListener('change', ()=>{ refreshOverlays(); });
document.getElementById('toggleNear').addEventListener('change', ()=>{ refreshOverlays(); });
document.getElementById('forceRedraw').addEventListener('click',()=>{ drawCogs(); drawRings(); refreshOverlays(); setT(parseFloat(slider.value||'4033.5')); buildUnifiedList(); });
// Build
refreshOverlays();
buildUnifiedList();
setT(parseFloat(document.getElementById('slider').value||'4033.5'));
})();</script>
</body>
</html>