# PRD: Referral Onboarding Widget

## Introduction

Users who arrive at the signup page via a referral link (`?ref=<code>`) currently see a minimal green text banner. This is easy to miss and does not reinforce the discount incentive throughout the signup flow, leading to missed conversion opportunities. This PRD covers replacing that banner with a persistent, visually prominent referral widget that keeps the reward front-and-center from the moment the user lands until they complete signup.

**Scope:** Frontend-only changes to `signup.tsx` and `ReferralBanner.tsx`. No new pages, no post-signup changes, no backend work beyond what already exists.

---

## Goals

- Increase signup completion rate for referred users by making the discount offer clearly visible and persistent throughout the two-step signup flow
- Replace the existing minimal green banner with a dedicated referral widget card that matches the app's design system (indigo/purple palette, Tailwind, Radix UI)
- Ensure the widget is non-intrusive: it complements the signup form without competing with it
- Zero regression for users arriving without a referral code (widget must not render at all)

---

## User Stories

### US-001: Referral widget renders when `ref` param is present
**Description:** As a referred user, I want to immediately see my referral discount when I land on the signup page so that I'm motivated to complete signup.

**Acceptance Criteria:**
- [ ] When `?ref=<code>` is present in the URL, the `ReferralWidget` component renders on the signup page
- [ ] When no `ref` param is present, no widget renders (existing behavior preserved)
- [ ] Widget renders on both steps of the signup flow (form step and email verification step)
- [ ] Typecheck passes

### US-002: Widget displays referral benefit clearly
**Description:** As a referred user, I want to clearly understand what discount I'm getting so that I feel confident completing my account creation.

**Acceptance Criteria:**
- [ ] Widget displays a headline: "You've been referred — claim your reward"
- [ ] Widget displays the discount offer: "Get 20% off your first month when you complete signup"
- [ ] Widget displays the referral code in a visually distinct chip/badge (e.g. `Code: ABC123`)
- [ ] Widget uses the indigo-to-purple gradient palette consistent with the existing `ReferralBanner` component
- [ ] Widget is not dismissible (sticky throughout the flow)
- [ ] Typecheck passes
- [ ] Verify in browser using dev-browser skill

### US-003: Widget reflects active step in the signup flow
**Description:** As a referred user going through the two-step signup, I want the widget to acknowledge my progress so it feels like part of the flow.

**Acceptance Criteria:**
- [ ] On step 1 (form): Widget CTA copy reads "Fill in your details below to claim this offer"
- [ ] On step 2 (email verification): Widget copy updates to "Almost there — verify your email to lock in your 20% discount"
- [ ] Step transition does not cause the widget to flash or remount unnecessarily
- [ ] Typecheck passes
- [ ] Verify in browser using dev-browser skill

### US-004: Replace existing `ReferralBanner` with new `ReferralWidget`
**Description:** As a developer, I want the old ad-hoc green banner removed and replaced with the new widget so there is one canonical referral UI component.

**Acceptance Criteria:**
- [ ] The green `bg-green-50` banner in `signup.tsx` is removed
- [ ] `ReferralBanner.tsx` is updated (or replaced) to implement the new widget design
- [ ] No duplicate referral UI exists on the signup page
- [ ] Typecheck passes

---

## Functional Requirements

- **FR-1:** The widget must only render when the `ref` URL query parameter is non-empty.
- **FR-2:** The widget must remain visible on both step 1 (signup form) and step 2 (email verification) without requiring the URL param to persist after navigation (store the code in component state on mount).
- **FR-3:** The widget must display: (a) a reward headline, (b) the discount description ("20% off your first month"), and (c) the referral code value in a styled badge.
- **FR-4:** Widget copy must reflect the current signup step — different sub-copy for form step vs. verification step.
- **FR-5:** The widget must be positioned as a sticky card above or beside the signup form (not overlapping). On mobile, it stacks above the form. On desktop (≥768px), it can sit in a left or top position — layout decision deferred to design, but component must support both via props or CSS.
- **FR-6:** The existing referral code capture and API submission logic in `signup.tsx` (`referralCode` sent to `/api/auth/signup`) must remain unchanged.
- **FR-7:** The widget must not render any UI if `referralCode` is an empty string or undefined.

---

## Non-Goals

- No backend changes — referral code redemption, discount application, and validation are handled server-side and are out of scope
- No display of the referrer's name, avatar, or identity
- No post-signup onboarding checklist or reward tracking
- No dedicated referral landing page
- No A/B testing infrastructure
- No animation beyond standard Tailwind transitions
- No support for multiple referral codes or stacking discounts

---

## Design Considerations

- **Component to modify:** `src/components/ReferralBanner.tsx` — update or replace with new `ReferralWidget` design
- **Component to update:** `src/pages/signup.tsx` — remove existing green banner, integrate `ReferralWidget`, pass `step` prop
- **Color palette:** Maintain indigo-to-purple gradient (`from-indigo-500 to-purple-600`) already established in `ReferralBanner.tsx`
- **Referral code badge:** Small pill/chip, white background with indigo text, monospace font recommended
- **Icon:** Keep the celebration emoji (🎉) or swap for a Radix UI icon — designer's call
- **Responsive layout:** Widget stacks above form on mobile; side-by-side or top-card on desktop

### Suggested Component Interface

```tsx
interface ReferralWidgetProps {
  referralCode: string;
  step: 'form' | 'verification';
}
```

---

## Technical Considerations

- `referralCode` is already extracted from `router.query.ref` in `signup.tsx` and stored in local state — pass it directly as a prop to the widget
- The signup page already tracks a `step` state (`'form' | 'verify'`) — pass this as the `step` prop
- No new API calls needed; no new state needed
- Radix UI is available (already in `package.json`) for tooltip or badge primitives if needed
- Zustand is available but not needed for this scope

---

## Success Metrics

- Referred-user signup completion rate increases (baseline: measure current completion rate of users arriving with `?ref=` param before shipping)
- No increase in overall signup page error rate or load time
- Zero console errors or TypeScript errors introduced

---

## Open Questions

1. **Layout on desktop:** Should the widget sit to the left of the form (two-column) or above it (single-column stacked)? Needs design decision before implementation.
2. **Discount amount:** Is "20% off your first month" the correct, current copy? Confirm with product before final implementation.
3. **Code display:** Should the referral code be shown to the user at all, or just the benefit? (Currently the code is an opaque hash — may not be meaningful to users.)
4. **Analytics:** Should we fire any tracking event (e.g. `referral_widget_viewed`, `referral_signup_completed`) as part of this? Not scoped in but easy to add.
