Files
initiative/specs/028-semantic-hover-tokens/spec.md

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:

  1. 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.
  2. 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.
  3. 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:

  1. 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).
  2. 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).
  3. 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).
  4. 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:

  1. 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.
  2. 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.