7.0 KiB
Research: Semantic Hover Tokens
R-001: Tailwind v4 Theme Token Mechanism
Decision: Define new CSS custom properties in the @theme block of index.css. Tailwind v4 automatically makes --color-* variables available as utility classes (e.g., --color-hover-neutral → text-hover-neutral, bg-hover-neutral).
Rationale: The project already uses this pattern for --color-primary, --color-destructive, etc. Adding new tokens follows the established convention and requires zero config changes.
Alternatives considered:
- Tailwind plugin extending theme: Unnecessary — Tailwind v4 CSS-native theming handles this.
- CSS-only approach without Tailwind utilities: Would lose the
hover:text-*class syntax that all components already use.
R-002: Scope of Affected Components
Decision: The spec lists five components, but the audit found hover colors in additional files: hp-adjust-popover.tsx, stat-block-panel.tsx, bestiary-search.tsx, ac-shield.tsx, and ui/button.tsx. The plan will address the five specified components plus ac-shield.tsx (already uses hover:text-primary for an editable field). The HP adjust popover's semantic damage/healing colors are out of scope — they represent domain-semantic colors (damage=red, healing=green) rather than interaction-tier hover colors. The button.tsx CVA variants were initially out of scope but were brought in during implementation (see R-007).
Rationale: The HP popover buttons communicate game semantics (damage vs. healing), not interaction intent. Forcing them into the three-tier system would reduce clarity. stat-block-panel.tsx and bestiary-search.tsx use hover:text-foreground which already matches the neutral-interactive intent (dim→bright) — these can adopt the neutral token.
Alternatives considered:
- Include all hover colors across all components: Over-scoped; HP popover serves a different purpose.
- Strictly limit to five listed files: Would miss
ac-shield.tsxwhich is clearly neutral-interactive.
R-003: Token Naming Convention
Decision: Use --color-hover-neutral, --color-hover-action, --color-hover-destructive as the CSS custom property names. This yields Tailwind classes like hover:text-hover-neutral, hover:bg-hover-action, etc.
Rationale: The hover- prefix groups them visually in the theme. The tier names (neutral/action/destructive) are concise and parallel the existing --color-primary/--color-destructive naming.
Alternatives considered:
--color-interactive-*: Longer, and "interactive" is redundant since hover already implies interaction.--color-hover-primaryfor the action tier: Conflicts conceptually with existing--color-primary(which is used for non-hover purposes too).
R-004: Background Hover Variants
Decision: Define three additional background tokens: --color-hover-neutral-bg, --color-hover-action-bg, --color-hover-destructive-bg. Components that use hover:bg-* will reference these.
Rationale: Several components use background hovers (condition-picker hover:bg-card, navigation buttons hover:bg-muted, bestiary items hover:bg-accent/10). A single text-only token won't cover these cases.
Alternatives considered:
- Reuse existing
--color-card/--color-mutedfor background hovers: Breaks the single-point-of-change goal — changing the neutral hover background would also change all card backgrounds. - No background tokens (text-only): Would leave background hovers hardcoded, defeating the purpose.
R-005: Default Token Values
Decision: Map defaults to preserve current visual appearance:
--color-hover-neutral: var(--color-primary)(#3b82f6 — blue, matching previoushover:text-primarybehavior)--color-hover-action: var(--color-primary)(#3b82f6 — blue)--color-hover-destructive: var(--color-destructive)(#ef4444 — red)--color-hover-neutral-bg: var(--color-card)(#1e293b)--color-hover-action-bg: var(--color-muted)(#64748b — defined but not used by nav buttons, see R-008)--color-hover-destructive-bg: transparent(current destructive hovers are text-only in scope)
Rationale: Using var() references means the hover tokens inherit from the base theme by default, reducing duplication. The neutral token was initially var(--color-foreground) but changed to var(--color-primary) during implementation because elements already at text-foreground (name, initiative, HP) had no visible hover change — the hover target color was identical to the resting color. Using var(--color-primary) preserves the original blue hover feedback while still centralizing control.
Alternatives considered:
- Hardcode hex values: Would break the cascade if base theme colors change.
- Fewer background tokens: The action and neutral backgrounds serve different purposes currently.
--color-hover-neutral: var(--color-foreground): No visible hover for elements already at foreground color — rejected during implementation.
R-006: Components Using hover:text-foreground
Decision: stat-block-panel.tsx and bestiary-search.tsx close buttons use hover:text-foreground (dim→bright). These will migrate to hover:text-hover-neutral since the default value of --color-hover-neutral is var(--color-primary) — providing a blue hover instead of the previous dim→bright.
Rationale: Consistent with the neutral-interactive tier. These are close/dismiss actions, not destructive (they don't delete data).
R-007: Button Component (ui/button.tsx) Brought Into Scope
Decision: Migrate the outline and ghost CVA variant hover styles in ui/button.tsx from hardcoded hover:bg-card hover:text-foreground to hover:bg-hover-neutral-bg hover:text-hover-neutral.
Rationale: Initially excluded as a shared UI primitive (R-002). During implementation, the ghost variant's hover:text-foreground produced no visible hover on the search button (same issue as R-005 — foreground→foreground). Additionally, the outline variant's hover:bg-card conflicted with inline hover:bg-hover-action-bg on the nav buttons, creating a double-background hover artifact. Migrating the Button variants to semantic tokens resolved both issues.
Alternatives considered:
- Keep button.tsx out of scope: Would leave the search button without visible hover and nav buttons with conflicting hover backgrounds.
R-008: Nav Button Background Hover Removed
Decision: The Previous/Next outline buttons in turn-navigation.tsx use hover:bg-transparent instead of hover:bg-hover-action-bg. The blue text + blue border provide sufficient hover feedback without a background fill.
Rationale: The --color-hover-action-bg default (var(--color-muted) = #64748b) created a heavy filled-box appearance on the small outline icon buttons. Combined with the blue border and icon, the solid grey background was visually overwhelming. Removing it produces a cleaner hover state.
Alternatives considered:
- Keep
hover:bg-hover-action-bg: Visually heavy on small outline buttons. - Use a semi-transparent background: Adds complexity for marginal benefit.