- {/* sr-only progress summary */}
-
- {i18n.stepsCompletedLabel(completedCount, sortedSteps.length)}{" "}
- {i18n.percentCompleteLabel(progressPercent)}
-
-
- {/* Assertive live region for step-change announcements */}
-
- {state.announcementText}
-
-
- {/* Polite pending indicator */}
- {state.isPending && (
-
- {i18n.updating}
-
- )}
-
- {/* ── Card ──────────────────────────────────────────────────────────── */}
-
- {/* ── Header ──────────────────────────────────────────────────────── */}
-
-
-
- {i18n.title}
-
-
- {i18n.percentCompleteLabel(progressPercent)}
-
-
-
-
- {i18n.subtitle}
-
-
- {/* Progress bar */}
-
-
-
-
- {/* Step count summary line */}
-
- {i18n.stepsCompletedLabel(completedCount, sortedSteps.length)}
- {isComplete && (
-
-
- {i18n.allCompleted}
-
- )}
-
-
-
- {/* ── Steps list ───────────────────────────────────────────────────── */}
-
-
- {sortedSteps.map((step, index) => {
- const isCurrent = effectiveCurrentStep === step.id;
- const isPending = state.isPending && isCurrent;
- const stepDescId = `${progressSummaryId}-desc-${index}`;
-
- const indicatorColorClass = step.completed
- ? "border-pluto-500 bg-pluto-100 text-pluto-800 shadow-[0_4px_12px_rgba(74,111,165,0.18)] dark:border-pluto-400 dark:bg-pluto-800/60 dark:text-pluto-100"
- : isCurrent
- ? "border-pluto-600 bg-pluto-50 text-pluto-700 shadow-[0_4px_12px_rgba(74,111,165,0.14)] dark:border-pluto-400 dark:bg-pluto-900/60 dark:text-pluto-200"
- : "border-pluto-200 bg-white text-pluto-600 dark:border-pluto-700 dark:bg-pluto-900/40 dark:text-pluto-400 group-hover:border-pluto-400 group-hover:bg-pluto-50 dark:group-hover:border-pluto-500 dark:group-hover:bg-pluto-800/50";
-
- return (
-
- {/* Step indicator button */}
-
-
- {/* Step text content */}
-
-
- {step.title}
- {step.required && (
-
- *
-
- )}
-
-
-
- {step.description}
-
-
-
-
-
- {/* Vertical connector line */}
- {orientation === "vertical" && index < sortedSteps.length - 1 && (
-
- )}
-
- );
- })}
-
-
-
- {/* ── Completion banner ─────────────────────────────────────────────── */}
-
- {isComplete && sortedSteps.length > 0 && (
-
-
-
-
-
-
-
- {i18n.successTitle}
-
-
- {i18n.successMessage}
-
-
-
-
- )}
-
-
-
- );
-});
-
-export default OnboardingProgressTracker;
+"use client";
+
+/**
+ * OnboardingProgressTracker
+ *
+ * Refactored for full i18n support via the "onboarding" next-intl namespace.
+ *
+ * Additional improvements:
+ * - All user-visible strings sourced from useOnboardingI18n (no hardcoded English)
+ * - Dark mode: dark: Tailwind variants on every surface, border, text, gradient
+ * - Mobile-first responsive layout (vertical default, horizontal on sm+)
+ * - Improved a11y: translated aria-labels, aria-busy spinner, focus-visible rings
+ * - StepIcon and StatusBadge extracted as memoised sub-components
+ * - prefers-reduced-motion respected throughout
+ * - Connector lines between vertical steps
+ */
+
+import React, { memo } from "react";
+import {
+ motion,
+ AnimatePresence,
+ useReducedMotion,
+ type Variants,
+} from "framer-motion";
+import {
+ useOnboardingProgress,
+ type OnboardingStep,
+} from "@/hooks/useOnboardingProgress";
+import { useOnboardingI18n } from "@/hooks/useOnboardingI18n";
+
+// ── Re-export so consumers need only one import ───────────────────────────────
+export type { OnboardingStep };
+
+// ── Props ─────────────────────────────────────────────────────────────────────
+
+export interface OnboardingProgressTrackerProps {
+ steps: OnboardingStep[];
+ currentStep?: string;
+ onStepChange?: (stepId: string) => void | Promise