Floating CTA
A .floating-cta capsule that keeps section-jump links and a call-to-action button always visible on long landing pages. A rounded (--r-xl), translucent bar is fixed to the bottom of the viewport; when the footer comes into view, JS automatically lifts it so it never overlaps the footer.
Shape
A rounded-box bar — border-radius: var(--r-xl) (16px, same family as buttons and cards; pill 9999px is forbidden) — with a translucent background, backdrop-filter: blur(16px), and an --sh-full elevation shadow. Section-jump links are arranged on the left; the global .btn apply button is anchored at the far right. The Preview below is a static mock — it shows the shape only, without the real fixed positioning behavior.
Behavior
In a real page, the capsule is fixed to the bottom of the viewport via position: fixed. The lift logic that raises it above the footer is written as client-side JS directly inside the page component.
Fixed position
position: fixed,bottom: var(--cta-gap)— 40px on desktop / 24px on mobileleft: 50%,width: min(800px, calc(100% - 32px))z-index: 70— above content, below modals
Footer avoidance (lift)
To prevent the capsule from overlapping the footer, JS recalculates the lift value on every scroll, resize, and ResizeObserver(body) event using the formula below.
lift = max(0, innerHeight - footer.getBoundingClientRect().top)- Apply to the capsule:
transform: translate(-50%, calc(-1 * var(--cta-lift)))— the capsule bottom always rests--cta-gapabove the footer - Do not use rAF (requestAnimationFrame) — it pauses in background tabs; update directly in the event handler instead
Parked-position spacing
When the capsule parks above the footer, set the last section's (e.g. FAQ) padding-bottom to roughly capsule height + 2 × gap so the space between the content end and the footer looks balanced. The footer's own padding-bottom should stay at its normal value, independent of the capsule.
Mobile
At viewport widths of 720px and below, the link area switches to horizontal scrolling. The apply button stays pinned to the far right and remains visible regardless of scroll position.
- Link row:
overflow-x: autowith edgemaskfades — visually hints that the row is scrollable - Apply button:
flex: 0 0 autopins it to the right, independent of link scrolling - Capsule width:
min(800px, calc(100% - 32px))— preserves 16px gutters on each side
Rules
- Radius:
var(--r-xl)(16px) — rounded box like buttons/cards; pill9999pxis forbidden - Item spacing: row gap = links gap =
36px— links and the apply button stay evenly spaced as one group - Background:
color-mix(in srgb, var(--card-bg) 66%, transparent)— translucent; automatically follows the dark mode token - Elevation:
--sh-fullfamily - Nav link text: weight
600— matches header links - Apply button: use the global
.btnas-is; no custom variants z-index: 70— below the header layer (100), above regular content- No emoji or italic — use inline SVG or pseudo-elements for icons