diff --git a/shared/stack-layout.css b/shared/stack-layout.css index 1a74614..13c6743 100644 --- a/shared/stack-layout.css +++ b/shared/stack-layout.css @@ -1,4 +1,3 @@ -/* Overlapping scroll slots — each layer covers the one below via z-index */ .scroll-section { height: var(--stack-slot); position: relative; @@ -10,7 +9,7 @@ .scroll-section--final { height: var(--stack-slot-last); - min-height: 260px; + min-height: 280px; } .stack-stop, @@ -18,18 +17,3 @@ height: 2rem; margin-bottom: 3rem; } - -/* Body visible only when card is stuck on the stack — next card covers previous */ -.scroll-section:not(.is-stuck) .body, -.scroll-section:not(.is-stuck) .layer-inner, -.scroll-section:not(.is-stuck) .frame-body, -.scroll-section:not(.is-stuck) .unit-body { - visibility: hidden; - min-height: 0; - height: 0; - padding-top: 0; - padding-bottom: 0; - border: none; - box-shadow: none; - overflow: hidden; -} diff --git a/shared/stack-scroll.js b/shared/stack-scroll.js index 9defb81..33ede73 100644 --- a/shared/stack-scroll.js +++ b/shared/stack-scroll.js @@ -1,32 +1,23 @@ -/** Scroll depth + jump + hide upcoming cards until they cover the stack */ +/** Scroll depth + jump-to-layer for stack variants */ export function initStackScroll(options = {}) { const { sectionSelector = '.scroll-section', depthEl = document.getElementById('depth'), depthPrefix = 'L', tabSelector = '[data-goto], .jump', - panelSelector = '.folder, .layer, .frame, .unit', } = options; const sections = document.querySelectorAll(sectionSelector); if (!sections.length) return; - const reveal = () => { - const v = getComputedStyle(document.documentElement).getPropertyValue('--stack-reveal').trim(); - return parseFloat(v) || 344; - }; - const mid = () => window.innerHeight * 0.42; function updateDepth() { - const rLine = reveal(); let active = 0; - sections.forEach((sec) => { const r = sec.getBoundingClientRect(); 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) => { @@ -34,21 +25,6 @@ export function initStackScroll(options = {}) { if (n === undefined) return; el.classList.toggle('active', Number(n) === active); }); - - sections.forEach((sec) => { - const layer = Number(sec.dataset.layer); - const panel = sec.querySelector(panelSelector); - if (!panel) return; - - const r = sec.getBoundingClientRect(); - const pr = panel.getBoundingClientRect(); - const onStack = Math.abs(pr.top - rLine) < 10; - const past = r.bottom <= rLine; - - sec.classList.toggle('is-active', layer === active); - sec.classList.toggle('is-stuck', onStack); - sec.classList.toggle('is-past', past); - }); } document.querySelectorAll(tabSelector).forEach((tab) => { @@ -63,6 +39,5 @@ export function initStackScroll(options = {}) { }); window.addEventListener('scroll', updateDepth, { passive: true }); - window.addEventListener('resize', updateDepth, { passive: true }); updateDepth(); } diff --git a/shared/stack-vars.css b/shared/stack-vars.css index 91d26ae..0e5439c 100644 --- a/shared/stack-vars.css +++ b/shared/stack-vars.css @@ -1,13 +1,12 @@ -/* Shared stack scroll — cards share one sticky line and cover via z-index */ +/* Sticky card stack — enough scroll per layer for cover effect */ :root { --stack-nav: 2.5rem; --stack-stick: 3rem; --stack-step: 2.75rem; - --stack-tab-h: 2rem; - --stack-reveal: calc(var(--stack-stick) + var(--stack-step) * 6 + var(--stack-tab-h)); --stack-slot: 100vh; - --stack-slot-last: 50vh; - /* Scroll one "deck" height before next card covers */ - --stack-pull: calc(var(--stack-slot) - var(--stack-reveal)); - --stack-body-h: calc(100dvh - var(--stack-reveal) - 1.25rem); + --stack-slot-last: 55vh; + /* ~70vh scroll per layer before the next card slides over */ + --stack-scroll-step: 70vh; + --stack-pull: calc(var(--stack-slot) - var(--stack-scroll-step)); + --stack-body-h: calc(100dvh - var(--stack-stick) - var(--stack-step) * 6 - 3rem); } diff --git a/stack-folder/folder.css b/stack-folder/folder.css index 4d7cc66..0552425 100644 --- a/stack-folder/folder.css +++ b/stack-folder/folder.css @@ -60,18 +60,14 @@ body { font-family: var(--sans); background: #2a2824; color: #1a1814; } padding: var(--stack-nav) 1rem 0; } -/* All folders stick at same line — higher z-index covers previous card */ +/* Card = tab + body; sticky with stepped top; higher z covers previous */ .folder { position: sticky; - top: var(--stack-reveal); width: 100%; } .tab { - position: absolute; - left: 0; - bottom: 100%; - margin-bottom: 0; + position: sticky; display: block; width: fit-content; max-width: calc(100% - 1rem); @@ -85,8 +81,8 @@ body { font-family: var(--sans); background: #2a2824; color: #1a1814; } border-radius: 8px 8px 0 0; cursor: pointer; text-align: left; + z-index: 60; box-shadow: 0 -2px 8px rgba(0,0,0,0.12); - transition: filter 0.15s; } .tab:hover { filter: brightness(1.06); } @@ -94,32 +90,33 @@ body { font-family: var(--sans); background: #2a2824; color: #1a1814; } .body { background: #e8e2d4; border: 1px solid #c4b8a8; + border-top: none; border-radius: 0 10px 10px 10px; padding: 1.25rem 1.4rem 2rem; min-height: var(--stack-body-h); box-shadow: 0 10px 32px rgba(0,0,0,0.25); } -.f0 { z-index: 10; } -.f0 .tab { margin-left: calc(var(--tab-offset) * 0); bottom: calc(100% + var(--stack-step) * 0); background: #c9a86c; color: #2a2824; } +.f0 { top: calc(var(--stack-stick) + var(--stack-step) * 0); z-index: 10; } +.f0 .tab { top: calc(var(--stack-stick) + var(--stack-step) * 0); margin-left: calc(var(--tab-offset) * 0); background: #c9a86c; color: #2a2824; } -.f1 { z-index: 11; } -.f1 .tab { margin-left: calc(var(--tab-offset) * 1); bottom: calc(100% + var(--stack-step) * 1); background: #a8c4d4; color: #1a2830; } +.f1 { top: calc(var(--stack-stick) + var(--stack-step) * 1); z-index: 11; } +.f1 .tab { top: calc(var(--stack-stick) + var(--stack-step) * 1); margin-left: calc(var(--tab-offset) * 1); background: #a8c4d4; color: #1a2830; } -.f2 { z-index: 12; } -.f2 .tab { margin-left: calc(var(--tab-offset) * 2); bottom: calc(100% + var(--stack-step) * 2); background: #b8d4a8; color: #1a2818; } +.f2 { top: calc(var(--stack-stick) + var(--stack-step) * 2); z-index: 12; } +.f2 .tab { top: calc(var(--stack-stick) + var(--stack-step) * 2); margin-left: calc(var(--tab-offset) * 2); background: #b8d4a8; color: #1a2818; } -.f3 { z-index: 13; } -.f3 .tab { margin-left: calc(var(--tab-offset) * 3); bottom: calc(100% + var(--stack-step) * 3); background: #d4b8c4; color: #2a1820; } +.f3 { top: calc(var(--stack-stick) + var(--stack-step) * 3); z-index: 13; } +.f3 .tab { top: calc(var(--stack-stick) + var(--stack-step) * 3); margin-left: calc(var(--tab-offset) * 3); background: #d4b8c4; color: #2a1820; } -.f4 { z-index: 14; } -.f4 .tab { margin-left: calc(var(--tab-offset) * 4); bottom: calc(100% + var(--stack-step) * 4); background: #d4c8a8; color: #2a2418; } +.f4 { top: calc(var(--stack-stick) + var(--stack-step) * 4); z-index: 14; } +.f4 .tab { top: calc(var(--stack-stick) + var(--stack-step) * 4); margin-left: calc(var(--tab-offset) * 4); background: #d4c8a8; color: #2a2418; } -.f5 { z-index: 15; } -.f5 .tab { margin-left: calc(var(--tab-offset) * 5); bottom: calc(100% + var(--stack-step) * 5); background: #c4c4c4; color: #2a2a2a; } +.f5 { top: calc(var(--stack-stick) + var(--stack-step) * 5); z-index: 15; } +.f5 .tab { top: calc(var(--stack-stick) + var(--stack-step) * 5); margin-left: calc(var(--tab-offset) * 5); background: #c4c4c4; color: #2a2a2a; } -.f6 { z-index: 16; } -.f6 .tab { margin-left: calc(var(--tab-offset) * 6); bottom: calc(100% + var(--stack-step) * 6); background: #2a4a6b; color: #e8e2d4; } +.f6 { top: calc(var(--stack-stick) + var(--stack-step) * 6); z-index: 16; } +.f6 .tab { top: calc(var(--stack-stick) + var(--stack-step) * 6); margin-left: calc(var(--tab-offset) * 6); background: #2a4a6b; color: #e8e2d4; } .body h1 { font-size: 1.65rem; margin-bottom: 0.35rem; } .body h2 { font-size: 1.25rem; margin-bottom: 0.4rem; } diff --git a/stack-rack/rack.css b/stack-rack/rack.css index a5f748e..e886e89 100644 --- a/stack-rack/rack.css +++ b/stack-rack/rack.css @@ -38,7 +38,6 @@ body { .unit { position: sticky; - top: var(--stack-reveal); margin: 0; border: 1px solid #2a3448; background: #161a22; @@ -47,16 +46,12 @@ body { } .unit-head { - position: absolute; - left: 0; - right: 0; - bottom: calc(100% + var(--stack-step) * var(--layer, 0)); + position: sticky; display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.65rem; background: #1a2030; - border: 1px solid #2a3448; - border-bottom: none; - border-radius: 2px 2px 0 0; + border-bottom: 1px solid #2a3448; + z-index: 60; } .unit-head button.jump { @@ -82,13 +77,26 @@ body { background: #161a22; } -.u0 { z-index: 10; --layer: 0; } -.u1 { z-index: 11; --layer: 1; } -.u2 { z-index: 12; --layer: 2; } -.u3 { z-index: 13; --layer: 3; } -.u4 { z-index: 14; --layer: 4; } -.u5 { z-index: 15; --layer: 5; } -.u6 { z-index: 16; --layer: 6; } +.u0 { top: calc(var(--stack-stick) + var(--stack-step) * 0); z-index: 10; } +.u0 .unit-head { top: calc(var(--stack-stick) + var(--stack-step) * 0); } + +.u1 { top: calc(var(--stack-stick) + var(--stack-step) * 1); z-index: 11; } +.u1 .unit-head { top: calc(var(--stack-stick) + var(--stack-step) * 1); } + +.u2 { top: calc(var(--stack-stick) + var(--stack-step) * 2); z-index: 12; } +.u2 .unit-head { top: calc(var(--stack-stick) + var(--stack-step) * 2); } + +.u3 { top: calc(var(--stack-stick) + var(--stack-step) * 3); z-index: 13; } +.u3 .unit-head { top: calc(var(--stack-stick) + var(--stack-step) * 3); } + +.u4 { top: calc(var(--stack-stick) + var(--stack-step) * 4); z-index: 14; } +.u4 .unit-head { top: calc(var(--stack-stick) + var(--stack-step) * 4); } + +.u5 { top: calc(var(--stack-stick) + var(--stack-step) * 5); z-index: 15; } +.u5 .unit-head { top: calc(var(--stack-stick) + var(--stack-step) * 5); } + +.u6 { top: calc(var(--stack-stick) + var(--stack-step) * 6); z-index: 16; } +.u6 .unit-head { top: calc(var(--stack-stick) + var(--stack-step) * 6); } .unit-body strong { color: #e5e7eb; display: block; margin-bottom: 0.2rem; } .unit-body p { color: #6b7280; font-size: 0.7rem; } diff --git a/stack-trace/trace.css b/stack-trace/trace.css index 412946b..c3f5e32 100644 --- a/stack-trace/trace.css +++ b/stack-trace/trace.css @@ -28,7 +28,6 @@ body { .frame { position: sticky; - top: var(--stack-reveal); margin: 0 0.5rem; border-left: 3px solid #3a3a44; background: #141418; @@ -36,10 +35,7 @@ body { } .frame-line { - position: absolute; - left: 0; - right: 0; - bottom: calc(100% + var(--stack-step) * var(--layer, 0)); + position: sticky; display: block; font-size: 0.66rem; color: #6b9b6b; @@ -50,6 +46,7 @@ body { width: 100%; padding: 0.65rem 0 0.35rem 1rem; background: #141418; + z-index: 60; } .frame-line:hover { color: #9fdf9f; text-decoration: underline; } @@ -60,13 +57,26 @@ body { background: #141418; } -.f0 { z-index: 10; border-color: #c4a574; --layer: 0; } -.f1 { z-index: 11; --layer: 1; } -.f2 { z-index: 12; --layer: 2; } -.f3 { z-index: 13; --layer: 3; } -.f4 { z-index: 14; border-color: #6b8b9b; --layer: 4; } -.f5 { z-index: 15; --layer: 5; } -.f6 { z-index: 16; border-color: #7eb87a; --layer: 6; } +.f0 { top: calc(var(--stack-stick) + var(--stack-step) * 0); z-index: 10; border-color: #c4a574; } +.f0 .frame-line { top: calc(var(--stack-stick) + var(--stack-step) * 0); } + +.f1 { top: calc(var(--stack-stick) + var(--stack-step) * 1); z-index: 11; } +.f1 .frame-line { top: calc(var(--stack-stick) + var(--stack-step) * 1); } + +.f2 { top: calc(var(--stack-stick) + var(--stack-step) * 2); z-index: 12; } +.f2 .frame-line { top: calc(var(--stack-stick) + var(--stack-step) * 2); } + +.f3 { top: calc(var(--stack-stick) + var(--stack-step) * 3); z-index: 13; } +.f3 .frame-line { top: calc(var(--stack-stick) + var(--stack-step) * 3); } + +.f4 { top: calc(var(--stack-stick) + var(--stack-step) * 4); z-index: 14; border-color: #6b8b9b; } +.f4 .frame-line { top: calc(var(--stack-stick) + var(--stack-step) * 4); } + +.f5 { top: calc(var(--stack-stick) + var(--stack-step) * 5); z-index: 15; } +.f5 .frame-line { top: calc(var(--stack-stick) + var(--stack-step) * 5); } + +.f6 { top: calc(var(--stack-stick) + var(--stack-step) * 6); z-index: 16; border-color: #7eb87a; } +.f6 .frame-line { top: calc(var(--stack-stick) + var(--stack-step) * 6); } .frame-body strong { color: #e8e6e3; font-weight: 500; display: block; margin-bottom: 0.2rem; } .frame-body p { color: #6b6966; font-size: 0.74rem; } diff --git a/stack/stack.css b/stack/stack.css index 7bc4ba6..b8b5f5d 100644 --- a/stack/stack.css +++ b/stack/stack.css @@ -36,7 +36,6 @@ body { .layer { position: sticky; - top: var(--stack-reveal); margin: 0; border-radius: 8px 8px 6px 6px; border: 1px solid rgba(255,255,255,0.08); @@ -45,10 +44,7 @@ body { .layer-tab { position: absolute; - left: 10px; - right: 10px; - bottom: calc(100% + var(--stack-step) * var(--layer, 0)); - height: 6px; + top: -6px; left: 10px; right: 10px; height: 6px; border-radius: 5px 5px 0 0; background: inherit; filter: brightness(1.12); @@ -62,13 +58,13 @@ body { min-height: var(--stack-body-h); } -.layer-0 { background: #1c1c20; z-index: 10; --layer: 0; } -.layer-1 { background: #24242c; z-index: 11; --layer: 1; } -.layer-2 { background: #2c2c36; z-index: 12; --layer: 2; } -.layer-3 { background: #343440; z-index: 13; --layer: 3; } -.layer-4 { background: #3c3c4a; z-index: 14; --layer: 4; } -.layer-5 { background: #444454; z-index: 15; --layer: 5; } -.layer-6 { background: #4c4c5e; z-index: 16; --layer: 6; } +.layer-0 { background: #1c1c20; top: calc(var(--stack-stick) + var(--stack-step) * 0); z-index: 10; } +.layer-1 { background: #24242c; top: calc(var(--stack-stick) + var(--stack-step) * 1); z-index: 11; } +.layer-2 { background: #2c2c36; top: calc(var(--stack-stick) + var(--stack-step) * 2); z-index: 12; } +.layer-3 { background: #343440; top: calc(var(--stack-stick) + var(--stack-step) * 3); z-index: 13; } +.layer-4 { background: #3c3c4a; top: calc(var(--stack-stick) + var(--stack-step) * 4); z-index: 14; } +.layer-5 { background: #444454; top: calc(var(--stack-stick) + var(--stack-step) * 5); z-index: 15; } +.layer-6 { background: #4c4c5e; top: calc(var(--stack-stick) + var(--stack-step) * 6); z-index: 16; } .layer-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.65rem;