## ADDED Requirements ### Requirement: Banner appears when specializations scroll out of view The system SHALL display a floating summary banner fixed to the top of the viewport on mobile when the specializations section is no longer visible in the viewport. #### Scenario: User scrolls past specializations on mobile - **WHEN** the user is on a mobile viewport (max-width: 639px) and scrolls down until the specializations section leaves the viewport - **THEN** a fixed banner SHALL slide in from the top of the screen displaying specialization status counts #### Scenario: User scrolls back up to specializations on mobile - **WHEN** the banner is visible and the user scrolls up until the specializations section re-enters the viewport - **THEN** the banner SHALL slide out of view (upward) #### Scenario: User is on tablet or desktop - **WHEN** the viewport width is greater than 639px - **THEN** the banner SHALL NOT render at all ### Requirement: Banner displays status counts with color-coded badges The banner SHALL show the count of specializations in each status category using the same color scheme as the specialization list: achieved (green), achievable (blue), missing required (amber), and unreachable (gray). #### Scenario: Multiple statuses present - **WHEN** the banner is visible and statuses are: 2 achieved, 5 achievable, 1 missing required, 6 unreachable - **THEN** the banner SHALL display four badges: "2 Achieved" in green, "5 Achievable" in blue, "1 Missing Req." in amber, "6 Unreachable" in gray #### Scenario: Zero count for a status category - **WHEN** a status category has zero specializations (e.g., 0 missing required) - **THEN** that category's badge SHALL still be displayed with a count of 0 #### Scenario: Statuses update after course selection change - **WHEN** the user selects or deselects a course while the banner is visible - **THEN** the banner status counts SHALL update to reflect the new optimization result ### Requirement: Banner animates in and out The banner SHALL animate its appearance and disappearance using a vertical slide transition. #### Scenario: Banner slides in - **WHEN** the specializations section scrolls out of the viewport on mobile - **THEN** the banner SHALL transition from `translateY(-100%)` to `translateY(0)` over 200ms with ease-out timing #### Scenario: Banner slides out - **WHEN** the specializations section scrolls back into the viewport on mobile - **THEN** the banner SHALL transition from `translateY(0)` to `translateY(-100%)` over 200ms with ease-out timing ### Requirement: Tapping banner scrolls to specializations The banner SHALL be tappable. Tapping it SHALL smoothly scroll the page so the specializations section is visible at the top of the viewport. #### Scenario: User taps the banner - **WHEN** the banner is visible and the user taps anywhere on it - **THEN** the page SHALL smooth-scroll to bring the specializations section to the top of the viewport #### Scenario: Banner hides after scroll completes - **WHEN** the user taps the banner and the page scrolls to the specializations section - **THEN** the banner SHALL slide out as the specializations section becomes visible (via the standard intersection trigger) ### Requirement: Banner renders above all other content The banner SHALL use `position: fixed` with `z-index: 1000` to ensure it layers above all other page content. #### Scenario: Banner overlaps page content - **WHEN** the banner is visible - **THEN** it SHALL be rendered at `position: fixed; top: 0` spanning the full viewport width, above all other elements ### Requirement: Banner uses consistent styling The banner SHALL use inline `React.CSSProperties` consistent with the existing codebase convention, and SHALL reuse the exported `STATUS_STYLES` color definitions from the specialization ranking component. #### Scenario: Status colors match specialization list - **WHEN** the banner displays status badges - **THEN** the badge colors SHALL exactly match the `STATUS_STYLES` used in the specialization ranking rows (achieved: #16a34a, achievable: #2563eb, missing_required: #d97706, unreachable: #9ca3af)