<!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>