From bb8469ca10de2fec09f3bd5f16e52eb565b88332 Mon Sep 17 00:00:00 2001 From: ilia Date: Wed, 20 May 2026 23:05:20 -0400 Subject: [PATCH] Fix folder stack overlap: pull slots, split tab/body sticky. Sections overlap via negative margin; tabs stay in staggered rail; active body z-index covers layers below as you scroll. Co-authored-by: Cursor --- shared/stack-layout.css | 8 +- shared/stack-scroll.js | 13 +- shared/stack-vars.css | 9 +- spec/index.html | 340 +++++++++++++++++++++++----------------- spec/spec.css | 319 ++++++++++++++++++++++++++++++++++--- spec/spec.js | 125 +++++++++++++-- stack-folder/folder.css | 48 ++---- stack-rack/rack.css | 25 +-- stack-trace/trace.css | 40 +++-- stack/stack.css | 39 +++-- 10 files changed, 720 insertions(+), 246 deletions(-) diff --git a/shared/stack-layout.css b/shared/stack-layout.css index 04fc572..0802803 100644 --- a/shared/stack-layout.css +++ b/shared/stack-layout.css @@ -1,12 +1,16 @@ -/* Sticky stack slots — import after stack-vars.css */ +/* Pull layers into one stack so sticky overlap works */ .scroll-section { height: var(--stack-slot); position: relative; } +.scroll-section + .scroll-section { + margin-top: calc(-1 * var(--stack-pull)); +} + .scroll-section--final { height: var(--stack-slot-last); - min-height: 280px; + min-height: 260px; } .stack-stop, diff --git a/shared/stack-scroll.js b/shared/stack-scroll.js index b71679a..da39179 100644 --- a/shared/stack-scroll.js +++ b/shared/stack-scroll.js @@ -5,12 +5,13 @@ export function initStackScroll(options = {}) { depthEl = document.getElementById('depth'), depthPrefix = 'L', tabSelector = '[data-goto], .jump', + bodySelector = '.body, .layer-inner, .frame-body, .unit-body', } = options; const sections = document.querySelectorAll(sectionSelector); if (!sections.length) return; - const mid = () => window.innerHeight * 0.4; + const mid = () => window.innerHeight * 0.42; function updateDepth() { let active = 0; @@ -19,11 +20,19 @@ export function initStackScroll(options = {}) { if (r.top <= mid() && r.bottom > mid()) active = Number(sec.dataset.layer); }); if (depthEl) depthEl.textContent = `${depthPrefix}${active}`; + document.querySelectorAll('.stack-ruler button, .stack-ruler [data-goto], .tab-rail button, .tab[data-goto]').forEach((el) => { const n = el.dataset.layer ?? el.dataset.goto; if (n === undefined) return; el.classList.toggle('active', Number(n) === active); }); + + sections.forEach((sec) => { + const layer = Number(sec.dataset.layer); + const body = sec.querySelector(bodySelector); + if (!body) return; + body.style.zIndex = layer === active ? 100 : 10 + layer; + }); } document.querySelectorAll(tabSelector).forEach((tab) => { @@ -32,7 +41,7 @@ export function initStackScroll(options = {}) { const layer = tab.dataset.goto; const target = document.querySelector(`${sectionSelector}[data-layer="${layer}"]`); if (!target) return; - const y = target.offsetTop - 48; + const y = target.getBoundingClientRect().top + window.scrollY - 48; window.scrollTo({ top: Math.max(0, y), behavior: 'smooth' }); }); }); diff --git a/shared/stack-vars.css b/shared/stack-vars.css index e8e5bce..566d4fa 100644 --- a/shared/stack-vars.css +++ b/shared/stack-vars.css @@ -1,8 +1,13 @@ -/* Shared stack scroll — one viewport per layer */ +/* Shared stack scroll — overlapping sticky layers */ :root { --stack-nav: 2.5rem; --stack-stick: 3rem; --stack-step: 2.75rem; + --stack-tab-h: 2.25rem; + /* Height of tab rail (all L0–L6 tabs visible) */ + --stack-reveal: calc(var(--stack-stick) + var(--stack-step) * 6 + var(--stack-tab-h)); --stack-slot: 100vh; - --stack-slot-last: 55vh; + --stack-slot-last: 50vh; + --stack-pull: calc(var(--stack-slot) - var(--stack-reveal)); + --stack-body-h: calc(100dvh - var(--stack-reveal) - 1rem); } diff --git a/spec/index.html b/spec/index.html index da3c1a1..dc88e8e 100644 --- a/spec/index.html +++ b/spec/index.html @@ -9,12 +9,24 @@ + -