`) is a
static rect pattern encoding nothing. A user scanning *their own insurance
ID* and getting "no data" is a trust incident. At minimum an insurance ID
card must encode policy deep-link or signed token; as-is it's a real-looking
credential that does nothing — worse than no QR.
- **B7 (Medium) — Toast is not announced.** No `role="status"`/`aria-live` on
`#toast`; screen-reader users never hear "Policy renewal started ✓". Also
hardcoded `white-space:nowrap` will overflow the pill on 320 px devices or
longer localized strings.
- **B8 (Low) — Sheet keyboard/escape handling absent.** No Esc-to-close, no
focus trap, focus stays behind the backdrop; keyboard users tab into a
blurred background. `.backdrop` is a `
` with a click listener — not
keyboard-activatable.
- **B9 (Low) — Drag threshold tuned for mouse, not thumb.** 26–36 px on a
~0.35 mm/px phone screen is ~9 mm — double the comfort threshold for flick
gestures; combined with B2 users get missed or accidental expansions.
- **B10 (Low) — `Hero renew` pill says "Renew Now" and the toast confirms a
renewal with no confirmation step, no amount, no terms.** A one-tap
financial commitment with zero friction text. Fine for a mock; a lawsuit in
production.
- **B11 (Low) — Screens preserve scroll position across navigation.** `go()`
never resets `scrollTop`, so returning to a long screen restores a scrolled
view with no status indication. Minor but sloppy.
- **B12 (Low) — Time is hardcoded "9:41"** and the bell red dot has no
unread-state backing. Cosmetic, but it signals the app's data plumbing is
imaginary.
## 4. Performance
- **P1 — backdrop-filter stacking.** Five separate `backdrop-filter` regions
(hero-ic blur 4, batt-tag blur 6, dc-glass blur 6, tabbar blur **14**,
sheet backdrop blur 4) sit over scrollable content. On mid/low Android this
is the single largest GPU cost; scroll jank is guaranteed when the sheet is
open over blurred content.
- **P2 — Animating `filter: blur(3px)`** on `.tabbar.ghost` (`:283`) — filter
animation is paint-every-frame, not composited; on a full-width bar this is
a visible stutter. The same effect is free as pre-rendered opacity+translate.
- **P3 — Massive shadows.** `0 34px 90px`, `0 22px 46px`, multi-layer card
shadows repaint on any transform of their elements. Real risk during the
sheet's transform animation on low-end devices (verified pattern on mobile
WebKit).
- **P4 — Redundant gradients.** Hero, drive card, ID card, FAB each stack 2–3
radial + linear gradients as backgrounds. Beautiful; also 4 large
`background-size` rasterizations. Cacheable but adds first-paint cost on
weak GPUs.
- **P5 — No `will-change`/containment hints** on `.sheet` or `.screens`; the
`.screen` switch depends on `display` toggling which forces full
layout+paint of 1000-node pages on every tab switch. For 4 pages it's
tolerable; at 8 it won't be.
- **P6 — Positives:** zero external requests, no fonts, no images, ~10 KB
gzipped. First paint is fast. This is why it *feels* snappy in a demo.
- **P7 — Pointermove handler** does `performance.now()` + style writes per
event — fine — but no `requestAnimationFrame` throttle; at 120 Hz screens
style writes run 2× frame rate. Trivial fix.
## 5. Security & privacy
- **S1 — Realistic PII in public markup.** Full names (Rahul Sharma, Alex
Mandes, Sarah Kimani, David Otieno, Grace Wanjiru), DOB (24 Feb 2001),
ID number 326547624, policy CA326547624, plate MP04CY9999, residence. If any
of these map to real humans, this file is a data-protection incident (Kenya
DPA 2019 / GDPR-class). Even if synthetic, nothing in the file says so.
- **S2 — No auth/session concept.** An app that displays ID cards, policy
numbers, and takes "renewal" actions has zero authentication surface. As a
mock: understandable. As a product blueprint: where is it?
- **S3 — No CSP/SRI/referrer-meta.** Currently self-hosted so risk is latent,
but the day someone hot-links a script or style, there's no defense in
depth. `textContent` for toasts is XSS-safe today (`:897`) — the classic
regression is someone "improving" it to `innerHTML` for bold text.
- **S4 — Sensitive actions lack confirmation & audit trail.** Renewal, claim
registration, ID download: one tap, toast, done. No step-up auth, no
idempotency, no server request at all (obviously) — meaning the file
currently *teaches the wrong interaction contract* to anyone building the
backend from it.
- **S5 — Secrets/privacy in URLs to be designed later** — but note the QR
(B6) will likely tempt someone to encode raw policy IDs client-side. Needs a
signed, short-lived token design from the start.
- **S6 — Input handling is unstructured.** The search input has no
validation/sanitization conventions; when wired to an API this becomes the
injection vector of choice. Establish encoding-at-boundary now.
## 6. Design / UX (and a11y)
- **D1 — Visual craft is real.** Consistent radius scale (13→30), one strong
brand color, disciplined soft-shadow language, coherent purple/navy/light
hierarchy. It looks expensive. (This is what's fooling stakeholders into
thinking it's nearly-done.)
- **D2 — Identity confusion.** Hero says *Car* Insurance; sections push
*Health* & Wellness, Quick Actions reward "+$234.00" for *claims*, Benefits
pushes driving score + heart rate. The app doesn't know what it is: car
insurance, health insurance, or a wellness-rewards program. Pick one north
star per surface.
- **D3 — FAB mega-menu buries support two gestures deep** (FAB → expand →
Support stab) while "Message Now" exists on Policies — two competing
support entries with different states.
- **D4 — Emoji-as-iconography.** 🧔🏻👩🏼📄🔔💬🛡 render inconsistently across
platforms (tofu on some Androids, inconsistent skin tones). For a financial
app this reads as unprofessional; replace with a single icon font/SVG set.
- **D5 — Contrast failures.** `.lbl` rgba(255,255,255,.62) on purple
(~2.9:1), `#a6a7b3` placeholder, `#9a9ba8` 10.5 px tab labels, `#cfcfd9`
dots — multiple sub-4.5:1 ratios at 10–12 px sizes. Insurance users skew
older; this is an exclusion shipped as a style.
- **D6 — Home indicator / island are fake device chrome painted by the app**
(`.island`, `.home-ind`). Inside a real device in-app WebView these double
up with the OS chrome. Kill them outside the demo frame.
- **D7 — No loading/empty/error states anywhere.** The file only knows the
happy path. First product question that will be asked: "what does this
screen show while policies load?" — there's no answer in this code.
- **D8 — Motion is un-governed**: no `prefers-reduced-motion` query; the
fadeUp + sheet + blur + toast stack all animate regardless of vestibular
settings.
---
## 7. Execution plan — "finally improve InsurePay"
Rough effort for **1 senior FE + 0.5 QA**, assuming it must become a real
maintainable web app. If any phase's goal shifts (e.g., the product stays a
prototype), that's a scope decision — write it down explicitly instead of
letting it happen by accident.
### Phase 0 — Foundations & hygiene (≈3–4 days) — *do not skip*
| # | Task | Acceptance criteria |
|---|---|---|
| 0.1 | Split the monolith: `index.html` + `styles.css` (+ `tokens.css`) + `app.js` as ES module; add `package.json` (Vite or no-build ESM), lint (ESLint+stylelint), formatting (Prettier), git baseline | `npm run dev/build/lint` green; zero globals (verify via `window` enumeration in CI) |
| 0.2 | Extract design tokens → CSS custom properties for *all* spacing/radii/font sizes; px→rem at 16 px base; z-index scale `z.base/z.overlay/z.sheet/z.toast` | No magic numbers outside tokens; rem audit passes |
| 0.3 | SVG sprite: one `` per icon, `