7.8 KiB
Feature Specification: Semantic Hover Tokens
Feature Branch: 028-semantic-hover-tokens
Created: 2026-03-10
Status: Draft
Input: User description: "Unify hover color semantics across all interactive elements and make them globally configurable via CSS custom properties in the theme."
User Scenarios & Testing (mandatory)
User Story 1 - Theme Author Changes Hover Colors in One Place (Priority: P1)
A theme author (or future-self) wants to change the hover color for all editable fields across the app. They edit a single CSS custom property in the theme file and every editable field (name, initiative, HP, AC, conditions) updates its hover color consistently.
Why this priority: The entire point of this feature is centralizing hover color control. If tokens exist but aren't referenced everywhere, the feature delivers no value.
Independent Test: Change the neutral-interactive hover token value in the theme file and verify all editable fields reflect the new color without any other code changes.
Acceptance Scenarios:
- Given the theme defines a neutral-interactive hover token, When the token value is changed from grey-to-white to any other color, Then all editable fields (name, initiative, HP, AC, conditions) display the new hover color.
- Given the theme defines a primary-action hover token, When the token value is changed, Then the Add button and step forward/back navigation buttons display the new hover color.
- Given the theme defines a destructive-action hover token, When the token value is changed, Then the clear encounter and remove combatant buttons display the new hover color.
User Story 2 - Consistent Visual Language for Interaction Types (Priority: P1)
A user hovers over different interactive elements and perceives a consistent visual language: editable data fields share one hover style, primary action buttons share another, and destructive actions share a third. This replaces the current inconsistent mix where blue is used for both editable fields and navigation.
Why this priority: Consistent hover semantics improve usability by communicating interaction intent. This is the user-facing motivation for the feature.
Independent Test: Hover over each interactive element category and verify visual consistency within tiers and clear distinction between tiers.
Acceptance Scenarios:
- Given a combatant row is displayed, When the user hovers over the name, initiative, HP, or AC fields, Then each field transitions to the neutral-interactive hover color (a subtle grey-to-white shift).
- Given the top bar is displayed, When the user hovers over the Add button or step forward/back navigation, Then the element transitions to the primary-action hover color (blue).
- Given the combatant row or top bar is displayed, When the user hovers over the remove combatant button or clear encounter button, Then the element transitions to the destructive-action hover color (red).
- Given the condition tags on a combatant row, When the user hovers over a condition tag, Then it uses the neutral-interactive hover style, not the primary-action blue.
User Story 3 - No One-Off Hover Colors Remain (Priority: P2)
A developer reviewing the codebase finds no hardcoded hover color values outside the theme file. Every hover color reference uses one of the three semantic token classes.
Why this priority: Eliminating one-offs (like the amber hover) ensures long-term maintainability and prevents drift back to inconsistency.
Independent Test: Search the codebase for hover color classes that do not reference the three semantic tokens and confirm none exist in the affected components.
Acceptance Scenarios:
- Given the affected components (combatant-row, condition-tags, condition-picker, turn-navigation, action-bar), When a developer searches for hover color classes, Then every hover color reference resolves to one of the three semantic tokens.
- Given the current amber one-off hover color, When the feature is complete, Then the amber hover is replaced with the appropriate semantic token.
Edge Cases
- What happens when a component needs hover colors for both text and background? The tokens should support both text and background variants where needed (e.g., condition picker items use background hover, not text hover).
- What happens when hover colors interact with disabled states? Disabled elements should not display hover color changes regardless of token values.
- What happens when an element fits multiple tiers (e.g., clicking a condition tag both edits data and could be seen as an action)? The tier assignment is based on the primary interaction intent: editing data = neutral-interactive, triggering a distinct action = primary-action.
Requirements (mandatory)
Functional Requirements
- FR-001: The theme MUST define three semantic hover color tokens as CSS custom properties: one for neutral-interactive elements, one for primary-action elements, and one for destructive-action elements.
- FR-002: Neutral-interactive hover token MUST be used for all editable data fields: combatant name, initiative value, HP display, AC display, and condition tags.
- FR-003: Primary-action hover token MUST be used for navigation and additive action elements: Add Combatant button, step forward button, step back button, and Roll All button.
- FR-004: Destructive-action hover token MUST be used for removal and clearing actions: remove combatant button and clear encounter button.
- FR-005: Components MUST reference the semantic tokens via theme-aware classes, not hardcoded color values.
- FR-006: Changing a token value in the theme file MUST propagate to all components using that token without any other code changes.
- FR-007: The existing amber one-off hover color MUST be replaced with the appropriate semantic token.
- FR-008: Where components use hover background colors (e.g., condition picker items, navigation buttons), the semantic tokens MUST also provide background hover variants.
Key Entities
- Hover Token: A CSS custom property defining a semantic hover color. Has a name (e.g., neutral-interactive), a text color value, and optionally a background color value.
- Interaction Tier: A classification of interactive elements by intent — neutral-interactive (data editing), primary-action (navigation/creation), or destructive-action (removal/clearing).
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: All hover colors across the five affected components are controlled by exactly three semantic tokens — zero hardcoded hover color values remain in those components.
- SC-002: Changing any single hover token value updates every element in its tier — verified by modifying each token and confirming all associated elements reflect the change.
- SC-003: Users perceive three distinct hover color tiers when interacting with the app — neutral editing feels understated (grey-to-white), primary actions feel prominent (blue), and destructive actions feel cautionary (red).
- SC-004: No visual regressions in hover behavior — all elements that had hover states before the change still have hover states after.
Assumptions
- The three-tier system (neutral, primary, destructive) is sufficient for all current interactive elements. MVP baseline does not include additional tiers (e.g., warning, success).
- Background hover variants are needed only where components currently use background hover (condition-picker, navigation buttons). Text-only hover is the default.
- The default token values match the described colors: neutral = grey-to-white (#e2e8f0 or similar), primary = blue (#3b82f6), destructive = red (#ef4444).
- This feature is purely presentational — no domain or application layer changes are needed.