Tighten stack overlap; fix folder top tabs; replace paper with rack.
Cards and trace use negative-margin overlap; folder tabs stay above bodies; new server-rack variant. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Levkin — Stack Rack</title>
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="./rack.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="nav"><a href="/">← options</a><a href="/stack-trace/">trace</a><span id="depth">U0</span></nav>
|
||||
|
||||
<div class="rack-frame">
|
||||
<div class="rack-label">LEV-RACK-01</div>
|
||||
<main class="mount">
|
||||
<div class="scroll-section" data-layer="0"><article class="unit u0"><header class="unit-head"><span class="led on"></span><span class="uid">U0</span><span class="svc">foundation</span></header><div class="unit-body"><strong>Levkin</strong><p>Software dev · CA · 15+ yrs · new work open</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="1"><article class="unit u1"><header class="unit-head"><span class="led on"></span><span class="uid">U1</span><span class="svc">application</span></header><div class="unit-body"><strong>custom_software</strong><p>TS · Python · .NET</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="2"><article class="unit u2"><header class="unit-head"><span class="led on"></span><span class="uid">U2</span><span class="svc">automation</span><a href="https://auto.levkin.ca">auto↗</a></header><div class="unit-body"><strong>pipeline_cluster</strong><p>n8n · CI/CD · LLM hooks</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="3"><article class="unit u3"><header class="unit-head"><span class="led on"></span><span class="uid">U3</span><span class="svc">enterprise</span><a href="https://caseware.levkin.ca">caseware↗</a></header><div class="unit-body"><strong>caseware_module</strong><p>MNP · JazzIt · 8h→2m</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="4"><article class="unit u4"><header class="unit-head"><span class="led blink"></span><span class="uid">U4</span><span class="svc">quality</span><a href="https://iliadobkin.com">iliadobkin↗</a></header><div class="unit-body"><strong>sdet_suite</strong><p>traces · Playwright · CI</p></div></article></div>
|
||||
<div class="scroll-section" data-layer="5"><article class="unit u5"><header class="unit-head"><span class="led"></span><span class="uid">U5</span><span class="svc">ops</span><a href="https://jobs.levkin.ca">jobs↗</a></header><div class="unit-body"><strong>job_ops</strong><p>auth · internal</p></div></article></div>
|
||||
<div class="scroll-section scroll-section--final" data-layer="6"><article class="unit u6"><header class="unit-head"><span class="led on"></span><span class="uid">U6</span><span class="svc">interface</span></header><div class="unit-body"><strong>engage()</strong><p><a href="https://cal.levkin.ca/ilia/consult">book_consult</a> · <a href="mailto:hello@levkine.ca">mail</a></p></div></article></div>
|
||||
<div class="stop"></div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="foot"><span>// rack EOT</span><a href="https://git.levkin.ca">git.levkin.ca</a></footer>
|
||||
<script src="./rack.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
:root {
|
||||
--nav: 2.5rem;
|
||||
--stick: 0.5rem;
|
||||
--step: 1.7rem;
|
||||
--scroll-tick: 26vh;
|
||||
--overlap: 22vh;
|
||||
--rack: #12141a;
|
||||
--mono: 'IBM Plex Mono', monospace;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: var(--mono);
|
||||
background: #08090c;
|
||||
color: #9ca3af;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.nav {
|
||||
position: fixed; top: 0; left: 0; right: 0; z-index: 200;
|
||||
display: flex; gap: 1rem; padding: 0.5rem 1rem; font-size: 0.62rem;
|
||||
background: rgba(8,9,12,0.95); border-bottom: 1px solid #1e2430;
|
||||
}
|
||||
|
||||
.nav a { color: #5a6478; text-decoration: none; }
|
||||
.nav a:hover { color: #4ade80; }
|
||||
#depth { margin-left: auto; color: #4ade80; font-weight: 600; }
|
||||
|
||||
.rack-frame {
|
||||
max-width: 540px;
|
||||
margin: 0 auto;
|
||||
padding: calc(var(--nav) + 0.75rem) 0.75rem 0;
|
||||
border-left: 4px solid #2a3040;
|
||||
border-right: 4px solid #2a3040;
|
||||
background: linear-gradient(90deg, #0c0e14 0%, var(--rack) 8%, var(--rack) 92%, #0c0e14 100%);
|
||||
min-height: 100vh;
|
||||
box-shadow: inset 0 0 40px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.rack-label {
|
||||
font-size: 0.55rem;
|
||||
letter-spacing: 0.2em;
|
||||
color: #3a4458;
|
||||
padding: 0 0.5rem 0.75rem;
|
||||
border-bottom: 1px dashed #2a3040;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.mount { padding: 0 0.35rem; }
|
||||
|
||||
.scroll-section { height: var(--scroll-tick); position: relative; }
|
||||
.scroll-section--final { height: 16vh; min-height: 160px; }
|
||||
.stop { height: 1px; margin-bottom: 2rem; }
|
||||
|
||||
.unit {
|
||||
position: sticky;
|
||||
margin-bottom: calc(-1 * var(--overlap));
|
||||
border: 1px solid #2a3448;
|
||||
background: #161a22;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 0 #0a0c10, inset 0 1px 0 rgba(255,255,255,0.04);
|
||||
}
|
||||
|
||||
.unit-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.35rem 0.65rem;
|
||||
background: #1a2030;
|
||||
border-bottom: 1px solid #2a3448;
|
||||
font-size: 0.62rem;
|
||||
position: relative;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.led {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #3a4458;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.led.on { background: #4ade80; box-shadow: 0 0 6px #4ade80; }
|
||||
.led.blink { background: #fbbf24; animation: blink 1.2s ease infinite; }
|
||||
|
||||
@keyframes blink {
|
||||
50% { opacity: 0.35; }
|
||||
}
|
||||
|
||||
.uid { color: #6b7280; font-weight: 600; min-width: 1.5rem; }
|
||||
.svc { color: #9ca3af; text-transform: uppercase; letter-spacing: 0.08em; flex: 1; }
|
||||
.unit-head a {
|
||||
color: #60a5fa;
|
||||
text-decoration: none;
|
||||
font-size: 0.58rem;
|
||||
}
|
||||
|
||||
.unit-body {
|
||||
padding: 0.55rem 0.65rem 0.65rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.unit-body strong { color: #e5e7eb; font-weight: 500; display: block; margin-bottom: 0.15rem; }
|
||||
.unit-body p { color: #6b7280; font-size: 0.68rem; }
|
||||
.unit-body a { color: #60a5fa; text-decoration: none; }
|
||||
.unit-body a:hover { text-decoration: underline; }
|
||||
|
||||
.u0 { top: calc(var(--nav) + var(--stick)); z-index: 1; }
|
||||
.u1 { top: calc(var(--nav) + var(--stick) + var(--step)); z-index: 2; }
|
||||
.u2 { top: calc(var(--nav) + var(--stick) + var(--step) * 2); z-index: 3; }
|
||||
.u3 { top: calc(var(--nav) + var(--stick) + var(--step) * 3); z-index: 4; }
|
||||
.u4 { top: calc(var(--nav) + var(--stick) + var(--step) * 4); z-index: 5; }
|
||||
.u5 { top: calc(var(--nav) + var(--stick) + var(--step) * 5); z-index: 6; }
|
||||
.u6 {
|
||||
top: calc(var(--nav) + var(--stick) + var(--step) * 6);
|
||||
z-index: 7;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.foot {
|
||||
display: flex; justify-content: space-between; max-width: 540px; margin: 0 auto;
|
||||
padding: 1rem 1.25rem 2rem; font-size: 0.58rem; color: #3a4458;
|
||||
}
|
||||
.foot a { color: #3a4458; text-decoration: none; }
|
||||
@@ -0,0 +1,15 @@
|
||||
const sections = document.querySelectorAll('.scroll-section');
|
||||
const depthEl = document.getElementById('depth');
|
||||
const mid = () => window.innerHeight * 0.42;
|
||||
|
||||
function tick() {
|
||||
let a = 0;
|
||||
sections.forEach((s) => {
|
||||
const r = s.getBoundingClientRect();
|
||||
if (r.top <= mid() && r.bottom > mid()) a = +s.dataset.layer;
|
||||
});
|
||||
depthEl.textContent = `U${a}`;
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', tick, { passive: true });
|
||||
tick();
|
||||
Reference in New Issue
Block a user