All case studies
Case Study / 03

Sunvior: Auditing and Hardening a Live Marketing Site

A full audit and remediation pass on a live 20-page Astro site — fixing SEO redirect chains, a broken interactive widget, accessibility gaps, and 17 pages of drifted markup, with every change verified against the live render.

Category

Technical Audit & Design-System Remediation

Duration

Focused audit + remediation (35 files)

Role

Solo Developer — SEO, Accessibility & Front-End Systems

01 / Challenge

The business problem

Sunvior's marketing site for an iOS wellness app looked finished, but the polished surface hid accumulated drift. Earlier URL refactors had left the global nav and footer pointing at dead links that 301-redirected on every page load; a guided-breathing widget's countdown silently kept running against the wrong step; five custom interactive widgets announced nothing to screen readers; and roughly 17 of the ~20 pages hand-rolled their own Tailwind instead of using the shared components built to standardize them — so the 'design system' and the pages had quietly diverged. The mandate was to raise consistency, correctness, and accessibility on a live production site without shipping a single visible regression.

02 / Strategy

Approach

  1. 01

    Audit in parallel — run dedicated research passes over SEO and over code/accessibility while independently driving the live site in a browser, so every finding is cross-checked against real rendered behavior instead of taken on faith.

  2. 02

    Fix correctness before cosmetics: dead links and the broken widget ship first, the design-system refactor last.

  3. 03

    Treat every edit to a shared primitive as blast-radius-sensitive — a changed default can silently alter pages that were never opened — and verify each batch against the live render, not just a passing type-check.

03 / Implementation

What I built and changed

01

Parallelized Audit

Two focused research passes — one on SEO, one on code quality and accessibility — run against the source while I drove the running site in a browser to confirm each issue behaved as reported, not just as it read on the page.

  • Split the work into an SEO pass, a code/accessibility pass, and a live UX walkthrough so structural findings were confirmed against real rendered behavior.
  • Cross-check theory against practice — the SEO pass flagged dead nav links from the config, and the live walkthrough caught those same links redirecting inside the actual mobile menu.
  • Rank every finding critical / moderate / minor with file-and-line references before touching a single line.
02

Correctness First: Dead Links and a Broken Timer

The highest-impact, lowest-risk fixes — internal links that 301-redirected on every page load, and an interactive widget whose timer had come unglued from the step it was meant to be counting.

  • Repoint the global nav, footer, and in-page links from redirect targets to their real destinations, killing a redirect hop that fired on every page and wasted crawl budget.
  • Remove a self-referential card on the affirmation-app page whose link redirected back to the page it lived on.
  • Rework the guided-practice widget so Stop, Prev, and Next each re-scope the countdown to the current step, instead of leaving an old timer running against a different instruction.
03

Accessibility for Custom Widgets

The interactive widgets were visually rich but silent to assistive tech, and one core animation ignored the OS reduced-motion setting — in a product explicitly built around calm and anxiety relief.

  • Add aria-live regions to five widgets whose text updates on their own — breathing phases, timer completion, affirmation draws — matching the announce-state-not-every-tick pattern already used elsewhere in the codebase.
  • Guard the breathing-bubble animation behind prefers-reduced-motion so motion-sensitive users aren't force-fed a continuously scaling circle.
  • Add a real focus trap and focus restoration to the mobile menu, which surfaced a genuine browser gotcha: Chrome renders a collapsed <details> with its layout box intact, so offsetParent and getClientRects both wrongly reported hidden links as focusable — checkVisibility() was the only test that got it right.
04

Consolidating a Drifted Design System

The largest change: extend the shared Heading / Eyebrow / Section primitives, then migrate ~17 pages off their hand-rolled copies — a net deletion of code, done in verified batches against the live render.

  • Extend the primitives additively — a compact heading variant, a split between semantic tag and visual size, a missing id prop — so every existing consumer keeps its exact current output.
  • Migrate pages in batches by pattern — layout wrappers, then lead paragraphs, then labels, then headings — screenshotting each batch before and after so any regression is trivial to bisect.
  • Verify against the running site, not just the type-checker, which caught two bugs the compiler was perfectly happy with: removing one baked-in margin silently zeroed spacing on nine untouched pages, and Tailwind's utility ordering overrode a default margin and letter-spacing but NOT a default color, so one dark-background label had to stay hand-rolled.
04 / Outcomes

Business results

  • Every page-level, footer, and in-page link now resolves to its real destination, eliminating a site-wide redirect hop and a self-referential loop.

  • A visibly broken interactive timer now tracks the step it's showing; five previously silent widgets announce their state to screen readers; and a core animation respects the OS reduced-motion setting.

  • Roughly 17 pages migrated onto shared typography and layout primitives — a net reduction of ~265 lines across 35 files (577 removed / 312 added), including two fully unused components (386 lines) deleted outright.

  • Every batch verified against the live render at mobile and desktop, shipping with no visual regressions and a clean type-check, followed by a multi-agent security review that surfaced no new vulnerabilities.

05 / Takeaway

What the work proved

A shared component is a blast radius, not just a convenience. The moment I removed a baked-in margin from one typography primitive, nine pages I had never even opened lost their spacing — and a passing type-check said nothing about it. Consolidation only pays off if every change to a shared default is verified against the live render of every existing consumer, not just the files you happen to be editing.