/** * Pure geometry for the A-Z jump strip (see AlphabetScrollBar.svelte). * * The strip stretches from wherever it sits down to a floor, and the floor is * the whole question: get it wrong and the tail of the alphabet renders past * the bottom of the scroller, under the mini player / bottom nav, where it * cannot be tapped. * * The floor is the scroller's own bottom edge — never the viewport's. The strip * used to size itself as `window.innerHeight` minus a hardcoded guess at the * bars' height (5rem/7rem/11rem by platform and mini-player visibility), which * dates from when those bars were `position: fixed` overlays. They are in-flow * flex siblings below the scroller now (see BottomUi.svelte), so the scroller's * bottom edge *is* the top of the mini player, measured exactly, every frame — * and the guess was short on every device with a navigation/gesture bar, * because `--safe-bottom` is padded inside BottomUi and the guess never knew * about it. * * Extracted from the component so the floor rule is unit-testable — the * component only supplies measurements. * * TRACES: UR-007 | DR-007, DR-262 */ /** * Breathing room left under the last letter, in px. Mirrors the `top-2` sticky * offset at the other end so the strip sits symmetrically in the scrollport. */ export const STRIP_BOTTOM_GAP = 8; export interface StripHeightInput { /** Viewport-relative top of the strip container (`getBoundingClientRect().top`). */ stripTop: number; /** * Viewport-relative bottom edge of the scroll container the strip lives in, * or `null` when the strip has no scrollable ancestor to measure. */ scrollerBottom: number | null; /** Viewport height — the fallback floor when there is no scroll container. */ viewportHeight: number; /** Override for {@link STRIP_BOTTOM_GAP}, in px. */ gap?: number; } /** How tall the A-Z strip may be without running under the bottom bars. */ export function stripHeightFor({ stripTop, scrollerBottom, viewportHeight, gap = STRIP_BOTTOM_GAP, }: StripHeightInput): number { const floor = scrollerBottom ?? viewportHeight; return Math.max(0, floor - gap - stripTop); }