## Context The app is a React (Vite/TypeScript) single-page app with no external UI library. Courses are rendered as clickable buttons in `CourseSelection.tsx`. There is no existing tooltip or popover infrastructure. The app already handles responsive layout via a `useMediaQuery` hook. Course descriptions and instructors come from a static PDF (`ref/J27 Electives-Course Descriptions.pdf`) plus one supplementary markdown file (`ref/inovation-and-design.md`). The data is stable per cohort (J27). ## Goals / Non-Goals **Goals:** - Show course description and instructor(s) inline via a popover triggered by an info icon - Work identically on desktop and mobile (click/tap, no hover or long-press) - Keep course description data separate from solver data structures **Non-Goals:** - Dynamic fetching of descriptions from an API - Editing or updating descriptions at runtime - Changing the Course type or solver logic - Adding a third-party tooltip/popover library ## Decisions ### 1. Separate data file keyed by course ID Store descriptions in `app/src/data/courseDescriptions.ts` as a `Record` keyed by course ID. **Why over extending Course type:** Descriptions are long strings unrelated to solver logic. Keeping them separate preserves readability of `courses.ts` and avoids polluting the `Course` interface used throughout the solver. **Why key by course ID (not name):** The same course name can appear in multiple elective sets with different instructors (e.g., "Collaboration, Conflict and Negotiation" — Steve Blader in Spring, Elizabeth Morrison in Summer). Per-ID keying handles this correctly at the cost of some description duplication. ### 2. Info icon trigger (not hover/long-press) An `(i)` icon button next to each course name, clickable on all platforms. **Why over CSS hover tooltip:** Hover doesn't work on touch devices. A separate info icon avoids conflicting with the existing click-to-select behavior on the course button. **Why over long-press on mobile:** Long-press is discoverable only if users know to try it. An explicit icon is universally obvious. ### 3. Pure CSS/React popover (no library) Build the popover as a positioned `div` managed with React state. Close on: click outside (document listener), re-click icon, or Escape key. **Why no library:** The app has zero UI dependencies beyond React. A single popover component doesn't justify adding one. The positioning logic is straightforward since popovers anchor to a known icon element. ### 4. Popover content layout ``` ┌────────────────────────────────┐ │ Course Name │ │ Instructor(s): Name, Name │ │ ────────────────────────────── │ │ Description text, scrollable │ │ if longer than max-height... │ └────────────────────────────────┘ ``` - Fixed max-width (~320px), max-height (~300px) with overflow scroll - Instructor list shown as comma-separated - Close button (X) in top-right corner ### 5. Event handling: stop propagation on info icon The `(i)` icon click must call `e.stopPropagation()` to prevent the parent course button's `onClick` (which pins the course) from firing. ## Risks / Trade-offs - **Description duplication across sets** — Same description text stored under multiple course IDs (e.g., `spr1-collaboration` and `sum1-collaboration`). Acceptable given the small dataset (~35 entries) and the need for per-ID instructor differentiation. - **Popover positioning at screen edges** — A simple anchored popover could overflow the viewport on narrow screens. Mitigation: on mobile, render as a near-full-width card or use `position: fixed` centered overlay instead of anchored positioning. - **Stale data if courses change** — Descriptions are hardcoded. If the course list changes for a future cohort, both `courses.ts` and `courseDescriptions.ts` need updating. This matches the existing pattern (all course data is static).