+ {/* Tick track — 1:1 with the document, translated per frame. */}
+
+ {ticks.map((t, i) => (
+
{
+ tickRowRefs.current[i] = el;
+ }}
+ className="absolute inset-x-0"
+ style={{ top: t.docY, height: 0 }}
+ >
+ {
+ lineRefs.current[i] = el;
+ }}
+ className="absolute block bg-ink"
+ style={{
+ [outerProp]: 0,
+ top: 0,
+ width: t.major ? look.majorLen : look.minorLen,
+ height: 1,
+ opacity: mode === "full" ? 0 : t.alpha,
+ transformOrigin: `${outerProp} center`,
+ }}
+ />
+ {t.major && (
+ {
+ labelRefs.current[i] = el;
+ }}
+ className="absolute -translate-y-1/2 font-mono text-ink"
+ style={{
+ [outerProp]: look.majorLen + 4,
+ top: 0,
+ fontSize: 9,
+ letterSpacing: "0.08em",
+ opacity: look.labelAlpha,
+ }}
+ >
+ {t.pct}
+
+ )}
+
+ ))}
+
+
+ {/* Visible-span bracket: the current viewport's slice of the page,
+ shown only while the zoomed map is formed. */}
+ {mode === "full" && (
+
+ )}
+
+ {/* Needle: travels [NAV_H, vh] with progress, meeting its tick. */}
+
+
+
+
+ {[0, 1, 2].map((c) => (
+ {
+ digitRefs.current[c] = el;
+ }}
+ className="ruler-digit-col"
+ >
+ {"0123456789".split("").map((d) => (
+ {d}
+ ))}
+
+ ))}
+
+ %
+
+
+
+
+ {/* Hover ghost — destination preview, outside the rail so its label
+ can extend inward past the ticks. */}
+ {mode === "full" && (
+