Lesson 04 | Act 4: Elderly Mode

⏱ Est. reading time: 5 min Updated on 5/7/2026

Act 4: Elderly Mode (Episodes 8-10)

The most challenging part — making it usable and accessible for a 65-year-old.

Episode 8: Two Modes, One Codebase

Scene: Standard mode is done, now we need to add elderly mode. We can't build two separate versions.

  • CSS Custom Properties + body.elderly-mode: One class toggles all visuals
  • Elderly mode visual standards: 68px buttons (originally set to 80px, tested 68px as comfortable), 26px font, 7:1 contrast
  • Three mode toggle methods: UI button + keyboard m key + localStorage preference
  • 300ms CSS transition for smooth shifting (background, font-size, width)
  • Elderly mode hides ( ) % buttons — simplifying the UI, not removing features
  • Use visibility: hidden + pointer-events: none instead of display: none (to preserve Grid cells)
  • Core concept: CSS variables make theme switching just a matter of altering a few values

Output Files:

  • style.css.elderly-mode full override styles (white background, blue theme, large buttons & text)
  • app.js — Mode toggle logic (initMode / toggleMode + localStorage)
  • index.htmldata-hide-elderly attribute + mode toggle button + sound toggle button
  • tests/mode/switch.test.js — Mode toggle tests

Command: /gsd-discuss-phase 3, /gsd-plan-phase 3, /gsd-execute-phase 3


Episode 9: Accessibility is Not a Bonus, It's Fundamental

Scene: Visuals look good, but how do blind users navigate? What about screen readers for elderly users?

  • ARIA labels: Chinese descriptions for every button (e.g. aria-label="Seven", aria-label="Divide")
  • Focus indicator: Pressing Tab shows where you are, 3px blue outline in elderly mode (WCAG AAA requires thicker outlines)
  • Screen readers: After calculating 2+3=5, it should announce "2+3 equals 5" (dynamic aria-label updates)
  • Long-press backspace: Holding ⌫ for 500ms in elderly mode clears all (touchstart timer)
  • Button sounds: Web Audio API 800Hz 0.05s beep, default off, localStorage remembers toggle state
  • Why sounds matter: As elderly users' vision declines, auditory feedback serves as a secondary confirmation channel
  • Core concept: Accessibility is not an afterthought patch, it's part of the design

Output Files:

  • app.js — Dynamic ARIA updates (announceResult) + long-press detection (_longPressTimer) + sound system (playClickSound)
  • tests/a11y/aria.test.js — ARIA attribute tests
  • tests/a11y/focus.test.js — Focus indicator tests

Command: /gsd-execute-phase 3 (continued)


Episode 10: Bug Hunt — Elderly Mode Buttons Overflow

Scene: Thought we were done, but opening elderly mode reveals buttons breaking the container bounds.

  • Bug: Buttons overflowing the container edge
  • Root cause: display: none breaks CSS Grid auto-placement (hidden elements don't take up space)
  • Fix: visibility: hidden + pointer-events: none (takes space but invisible and unclickable)
  • Fortification: grid-template-columns: repeat(4, 1fr) + width: auto to prevent overflow
  • Color fix: Elderly mode white background + blue theme (#1a73e8), contrast > 7:1
  • Layout tweaks: Blue gradient background for the display area, layered shadow effects for buttons
  • file:// protocol limit: Chrome ES module isn't supported, revert to traditional <script> + exports compatibility
  • Core concept: CSS Grid hidden rules — a hidden element does not equal a removed element

Output Files: No new files, updated style.css + index.html

Command: /gsd-quick or direct manual fix