Skip to content
Coastal Healthcare Advocates

Module: main

Home-page interactions for index.html.

No framework — plain DOM code. Everything here is a progressive enhancement: with JavaScript off, the page still reads and works, just without the extras. Each feature checks that its elements exist first, so the file is safe to load on a page that lacks some of them.

Features, in file order:

  1. Mobile navigation disclosure (hamburger menu).
  2. In-page anchor links: smooth scroll + move keyboard focus to the target.
  3. Sticky header: shadow once scrolled; hides near the end of the page.
  4. "How it works": connector line draws in when the section is visible.
  5. Scroll-reveal entrance animations for [data-reveal] elements.
  6. Scrollspy: highlights the nav link for the section in view.
  7. "Get Started" drawer tab: shown only in the middle stretch of the page.
  8. Booking-band maze: route draws itself once the footer comes into view.
  9. "Fine print" sample statement: hovering a note highlights its line, and each marked line's highlighter swipes across the row as one stroke.

The FAQ needs nothing here: each question is a native <details>.

Loaded as <script type="module">, which is deferred by default, so the whole document has been parsed by the time this runs.

Several features throttle scroll handling with requestAnimationFrame and a ticking flag: however many scroll events fire, the work runs at most once per frame.

Source:

Members

(inner, constant) REVEAL_MS

How long to wait before clearing reveal-in (longest entrance, in ms).

Source:

(inner, constant) STAGGERED :Object.<string, string>

For each data-reveal value whose children enter one after another, the selector for those children (relative to the element).

Type:
  • Object.<string, string>
Source:

(inner, constant) STAGGER_CAP

Highest stagger index; items beyond this all share the last delay.

Source:

(inner) currentId

Id of the section currently marked, or null. @type {string|null}

Source:

(inner, constant) drawerTab

The fixed "Get Started" tab. @type {HTMLElement|null}

Source:

(inner, constant) finePrint

The sample-statement container. @type {HTMLElement|null}

Source:

(inner, constant) header

The sticky site header. @type {HTMLElement|null}

Source:

(inner, constant) howFlow

The "How it works" steps container. @type {HTMLElement|null}

Source:

(inner) lastY

Scroll position at the previous update, to detect direction.

Source:

(inner, constant) linksById

Section id → the nav links pointing at it. @type {Map<string, HTMLAnchorElement[]>}

Source:

(inner, constant) mobileNav

The mobile nav panel it controls. @type {HTMLElement|null}

Source:

Every in-page nav link (desktop and mobile). @type {HTMLAnchorElement[]}

Source:

(inner, constant) navToggle

The hamburger button. @type {HTMLElement|null}

Source:

(inner, constant) osReducedMotion :MediaQueryList

Live media query for the device's reduced-motion setting.

Type:
  • MediaQueryList
Source:

(inner) pending

Elements that haven't been revealed yet. Shrinks as they play.

Source:

(inner, constant) prefersReducedMotion :Object

Whether motion should be reduced right now: the device asks for it, or the visitor turned Animations off in Site preferences (data-motion="off" on <html>, see theme.js / prefs.js). Checked by every animated feature; under reduced motion, content is simply shown.

Type:
  • Object
Source:

(inner, constant) routeMazes

The maze graphics (wide and phone versions). @type {NodeListOf}

Source:

(inner) routeTicking

True while a check is already queued for the next frame.

Source:

(inner, constant) sections

The distinct sections to observe. @type {HTMLElement[]}

Source:

(inner, constant) siteFooter

The footer whose arrival triggers the route drawing. @type {HTMLElement|null}

Source:

(inner, constant) tabShowAt

The tab appears once this section reaches the viewport. @type {HTMLElement|null}

Source:

(inner) tabTicking

True while an update is already queued for the next frame.

Source:

(inner, constant) tabTuckAt

The tab tucks away once this section is well into view. @type {HTMLElement|null}

Source:

(inner, constant) tail :HTMLElement|null

The closing region of the page; the header hides as this approaches. Falls back to the footer if there is no #schedule section.

Type:
  • HTMLElement | null
Source:

(inner) ticking

True while an update is already queued for the next frame.

Source:

(inner) ticking

True while a sweep is already queued for the next frame.

Source:

(inner, constant) visible

Sections currently crossing the viewport's midline. @type {Set}

Source:

Methods

(inner) checkRoute() → {void}

Once the footer's top is above 92% of the viewport height, adds is-routed to every maze (the CSS draws the route) and stops listening — it only happens once per page view.

Source:
Returns:
Type
void

(inner) focusTarget(hash) → {void}

Moves keyboard focus to the element an in-page link points at.

Most section elements aren't normally focusable, so a temporary tabindex="-1" is added (focusable by script, but not added to the Tab order) and removed again once focus leaves. Scrolling is left to the caller (preventScroll), so focus doesn't fight the smooth scroll.

Parameters:
Name Type Description
hash string

A fragment such as '#services'.

Source:
Returns:
Type
void

(inner) onRouteScroll() → {void}

Scroll/resize handler: queues one checkRoute per animation frame. Declared with const after checkRoute, which is fine: checkRoute only reads it when it runs, by which point it exists.

Source:
Returns:
Type
void

(inner) onScroll() → {void}

Scroll/resize handler: queues one sweep per animation frame.

Source:
Returns:
Type
void

(inner) setCurrent(id) → {void}

Marks the nav links for section id with aria-current="true" and clears the mark from all others. No-op if id is already current.

Parameters:
Name Type Description
id string | null

Section id to mark, or null to clear all.

Source:
Returns:
Type
void

(inner) setNav(open) → {void}

Opens or closes the mobile menu and updates the button to match (aria-expanded for assistive tech, aria-label for its name).

Parameters:
Name Type Description
open boolean

true to open, false to close.

Source:
Returns:
Type
void

(inner) sweep() → {void}

Checks every still-pending element's position and reveals the ones that are due. An element is due once its top is above 92% of the viewport height — or unconditionally once the page is scrolled to the bottom (short final sections might never reach that line).

Elements already above the top of the viewport are shown without an entrance (the visitor jumped past them).

Source:
Returns:
Type
void

(inner) syncDrawerTab() → {void}

Shows or tucks away the drawer tab based on scroll position.

  • is-tucked hides it (before #what is reached, or once #intake is in the lower quarter of the viewport or above).
  • tab-wait (the initial authored state) is removed on first run.
  • The first time the tab appears, is-arriving plays a one-off attention animation (skipped under reduced motion).
Source:
Returns:
Type
void

(inner) update() → {void}

Recomputes the header's classes from the current scroll position:

  • scrolled once the page has moved more than 8px from the top;
  • header-hidden when the closing region is near and the visitor isn't scrolling up.
Source:
Returns:
Type
void