v1.4.0: Desktop layout redesign + mobile tabs

Specializations move from a 340px left rail to a horizontal 2-row chip
grid at the top (drag L→R to rank). Each chip shows rank, spec-colored
abbreviation tag matching the tags used in plans/schedule, full name on
its own row, status glyph, and a micro credit bar. Hover/tap a chip to
see full status, allocated/threshold credits, and contributing-courses
breakdown in a popover.

The right pane splits into two side-by-side columns on desktop: Top
Plans (left) and Schedule (right), each scrolling independently. The
search progress bar hoists into a global strip below the spec grid so
it stays visible regardless of which column is scrolled.

Schedule blocks render their course choices as a horizontal row of
equal-width buttons (3-5 per set) instead of stacked rows. Pinned sets
collapse to a single line with the course name inline next to the set
title. Term headers (Spring/Summer/Fall) remain as section dividers.

On mobile, the layout becomes a 3-tab segmented control
(Specializations / Plans / Courses) with the search progress strip
above the tabs. The previous floating MobileStatusBanner and
MobileCourseBanner are dropped — tabs replace their navigation
function.
This commit is contained in:
2026-05-09 17:45:28 -04:00
parent b282709476
commit 2ebfb9d2ec
14 changed files with 1293 additions and 205 deletions
@@ -0,0 +1,105 @@
## ADDED Requirements
### Requirement: Desktop horizontal course button arrangement
On desktop, each non-pinned elective set in the Schedule column SHALL render its course choices as a horizontal flex row of equal-width buttons (one button per course), with each button stretching to fill its share of the row. Pinned sets SHALL continue to render as today (single-line course name with a Clear button). On mobile, course choices SHALL continue to render as vertically stacked rows.
#### Scenario: Desktop unpinned set renders horizontal row
- **WHEN** the user views an unpinned elective set on desktop
- **THEN** the set's course choices SHALL render as a horizontal flex row of equal-width buttons, one button per course
#### Scenario: Desktop unpinned set with three courses
- **WHEN** an unpinned elective set has 3 courses on desktop
- **THEN** the row SHALL render 3 buttons stretched to fill the available width
#### Scenario: Desktop unpinned set with five courses
- **WHEN** an unpinned elective set has 5 courses on desktop
- **THEN** the row SHALL render 5 buttons stretched to fill the available width, narrower than the 3-course case
#### Scenario: Pinned set on desktop unchanged
- **WHEN** an elective set is pinned on desktop
- **THEN** the set SHALL continue to render the pinned course name with a Clear button on a single line, not as a horizontal row
#### Scenario: Mobile keeps stacked rows
- **WHEN** the user views an unpinned elective set on mobile
- **THEN** the course choices SHALL continue to render as vertically stacked full-width rows
### Requirement: Course button anatomy on desktop
Each course button in a desktop horizontal row SHALL display: an info icon in the top-left when course description info is available, a "recommended" star indicator in the top-right when this course is the recommended choice for the set, the course name with a multi-line clamp (max 2-3 lines) and the full name available via the title attribute, and a row of spec ceiling tags at the bottom showing the specializations this course could contribute to.
#### Scenario: Button with all elements
- **WHEN** a course on desktop is the recommended choice, has a description, and has spec qualifications
- **THEN** the button SHALL show the info icon (top-left), the recommended star (top-right), the course name with line-clamp, and the spec ceiling tags at the bottom
#### Scenario: Course without info
- **WHEN** a course on desktop has no description in `COURSE_DESCRIPTIONS`
- **THEN** the button SHALL omit the info icon while keeping all other elements
#### Scenario: Course not recommended
- **WHEN** a course on desktop is not the recommended choice for its set
- **THEN** the button SHALL omit the recommended star while keeping all other elements
#### Scenario: Long course name truncation
- **WHEN** a course name exceeds the line-clamp limit
- **THEN** the visible text SHALL truncate with an ellipsis and the full name SHALL be available via the title attribute on hover
#### Scenario: Spec tag overflow within button
- **WHEN** a course has more spec tags than fit in a single row inside the button at the current button width
- **THEN** the spec tag row SHALL wrap to multiple lines within the button, and the button heights in the set SHALL flex-stretch to remain aligned
### Requirement: Course button states on desktop
Course buttons on desktop SHALL communicate the following states with distinct styling: cancelled (strikethrough name, gray background, "Cancelled" footer text, non-clickable), already-selected-elsewhere (gray background, "Already selected" footer text, non-clickable), per-course searching (skeleton placeholder where spec tags would render), recommended (recommended star + visual emphasis), and required-for-spec (small amber footer note "Required for X" when the course is required for one or more specializations).
#### Scenario: Cancelled course button
- **WHEN** a course in an unpinned set has `cancelled: true`
- **THEN** its button SHALL render with strikethrough name, gray background, a "(Cancelled)" footer label, and SHALL not be clickable
#### Scenario: Already-selected course button
- **WHEN** a course is in the disabled-because-pinned-elsewhere set
- **THEN** its button SHALL render with gray background, an "(Already selected)" footer label, and SHALL not be clickable
#### Scenario: Per-course searching state
- **WHEN** the decision tree analysis for a course is still in progress (the course's `evaluated` flag is false)
- **THEN** the button SHALL render a pulsing skeleton band where the spec ceiling tags would otherwise appear, with all other content unchanged
#### Scenario: Required-for footer
- **WHEN** a course is required for one or more specializations
- **THEN** the button SHALL render a small amber "Required for X" footer beneath the spec tag row
## MODIFIED Requirements
### Requirement: Inline decision tree ceiling per course option
When decision tree analysis is available for an open elective set, each course option SHALL display its ceiling outcome (spec abbreviations) as small spec tags. On mobile, the spec tags SHALL render on the right side of each course row. On desktop, the spec tags SHALL render in a row along the bottom of each course button.
#### Scenario: Mobile ceiling data on right side
- **WHEN** an open set has completed decision tree analysis on mobile and a course has ceiling specs (BNK, FIN, LCM)
- **THEN** the course row SHALL show the course name on the left and tags for BNK, FIN, LCM on the right
#### Scenario: Desktop ceiling data along bottom
- **WHEN** an open set has completed decision tree analysis on desktop and a course has ceiling specs (BNK, FIN, LCM)
- **THEN** the course button SHALL show the course name with line-clamp at top and a row of tags for BNK, FIN, LCM along the bottom of the button
#### Scenario: Ceiling data not yet available
- **WHEN** an open set's decision tree analysis is still computing
- **THEN** the course buttons (mobile rows or desktop buttons) SHALL render without ceiling tags, and the set header SHALL show a subtle loading indicator
#### Scenario: Pinned set does not show ceiling
- **WHEN** a set has a pinned course selection
- **THEN** the set SHALL display the pinned course name without ceiling data on either mobile or desktop (same as current behavior)
### Requirement: High impact indicator on set header
When a set has high impact (variance > 0 in ceiling outcomes), the set header SHALL display a "high impact" indicator. This applies on both mobile and desktop.
#### Scenario: High impact set on mobile or desktop
- **WHEN** an open set's analysis shows impact > 0
- **THEN** the set header SHALL display a "high impact" label next to the set name
### Requirement: No standalone decision tree section
The standalone DecisionTree component at the bottom of the results dashboard SHALL be removed. All ceiling data SHALL be displayed inline within the course selection panel — on mobile as right-side row content, on desktop as bottom-of-button content.
#### Scenario: All tree data inline on mobile
- **WHEN** the user views the course selection panel on mobile
- **THEN** there SHALL be no separate "Decision Tree" heading or section; all ceiling outcomes appear within their respective elective set cards as right-side row content
#### Scenario: All tree data inline on desktop
- **WHEN** the user views the Schedule column on desktop
- **THEN** there SHALL be no separate "Decision Tree" heading or section; all ceiling outcomes appear within their respective elective set cards as bottom-of-button content