<!doctype html>

<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>High-watermark Persistent Rack (16 documents)</title>
<style>
  :root{
    --doc-w:850px; /* document width */
    --doc-h:1100px; /* document height */
    --gap-x:50px;   /* horizontal gap between docs */
    --gap-y:100px;  /* vertical gap between docs */
    --rack-left:20px;
    --rack-top:20px;
  }
  html,body{height:100%;margin:0;font-family:Inter,Arial,Helvetica,sans-serif}
  /* Viewport where user scrolls/pans (this is what we scroll programmatically) */
  .viewport{width:100vw;height:100vh;overflow:auto;touch-action:pan-x pan-y;background:#eef2f6}
  /* Very large workspace that simulates the 32" x 64" desktop (kept pixel-based for consistency) */
  .workspace{position:relative;width:3200px;height:6400px;margin:40px auto;background:linear-gradient(180deg,#fff,#f7fbff);box-shadow:0 12px 40px rgba(10,20,40,0.08)}/* Rack (top-left) */ .rack{position:absolute;left:var(--rack-left);top:var(--rack-top);display:grid;grid-template-columns:repeat(4,100px);grid-auto-rows:60px;gap:20px;z-index:120} .rack button{width:100px;height:60px;border-radius:8px;border:1px solid #888;background:linear-gradient(#fff,#e9effa);font-weight:700;display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer} .rack .coords{font-size:11px;font-weight:500;margin-top:4px}

/* Editor panel (appears below rack) */ #editorPanel{position:absolute;left:var(--rack-left);display:none;background:#fff;border:1px solid #cfd6df;padding:10px;border-radius:6px;box-shadow:0 6px 18px rgba(10,20,40,0.08);max-height:55vh;overflow:auto;z-index:150} #editorPanel textarea{display:block;width:320px;height:30px;margin-bottom:8px;font-size:13px;padding:6px}

/* Controls */ .controls{position:absolute;left:480px;top:28px;z-index:200} .controls button{margin-right:10px;padding:8px 12px;border-radius:6px;border:1px solid #888;background:#fff;cursor:pointer}

/* Document panel */ .doc{position:absolute;width:var(--doc-w);height:var(--doc-h);background:#fff;border:1px solid #c7ced8;border-radius:8px;overflow:hidden;z-index:60;box-shadow:0 6px 20px rgba(8,20,40,0.06)} .doc iframe{position:relative;z-index:1;width:100%;height:100%;border:0}

/* Floating return button: high z-index so it's always clickable above iframe content */ .return-btn{position:absolute;top:12px;left:12px;z-index:9999;padding:8px 10px;border-radius:6px;border:1px solid #666;background:#fff;font-weight:700;cursor:pointer}

/* small note */ .note{position:fixed;right:12px;bottom:12px;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid #ddd;box-shadow:0 8px 26px rgba(0,0,0,0.08);z-index:200} </style>

</head>
<body><div class="viewport" id="viewport">
  <div class="workspace" id="workspace">
    <div id="rack" class="rack" aria-label="button rack"></div><div class="controls">
  <button id="editBtn">Edit</button>
  <button id="saveBtn">Save</button>
  <button id="clearBtn">Clear All</button>
</div>

<div id="editorPanel" aria-hidden="true"></div>

<div id="docsContainer"></div>

  </div>
</div><div class="note">Triple-tap anywhere (mobile) or triple-click (desktop) to return home above the rack.</div><script>
(function(){
  const FRAME_COUNT = 16;
  const DOC_W = 850;
  const DOC_H = 1100;
  const GAP_X = 50;
  const GAP_Y = 100;

  const viewport = document.getElementById('viewport');
  const workspace = document.getElementById('workspace');
  const rack = document.getElementById('rack');
  const docsContainer = document.getElementById('docsContainer');
  const editorPanel = document.getElementById('editorPanel');
  const editBtn = document.getElementById('editBtn');
  const saveBtn = document.getElementById('saveBtn');
  const clearBtn = document.getElementById('clearBtn');

  let editMode = false;
  let currentView = 'rack'; // 'rack' or 'docX'
  let autosaveTimeout = null;

  function getCoords(i){
    const col = (i-1) % 4;
    const row = Math.floor((i-1)/4);
    const x = col * (DOC_W + GAP_X);
    const y = row * (DOC_H + GAP_Y);
    return {x,y, xEnd: x + DOC_W, yEnd: y + DOC_H};
  }

  // Create rack buttons, docs and editor textareas
  for(let i=1;i<=FRAME_COUNT;i++){
    const coords = getCoords(i);

    // rack button
    const b = document.createElement('button');
    b.innerHTML = `${i}<span class='coords'>X:${coords.x}-${coords.xEnd}, Y:${coords.y}-${coords.yEnd}</span>`;
    b.addEventListener('click', ()=> goToDoc(i));
    rack.appendChild(b);

    // document container
    const doc = document.createElement('div');
    doc.className = 'doc';
    doc.id = 'doc' + i;
    doc.style.left = coords.x + 'px';
    doc.style.top = coords.y + 'px';

    // return button fixed within the doc (floating above iframe)
    const ret = document.createElement('button');
    ret.className = 'return-btn';
    ret.innerHTML = '.'+i+` <span style='font-size:11px;display:block;margin-top:4px;'>X:${coords.x}-${coords.xEnd}, Y:${coords.y}-${coords.yEnd}</span>`;
    ret.addEventListener('click', ()=> { goHome(); });
    doc.appendChild(ret);

    // iframe
    const iframe = document.createElement('iframe');
    iframe.id = 'iframe' + i;
    iframe.setAttribute('sandbox', 'allow-scripts allow-forms allow-same-origin allow-popups');
    doc.appendChild(iframe);

    docsContainer.appendChild(doc);

    // editor textarea
    const ta = document.createElement('textarea');
    ta.id = 'ta' + i;
    ta.placeholder = `Document ${i} SRC`;
    editorPanel.appendChild(ta);
  }

  // Position editorPanel exactly 30px below the rack
  function positionEditorPanel(){
    // rack is absolutely positioned inside workspace
    const top = rack.offsetTop + rack.offsetHeight + 30; // 30px gap
    const left = rack.offsetLeft;
    editorPanel.style.top = top + 'px';
    editorPanel.style.left = left + 'px';
  }
  // Run once after layout
  positionEditorPanel();

  // Scroll helpers: center a doc in the viewport
  function centerElementInViewport(el){
    const elRect = el.getBoundingClientRect();
    const vpRect = viewport.getBoundingClientRect();
    // Compute element's coordinates relative to workspace (offsetLeft/Top)
    const offsetLeft = el.offsetLeft;
    const offsetTop = el.offsetTop;
    const targetLeft = Math.max(0, offsetLeft + el.offsetWidth/2 - viewport.clientWidth/2);
    const targetTop = Math.max(0, offsetTop + el.offsetHeight/2 - viewport.clientHeight/2);
    viewport.scrollTo({left: targetLeft, top: targetTop, behavior: 'auto'});
  }

  // Home scroll (center rack horizontally, position near top)
  function goHome(){
    const rackLeft = rack.offsetLeft;
    const rackWidth = rack.offsetWidth;
    const targetLeft = Math.max(0, rackLeft - (viewport.clientWidth/2 - rackWidth/2));
    const targetTop = Math.max(0, rack.offsetTop - 20);
    viewport.scrollTo({left: targetLeft, top: targetTop, behavior: 'auto'});
    currentView = 'rack';
    scheduleAutoSave();
  }

  // Navigate to doc
  function goToDoc(i){
    const el = document.getElementById('doc'+i);
    if(!el) return;
    centerElementInViewport(el);
    currentView = 'doc'+i;
    scheduleAutoSave();
  }

  // Toggle edit panel
  editBtn.addEventListener('click', ()=>{
    editMode = !editMode;
    if(editMode){
      // populate
      for(let i=1;i<=FRAME_COUNT;i++){
        const iframe = document.getElementById('iframe'+i);
        const ta = document.getElementById('ta'+i);
        ta.value = iframe.src || '';
      }
      positionEditorPanel();
      editorPanel.style.display = 'block';
      editorPanel.setAttribute('aria-hidden','false');
      editBtn.textContent = 'Apply';
    } else {
      // apply
      for(let i=1;i<=FRAME_COUNT;i++){
        const iframe = document.getElementById('iframe'+i);
        const ta = document.getElementById('ta'+i);
        if(iframe && ta){ iframe.src = ta.value.trim(); }
      }
      editorPanel.style.display = 'none';
      editorPanel.setAttribute('aria-hidden','true');
      editBtn.textContent = 'Edit';
      scheduleAutoSave();
    }
  });

  // Save / Clear
  function saveConfig(){
    const cfg = { currentView };
    for(let i=1;i<=FRAME_COUNT;i++){
      const iframe = document.getElementById('iframe'+i);
      cfg['iframe'+i] = iframe ? iframe.src : '';
    }
    localStorage.setItem('highwater_cfg_v1', JSON.stringify(cfg));
  }
  function loadConfig(){
    const saved = JSON.parse(localStorage.getItem('highwater_cfg_v1') || '{}');
    if(Object.keys(saved).length===0) return;
    for(let i=1;i<=FRAME_COUNT;i++){
      const src = saved['iframe'+i];
      if(src){ const iframe = document.getElementById('iframe'+i); if(iframe) iframe.src = src; }
      // also populate editor textarea so user sees current values when opening editor
      const ta = document.getElementById('ta'+i); if(ta) ta.value = saved['iframe'+i] || '';
    }
    if(saved.currentView){
      if(saved.currentView === 'rack') goHome();
      else{
        const el = document.getElementById(saved.currentView);
        if(el) centerElementInViewport(el);
        currentView = saved.currentView;
      }
    }
  }

  saveBtn.addEventListener('click', ()=>{ saveConfig(); alert('Saved configuration.'); });
  clearBtn.addEventListener('click', ()=>{
    localStorage.removeItem('highwater_cfg_v1');
    for(let i=1;i<=FRAME_COUNT;i++){ const iframe = document.getElementById('iframe'+i); if(iframe) iframe.src = ''; const ta = document.getElementById('ta'+i); if(ta) ta.value = ''; }
    goHome();
    alert('Cleared configuration.');
  });

  // Auto-save scheduling (so last state is preserved even if user is interrupted)
  function scheduleAutoSave(){
    if(autosaveTimeout) clearTimeout(autosaveTimeout);
    autosaveTimeout = setTimeout(()=>{ saveConfig(); autosaveTimeout = null; }, 400);
  }

  // Triple-tap / triple-click detection on viewport
  (function(){
    let taps = 0; let timer = null;
    viewport.addEventListener('touchend', ()=>{
      taps++;
      if(taps===1){ timer = setTimeout(()=>{ taps = 0; }, 700); }
      else if(taps===3){ clearTimeout(timer); taps = 0; goHome(); }
    }, {passive:true});

    // Desktop triple-click fallback
    let clicks = 0; let clickTimer = null;
    viewport.addEventListener('click', ()=>{
      clicks++;
      if(clicks===1){ clickTimer = setTimeout(()=>{ clicks = 0; }, 700); }
      else if(clicks===3){ clearTimeout(clickTimer); clicks = 0; goHome(); }
    });
  })();

  // Update editor panel position when window resizes (so it stays under rack)
  window.addEventListener('resize', positionEditorPanel);

  // Load saved config on start (and center view)
  window.addEventListener('load', ()=>{ positionEditorPanel(); loadConfig(); });

  // Expose a small API for debugging from console
  window.__RackApp = { goToDoc, goHome, saveConfig, loadConfig };

})();
</script></body>
</html>