V3 pricing flow: blue-600 → dealops-primary

Replace hardcoded Tailwind blue-* classes with brand dealops-primary tokens across the rep-facing Select Products page so CTAs and selection states match the rest of the product.

Author @yijunz166 PR dealops#5825 Branch yijun/v3-fix-blue-to-dealops-primary Files 5 Δ +33 / −33 Scope PricingFlowV3 State Open

What it changes
Five components in the V3 Select Products page swap raw blue-600/700 Tailwind classes for the brand dealops-primary token, matching DealopsButton.
Why
Hardcoded blue clashed with the dealops palette on the rep-facing flow. The Continue CTA, use-case pill, facet chips, and modal link/CTA all looked off-brand.
Risk
Pure CSS/className change. No logic, no props, no state. Worst case is a visual regression bounded to PricingFlowV3.

1. Why this exists

PricingFlowV3 is the current rep-facing pricing UI. Several primitive components inside its Select Products page were styled with raw Tailwind bg-blue-600 / text-blue-600 utilities rather than the brand token used everywhere else (dealops-primary, which DealopsButton already consumes). That meant the Continue button, the active Use Case pill, and the modal link CTA rendered in a different blue from the surrounding chrome.

This PR is a straight token swap — no behavior changes, no new props.

2. Before / after

Before — hardcoded blue
Continue CTA
Continue
Active facet / use-case pill
Renewals
Modal link trigger
Configure section
After — dealops-primary
Continue CTA
Continue
Active facet / use-case pill
Renewals
Modal link trigger
Configure section

Swatches above approximate the Tailwind defaults (blue-600 ≈ #2563eb) and the dealops brand indigo. Exact dealops-primary value comes from the consuming theme config; the point is they are different, and the V3 page was using the wrong one.

3. Files touched

4. The token swap, by file

Component Before After
ProductSelectionPage
Continue / Finish button
bg-blue-600 ... hover:bg-blue-700 bg-dealops-primary ... hover:bg-dealops-primary/90
FacetBar
Active facet chip
border-blue-600 bg-blue-600 text-white border-dealops-primary bg-dealops-primary text-dealops-primaryForeground
SectionFacetBar
Section-scoped facet chip
border-blue-600 bg-blue-600 text-white border-dealops-primary bg-dealops-primary text-dealops-primaryForeground
ModalSectionTrigger
Link trigger + modal Confirm
text-blue-600 hover:text-blue-700
bg-blue-600 hover:bg-blue-700
text-dealops-primary hover:text-dealops-primary/90
bg-dealops-primary hover:bg-dealops-primary/90

5. The one outlier: UseCaseSelector

Four of the five files are pure className swaps. UseCaseSelector.tsx is the exception: +28 / −28 reflects a small structural rewrite, not just a color change. The use-case picker was reshaped from a row of pill buttons + manual "clear" button into a Shadcn Select dropdown.

Before — pill row

A horizontal flex-wrap row of <button> pills, one per use case. Active pill rendered in blue-600. A separate "clear" pill appeared when something was selected.

{values.map((v) => (
  <button onClick={() => select(isOn ? null : v)}
    className={isOn
      ? 'border-blue-600 bg-blue-600 text-white'
      : 'border-gray-300 bg-white ...'}>
    {v}
  </button>
))}
{current ? <button>clear</button> : null}
After — Shadcn Select

A single <Select> with a 300px trigger. A sentinel value __all__ represents "no use case selected", since Radix Select rejects empty-string values.

<Select value={current ?? ALL_USE_CASES}
  onValueChange={(val) =>
    select(val === ALL_USE_CASES ? null : val)}>
  <SelectTrigger className="w-[300px]">
    <SelectValue placeholder="Select use case" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value={ALL_USE_CASES}>All use cases</SelectItem>
    {values.map((v) => (
      <SelectItem key={v} value={v}>{v}</SelectItem>
    ))}
  </SelectContent>
</Select>
Heads up for review: the PR title and description describe a pure color swap, but UseCaseSelector also changes the control type (pill row → dropdown). That's a UX change worth flagging — long use-case lists no longer wrap; the user has to open a menu. Worth confirming this was intentional and not accidentally bundled into a styling PR.

6. What it doesn't change

7. Risk & rollback

Low risk. Four of five files are className-only. Rollback is a straight revert of the branch — no migrations, no feature flags, no data shape changes. The only behavior shift is the use-case picker rendering as a dropdown instead of a pill row, which is visible immediately on the Select Products page if it regresses.