This commit is contained in:
NotSoToothless
2026-06-07 20:44:44 -07:00
committed by GitHub
parent b88f41c14c
commit 28ce4f0541
+41 -21
View File
@@ -45,8 +45,8 @@
}
@media (min-width: 1024px) {
.timeline-hero {
padding-top: 7.5rem;
padding-bottom: 3.25rem; /* room between hero text and row 1 */
padding-top: 8.5rem; /* clearance below the fixed nav */
padding-bottom: 1.75rem; /* JS centering adds the rest of the hero→row1 gap */
}
}
@@ -125,7 +125,7 @@
@media (min-width: 1024px) {
.timeline {
margin-top: 2.5rem;
margin-top: 1.5rem; /* base; JS centering adds to this */
}
.timeline-grid {
grid-template-columns: repeat(3, 1fr);
@@ -169,7 +169,7 @@
.timeline-node:nth-child(4) { grid-area: 2 / 3; }
.timeline-node:nth-child(5) { grid-area: 2 / 2; }
.timeline-node:nth-child(6) { grid-area: 2 / 1; }
/* Static fallback gap before row 2; JS (applyFirstGap) overrides
/* Static fallback gap before row 2; JS (layoutFirstScreen) overrides
this on desktop with a measured value so row 2 lands just below
the fold on any viewport height. */
.timeline-node:nth-child(4),
@@ -191,10 +191,10 @@
already have that room, so they keep the roomier sizing above. */
@media (min-width: 1024px) and (max-height: 1080px) {
.timeline-hero {
padding-top: 4.5rem;
padding-bottom: 1.5rem;
padding-top: 6.5rem; /* nav clearance on short screens */
padding-bottom: 1rem;
}
.timeline { margin-top: 1rem; }
.timeline { margin-top: 0.75rem; }
.timeline-card { padding: 1.85rem; }
.timeline-title { font-size: 1.5rem; }
.timeline-desc { font-size: 1.02rem; line-height: 1.6; }
@@ -479,27 +479,47 @@
return { x: x, y: y };
}
// Size the gap before row 2 so it sits just below the fold on load,
// measured from the real row-1 bottom and the real viewport height —
// no per-resolution magic numbers. Desktop (3-col) only.
function applyFirstGap() {
// Desktop layout pass: vertically centre row 1 + the comet's breathing
// band in the viewport (spare space split evenly above row 1 and below
// the comet), then push row 2 just under the fold so it stays hidden.
// This keeps the same balanced look on any viewport height — no
// per-resolution magic numbers.
var COMET_BAND = 90; // breathing room reserved below row 1 for the comet
function layoutFirstScreen() {
var rowTwo = [nodes[3], nodes[4], nodes[5]].filter(Boolean);
if (!rowTwo.length) return;
if (!window.matchMedia('(min-width: 1024px)').matches) {
// Reset both adjustables so we measure the natural layout each time.
timeline.style.marginTop = '';
rowTwo.forEach(function (n) { n.style.marginTop = ''; });
return;
}
// Measure row 2's natural top with no extra gap (grid row gap only).
if (!window.matchMedia('(min-width: 1024px)').matches) return;
if (!rowTwo.length) return;
var vh = window.innerHeight;
rowTwo.forEach(function (n) { n.style.marginTop = '0px'; });
var top = rowTwo[0].getBoundingClientRect().top + window.pageYOffset;
// +32 so the marker (which pokes ~1.8rem above the node) clears too.
var gap = Math.max(48, (window.innerHeight + 32) - top);
// Natural row-1 extent (tallest of the first three cards).
var row1Top = Infinity, row1Bottom = 0;
for (var k = 0; k < 3 && k < nodes.length; k++) {
var r = nodes[k].getBoundingClientRect();
row1Top = Math.min(row1Top, r.top);
row1Bottom = Math.max(row1Bottom, r.bottom);
}
var row1Height = row1Bottom - row1Top;
// Centre: half the leftover height goes above row 1, half below comet.
var spare = vh - row1Top - row1Height - COMET_BAND;
var topMargin = Math.max(0, spare * 0.5);
var base = parseFloat(getComputedStyle(timeline).marginTop) || 0;
timeline.style.marginTop = (base + topMargin) + 'px';
// After the shift, drop row 2 just under the fold (+40 clears its marker).
var row2Top = rowTwo[0].getBoundingClientRect().top;
var gap = Math.max(48, (vh + 40) - row2Top);
rowTwo.forEach(function (n) { n.style.marginTop = gap + 'px'; });
}
function build() {
_samples = null;
applyFirstGap();
layoutFirstScreen();
// Use layout dimensions (not getBoundingClientRect) so the SVG
// coordinate system matches the transform-independent getMarkerCenter.
svg.setAttribute('viewBox', '0 0 ' + timeline.offsetWidth + ' ' + timeline.offsetHeight);
@@ -568,7 +588,7 @@
// reveal line is the frontier. This keeps the comet just below the last
// in-view card on load, then leading the draw as you scroll, instead of
// jumping ahead off-screen.
var REVEAL_FRACTION = 0.82;
var REVEAL_FRACTION = 0.85;
function frontierProgress() {
if (!pathLength || !_samples) return state.progress;
var revealY = window.innerHeight * REVEAL_FRACTION - timeline.getBoundingClientRect().top;