@wireai/activation 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/theme/defaultTheme.ts","../../src/theme/ThemeContext.tsx","../../src/theme/typography.ts","../../src/motion/motionSpec.ts","../../src/motion/useReducedMotion.ts","../../src/components/Button.tsx","../../src/motion/centeredModalMotion.ts","../../src/components/CenteredModal.tsx","../../src/components/DoneCheck.tsx","../../src/components/CardHandoff.tsx","../../src/components/ModalPaneHost.tsx","../../src/components/StepDots.tsx","../../src/haptics/haptics.ts","../../src/reviews/feedbackForm.ts","../../src/theme/mergeThemeOver.ts","../../src/reviews/decision.ts","../../src/questionnaire/decision.ts","../../src/questionnaire/steps.ts","../../src/questionnaire/transport.ts","../../src/questionnaire/QuestionnaireGate.tsx","../../src/coachmarks/runtime.ts","../../src/features/defaults.ts","../../src/features/cache.ts","../../src/features/fetchWireFeatures.ts","../../src/features/useWireFeatures.ts","../../src/features/WireFeaturesProvider.tsx","../../src/reviews/equality.ts","../../src/reviews/runtime.ts","../../src/questionnaire/runtime.ts","../../src/questionnaire/useQuestionnaireGate.ts"],"names":["createContext","useContext","useState","useEffect","AccessibilityInfo","useRef","Animated","useCallback","jsx","Pressable","Text","React","StyleSheet","forwardRef","Easing","useImperativeHandle","BackHandler","jsxs","Modal","styles","SafeAreaView","Fragment","easeWire","View","useMemo","_a","_b","_c","TextInput","useStableValue","testing"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * defaultOnboardingTheme — a neutral, light, brand-agnostic baseline. Consumers\n * pass a `Partial<OnboardingTheme>` that is deep-merged over this (see\n * `mergeTheme`), so they only override what differs from neutral.\n */\nimport type { OnboardingTheme } from \"./types\";\n\nexport const defaultOnboardingTheme: OnboardingTheme = {\n colors: {\n background: \"#FFFFFF\",\n surface: \"#F7F7F8\",\n text: \"#101114\",\n textMuted: \"#6B7280\",\n primary: \"#111111\",\n onPrimary: \"#FFFFFF\",\n primarySoft: \"rgba(17,17,17,0.06)\",\n border: \"#E4E4E7\",\n borderStrong: \"#C7C7CC\",\n disabled: \"#EBEBEB\",\n success: \"#16A34A\",\n warning: \"#D97706\",\n error: \"#DC2626\",\n info: \"#2563EB\",\n },\n fonts: {\n regular: undefined,\n medium: undefined,\n bold: undefined,\n baseSize: 16,\n scale: 1,\n },\n radius: {\n sm: 8,\n md: 12,\n lg: 16,\n full: 9999,\n },\n spacing: {\n xs: 4,\n sm: 8,\n md: 16,\n lg: 24,\n xl: 32,\n },\n // Circled (pill) CTA by default; an app can pass `button: { radius: 12 }` for\n // a rounded rectangle, or override height/paddingX to match its design system.\n button: {\n radius: 9999,\n height: 52,\n paddingX: 24,\n },\n};\n\n/**\n * Deep-merge a partial theme over the default. Two levels deep is enough — the\n * theme is intentionally shallow (colors/fonts/radius/spacing), so we merge each\n * known sub-object and leave scalars to overwrite.\n */\nexport const mergeTheme = (\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return defaultOnboardingTheme;\n return {\n colors: { ...defaultOnboardingTheme.colors, ...override.colors },\n fonts: { ...defaultOnboardingTheme.fonts, ...override.fonts },\n radius: { ...defaultOnboardingTheme.radius, ...override.radius },\n spacing: { ...defaultOnboardingTheme.spacing, ...override.spacing },\n button: { ...defaultOnboardingTheme.button, ...override.button },\n };\n};\n","/**\n * ThemeContext — provides the resolved OnboardingTheme to every shell element and\n * themed card via `useOnboardingTheme()`. WHY a context rather than prop-drilling:\n * the cards are mounted by the SDK's ComponentRenderer (not by us), so we can't\n * pass them props directly — they must read the theme from context.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\nimport { mergeTheme } from \"./defaultTheme\";\nimport type { OnboardingTheme } from \"./types\";\n\nconst OnboardingThemeContext = createContext<OnboardingTheme | null>(null);\n\nexport type OnboardingThemeProviderProps = {\n /** Partial overrides merged over the neutral default theme. */\n theme?: Partial<OnboardingTheme>;\n children: React.ReactNode;\n};\n\nexport const OnboardingThemeProvider: React.FC<OnboardingThemeProviderProps> = ({\n theme,\n children,\n}) => {\n const resolved = useMemo(() => mergeTheme(theme), [theme]);\n return (\n <OnboardingThemeContext.Provider value={resolved}>\n {children}\n </OnboardingThemeContext.Provider>\n );\n};\n\n/**\n * Read the active theme. Falls back to the default theme when used outside a\n * provider so a stray card never crashes — it just renders neutral.\n */\nexport const useOnboardingTheme = (): OnboardingTheme => {\n const ctx = useContext(OnboardingThemeContext);\n return ctx ?? mergeTheme();\n};\n","/**\n * typography — derive concrete RN text styles from the theme's font config, so\n * every label/title/caption in the kit scales from one `baseSize` + `scale` and\n * picks the right family. Cards call these instead of hardcoding fontSize/weight.\n */\nimport type { TextStyle } from \"react-native\";\nimport type { OnboardingFonts } from \"./types\";\n\nconst round = (n: number) => Math.round(n);\n\n/** Body text — the reference size. */\nexport const bodyStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.regular,\n fontSize: round(f.baseSize * f.scale),\n lineHeight: round(f.baseSize * f.scale * 1.5),\n});\n\n/** Slightly smaller secondary/hint text. */\nexport const captionStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.regular,\n fontSize: round(f.baseSize * 0.8125 * f.scale),\n lineHeight: round(f.baseSize * 0.8125 * f.scale * 1.5),\n});\n\n/** Emphasised label (e.g. a card question). */\nexport const labelStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.medium ?? f.bold,\n fontSize: round(f.baseSize * f.scale),\n lineHeight: round(f.baseSize * f.scale * 1.4),\n fontWeight: f.medium ? undefined : (\"600\" as const),\n});\n\n/** Heading (status title, done block). */\nexport const headingStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.bold,\n fontSize: round(f.baseSize * 1.25 * f.scale),\n lineHeight: round(f.baseSize * 1.25 * f.scale * 1.3),\n fontWeight: f.bold ? undefined : (\"700\" as const),\n});\n\n/** Button label. */\nexport const buttonLabelStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.bold ?? f.medium,\n fontSize: round(f.baseSize * f.scale),\n fontWeight: f.bold ? undefined : (\"600\" as const),\n});\n","/**\n * motionSpec — the single source of truth for every animation value in the kit,\n * extracted 1:1 from the Wire Activation card-interactions design canvas\n * (see design-refs/EXTRACTED-SPEC.md for the row-by-row mapping).\n *\n * Pure constants + pure helpers only — NO react-native import — so the spec is\n * unit-testable under node:test and components can't drift from the design\n * without a red test.\n */\n\n/** The design system's \"ease-wire\" curve: cubic-bezier(0.16, 1, 0.3, 1). */\nexport const WIRE_BEZIER = [0.16, 1, 0.3, 1] as const;\n\n/** Design-system duration tokens (colors_and_type.css --duration-*). */\nexport const DURATION_FAST_MS = 150;\nexport const DURATION_BASE_MS = 300;\nexport const DURATION_SLOW_MS = 500;\n\n/** Reduce-motion fallback: a short fade to the final frame, never a frozen mid-state. */\nexport const REDUCED_FADE_MS = 120;\n\n// ── Press feedback (spec rows 1, 4, 20) ─────────────────────────────────────\nexport const ROW_PRESS_SCALE = 0.975;\nexport const CHIP_PRESS_SCALE = 0.94;\nexport const BUTTON_PRESS_SCALE = 0.975;\n/** Reduce-motion press feedback: opacity dip instead of scale. */\nexport const REDUCED_PRESS_OPACITY = 0.85;\nexport const PRESS_SPRING = { friction: 8, tension: 220 } as const;\nexport const BUTTON_PRESS_SPRING = { friction: 8, tension: 240 } as const;\n\n// ── Selection state changes (spec rows 2, 3, 5, 6) ──────────────────────────\nexport const SELECT_FILL_MS = 180;\nexport const CHIP_FILL_MS = 160;\nexport const CHECK_SPRING = { friction: 6, tension: 180 } as const;\nexport const CHECK_SCALE_FROM = 0.6;\n\n// ── Card-to-card handoff (spec rows 7-10) ───────────────────────────────────\nexport const CARD_ENTER_MS = 220;\nexport const CARD_EXIT_MS = 180;\n/** The exit starts this long BEFORE the enter (enter is delayed by this). */\nexport const CARD_EXIT_LEAD_MS = 80;\nexport const CARD_SLIDE_PX = 26;\nexport const CARD_ENTER_SCALE_FROM = 0.96;\n/** The interstitial keeps the shell's springier value-beat (AnimatedCard idiom). */\nexport const CARD_SPRING = { damping: 14, stiffness: 180, mass: 1 } as const;\n/** Loader-to-card handoff: the loader just fades out. */\nexport const LOADER_HANDOFF_FADE_MS = 120;\n\n// ── InterstitialCard reveal (spec rows 11-13) ───────────────────────────────\nexport const INTERSTITIAL_HEAD_MS = 500;\nexport const INTERSTITIAL_HEAD_STAGGER_MS = 100;\nexport const INTERSTITIAL_ITEM_MS = 300;\nexport const INTERSTITIAL_ITEM_STAGGER_MS = 90;\nexport const INTERSTITIAL_ITEM_BASE_DELAY_MS = 200;\nexport const INTERSTITIAL_CHECK_DELAY_MS = 200;\nexport const INTERSTITIAL_CHECK_SCALE_FROM = 0.4;\n\n/** Delay before work item `index` begins its reveal (row lands after the head). */\nexport const interstitialItemDelay = (index: number): number =>\n INTERSTITIAL_ITEM_BASE_DELAY_MS + index * INTERSTITIAL_ITEM_STAGGER_MS;\n\n/** Delay before work item `index`'s check pops (200ms after its row starts). */\nexport const interstitialCheckDelay = (index: number): number =>\n interstitialItemDelay(index) + INTERSTITIAL_CHECK_DELAY_MS;\n\n// ── Status / completion payoff (spec rows 14-16) ────────────────────────────\nexport const STATUS_POP_SPRING = { friction: 6, tension: 200 } as const;\nexport const STATUS_POP_SCALE_FROM = 0.4;\nexport const STATUS_BURST_MS = 500;\nexport const STATUS_BURST_SCALE_FROM = 0.4;\nexport const STATUS_BURST_SCALE_TO = 1.5;\nexport const STATUS_BURST_OPACITY_FROM = 0.5;\nexport const STATUS_COPY_MS = 300;\nexport const STATUS_COPY_STAGGER_MS = 80;\n/** Copy starts settling once the badge pop is visibly underway. */\nexport const STATUS_COPY_BASE_DELAY_MS = 200;\n\n/** Delay before payoff copy line `index` fades up. */\nexport const statusCopyDelay = (index: number): number =>\n STATUS_COPY_BASE_DELAY_MS + index * STATUS_COPY_STAGGER_MS;\n\n// ── Loading treatment (spec rows 17-19) ─────────────────────────────────────\nexport const LOADER_PULSE_MS = 1600;\nexport const LOADER_PULSE_MIN_OPACITY = 0.35;\nexport const LOADER_ORBIT_MS = 2400;\n/** Skeleton lines appear only when the fetch runs past this. */\nexport const SKELETON_DELAY_MS = 300;\nexport const SKELETON_PULSE_MS = 1500;\nexport const SKELETON_MIN_OPACITY = 0.45;\n\n// ── Progress bar (spec row 21) ──────────────────────────────────────────────\nexport const PROGRESS_MS = 400;\n\n// ── Dev/QA duration scale (slow-mo for judging motion) ──────────────────────\n// A module-level multiplier applied to every timing DURATION (and stagger\n// delay) at animation start. 1 = design speed; 2 = half-speed slow-mo. Springs\n// are physics-based (friction/tension) and do NOT scale. This is a dev/QA tool\n// (the playground's tweak panel drives it) — production code never calls the\n// setter, so the default 1 keeps shipped motion exactly on spec.\n\nlet durationScale = 1;\n\n/** Set the global duration multiplier (clamped to 0.1-10; invalid resets to 1). */\nexport const setMotionDurationScale = (scale: number): void => {\n durationScale = Number.isFinite(scale) && scale > 0 ? Math.min(10, Math.max(0.1, scale)) : 1;\n};\n\nexport const getMotionDurationScale = (): number => durationScale;\n\n/** Apply the current duration scale to a spec duration/delay (rounded ms). */\nexport const scaledMs = (ms: number): number => Math.round(ms * durationScale);\n\n// ── Reduce-motion helpers (pure, shared by every animated component) ────────\n\nexport type EntranceSpec = {\n /** Duration to animate with (falls back to the short fade under reduce motion). */\n duration: number;\n /** Whether transforms (translate/scale) may move; false = opacity-only fade. */\n useTransform: boolean;\n};\n\n/** Entrances: full motion normally; a 120ms opacity-only fade under reduce motion. */\nexport const entranceSpec = (reduced: boolean, durationMs: number): EntranceSpec =>\n reduced\n ? { duration: REDUCED_FADE_MS, useTransform: false }\n : { duration: durationMs, useTransform: true };\n\n/** State changes (select fills etc.): snap instantly under reduce motion. */\nexport const stateChangeDuration = (reduced: boolean, durationMs: number): number =>\n reduced ? 0 : durationMs;\n\n/** Looping/ambient animations run only when motion is allowed. */\nexport const loopEnabled = (reduced: boolean): boolean => !reduced;\n","/**\n * useReducedMotion — the kit's ONE reduce-motion gate. Reads the OS setting via\n * AccessibilityInfo and stays subscribed to `reduceMotionChanged`, so every\n * animated component lands on its final frame (or a ~120ms fade) the moment the\n * user flips the setting — no restart needed.\n *\n * This closes the gap documented in ai_rules/rules/performance.md §3: every\n * animation in the kit must consume this hook (usually through the pure helpers\n * in motionSpec.ts: `entranceSpec` / `stateChangeDuration` / `loopEnabled`).\n */\nimport { useEffect, useState } from \"react\";\nimport { AccessibilityInfo } from \"react-native\";\n\n// Last-known value, module-level: cards remount every turn (keyed on message id),\n// and a `useState(false)` default would flash one animated frame per turn for a\n// reduce-motion user before the async read resolves.\nlet lastKnown = false;\n\nexport const useReducedMotion = (): boolean => {\n const [reduced, setReduced] = useState(lastKnown);\n\n useEffect(() => {\n let mounted = true;\n AccessibilityInfo.isReduceMotionEnabled()\n .then((value) => {\n lastKnown = value;\n if (mounted) setReduced(value);\n })\n .catch(() => {\n // Unavailable (e.g. some test envs): keep the last-known value.\n });\n const sub = AccessibilityInfo.addEventListener(\"reduceMotionChanged\", (value) => {\n lastKnown = value;\n setReduced(value);\n });\n return () => {\n mounted = false;\n sub?.remove();\n };\n }, []);\n\n return reduced;\n};\n","/**\n * Button — the kit's themed primary/outline button, replacing the SDK's hardcoded\n * `Btn`. Every color/radius/font comes from the active theme.\n *\n * Motion (design-refs/EXTRACTED-SPEC.md row 20): \"a footer button that answers\n * the tap\" — scale 1→0.975 spring on press-in, back on release, native driver.\n * Reduce motion: an opacity dip to 0.85 while pressed, no scale. Disabled keeps\n * the `disabled` token fill with no press handler (unchanged).\n */\nimport React, { useCallback, useRef } from \"react\";\nimport { Animated, Pressable, StyleSheet, Text } from \"react-native\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport { buttonLabelStyle } from \"../theme/typography\";\nimport {\n BUTTON_PRESS_SCALE,\n BUTTON_PRESS_SPRING,\n REDUCED_FADE_MS,\n REDUCED_PRESS_OPACITY,\n scaledMs,\n} from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\n\ntype Variant = \"primary\" | \"outline\";\n\ntype ButtonProps = {\n title: string;\n onPress?: () => void;\n variant?: Variant;\n disabled?: boolean;\n /** Stretch to the container width — for form-style CTAs (e.g. the review form's\n * \"Send feedback\"). Default false keeps the content-width pill used by cards. */\n fullWidth?: boolean;\n};\n\nconst _Button: React.FC<ButtonProps> = ({\n title,\n onPress,\n variant = \"primary\",\n disabled = false,\n fullWidth = false,\n}) => {\n const t = useOnboardingTheme();\n const reduced = useReducedMotion();\n const isPrimary = variant === \"primary\";\n\n // 0 = at rest, 1 = pressed. Scale normally; opacity dip under reduce motion.\n const pressT = useRef(new Animated.Value(0)).current;\n const pressTo = useCallback(\n (to: number) => {\n if (reduced) {\n Animated.timing(pressT, {\n toValue: to,\n duration: scaledMs(REDUCED_FADE_MS),\n useNativeDriver: true,\n }).start();\n return;\n }\n Animated.spring(pressT, {\n toValue: to,\n friction: BUTTON_PRESS_SPRING.friction,\n tension: BUTTON_PRESS_SPRING.tension,\n useNativeDriver: true,\n }).start();\n },\n [pressT, reduced],\n );\n const lastPress = useRef<number>(0);\n const handlePress = useCallback(() => {\n if (!onPress) return;\n const now = Date.now();\n if (now - lastPress.current < 500) return;\n lastPress.current = now;\n onPress();\n }, [onPress]);\n\n const handlePressIn = useCallback(() => pressTo(1), [pressTo]);\n const handlePressOut = useCallback(() => pressTo(0), [pressTo]);\n\n const scale = pressT.interpolate({\n inputRange: [0, 1],\n outputRange: [1, reduced ? 1 : BUTTON_PRESS_SCALE],\n });\n const opacity = pressT.interpolate({\n inputRange: [0, 1],\n outputRange: [1, reduced ? REDUCED_PRESS_OPACITY : 1],\n });\n\n return (\n <Pressable\n onPress={disabled ? undefined : handlePress}\n onPressIn={disabled ? undefined : handlePressIn}\n onPressOut={disabled ? undefined : handlePressOut}\n disabled={disabled}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled }}\n style={fullWidth ? styles.fill : undefined}\n >\n <Animated.View\n style={[\n styles.base,\n fullWidth && styles.fill,\n {\n borderRadius: t.button.radius,\n minHeight: t.button.height,\n paddingHorizontal: t.button.paddingX,\n opacity,\n transform: [{ scale }],\n },\n isPrimary\n ? { backgroundColor: disabled ? t.colors.disabled : t.colors.primary }\n : { borderWidth: 1.5, borderColor: disabled ? t.colors.border : t.colors.primary },\n ]}\n >\n <Text\n style={[\n buttonLabelStyle(t.fonts),\n {\n color: disabled\n ? t.colors.textMuted\n : isPrimary\n ? t.colors.onPrimary\n : t.colors.primary,\n },\n ]}\n >\n {title}\n </Text>\n </Animated.View>\n </Pressable>\n );\n};\n\nexport const Button = React.memo(_Button);\n\nconst styles = StyleSheet.create({\n base: { alignItems: \"center\", justifyContent: \"center\" },\n fill: { width: \"100%\" },\n});\n","/**\n * centeredModalMotion - the pure entrance spec for the content-agnostic CenteredModal shell.\n *\n * WHY split out: the shell UI (CenteredModal) is RN and cannot run under the kit's node:test\n * runner, but the entrance math is pure and worth pinning. Keep the animation spec here so both\n * the component and the tests read one source, and so any module (reviews, questionnaire) can\n * reuse the shell without depending on another feature module.\n *\n * The centered popup uses RN's built-in `Animated` (native driver), the same idiom as\n * CompletionView/CardHandoff, so the shell stays dependency-free (no reanimated).\n *\n * NOTE: `reviews/presentation.ts` re-exports these under their original names\n * (`REVIEW_MODAL_ANIM`, `entranceFrame`) for back-compat with the reviews public API.\n */\n\n/**\n * The entrance spec for the centered popup. Values chosen to match the boilerplate's\n * `animated-modal` feel (a springy zoom-in) with the kit's own native-driver idiom:\n * • backdrop fades 0 -> `backdropOpacity`\n * • card springs from `scaleFrom` -> 1 and fades 0 -> 1\n */\nexport const CENTERED_MODAL_ANIM = {\n /** Spring config for the card scale/opacity entrance (mirrors CompletionView's pop). */\n enterSpring: { friction: 7, tension: 80 },\n /** Exit timing in ms (fade + shrink back out before unmount). */\n exitMs: 160,\n /** Card scale at rest (progress 0); grows to 1 at progress 1. */\n scaleFrom: 0.9,\n /** Peak dim of the backdrop at progress 1. */\n backdropOpacity: 0.55,\n} as const;\n\n/** A single frame of the entrance, for a progress value in [0..1] (clamped). Pure, testable. */\nexport const centeredModalFrame = (\n progress: number,\n backdropMax: number = CENTERED_MODAL_ANIM.backdropOpacity,\n): { cardOpacity: number; cardScale: number; backdropOpacity: number } => {\n const p = progress < 0 ? 0 : progress > 1 ? 1 : progress;\n const { scaleFrom } = CENTERED_MODAL_ANIM;\n return {\n cardOpacity: p,\n cardScale: scaleFrom + (1 - scaleFrom) * p,\n backdropOpacity: backdropMax * p,\n };\n};\n","/**\n * CenteredModal - the content-agnostic centered-popup shell.\n *\n * Renders its children as an alert-style card in the MIDDLE of the screen, over a dimmed\n * backdrop, with a spring/fade entrance. It knows nothing about what it presents: the reviews\n * gate uses it (via the `ReviewModal` back-compat re-export) and the questionnaire module reuses\n * the same shell, neither depends on the other.\n *\n * Adapted from the mobile-launcher boilerplate's `animated-modal` (transparent RN Modal +\n * centered container + backdrop-tap dismiss + content stop-propagation + springy zoom-in), but\n * reimplemented on RN's built-in `Animated` (native driver) so the shell stays dependency-free:\n * the boilerplate uses react-native-reanimated, which the kit does not.\n *\n * Dismissal (backdrop tap / Android back / the imperative `close()` handle) animates the card\n * out, then fires `onDismiss`. It never auto-closes on resolve: the host keeps the card showing\n * whatever payoff it wants (a thank-you, a summary) until the user taps the backdrop to close,\n * exactly like CompletionView.\n */\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { Animated, BackHandler, Easing, Modal, Pressable, StyleSheet } from \"react-native\";\nimport { SafeAreaView } from \"react-native-safe-area-context\";\n\nimport type { OnboardingTheme } from \"../theme/types\";\nimport { REDUCED_FADE_MS } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport { CENTERED_MODAL_ANIM } from \"../motion/centeredModalMotion\";\n\n/** Imperative handle so an in-card \"Not now\"/\"Skip\" link can trigger the exit animation. */\nexport type CenteredModalHandle = { close: () => void };\n\nexport type CenteredModalProps = {\n /** The (already merged) active theme - card surface/radius/spacing come from here. */\n theme: OnboardingTheme;\n /** Whether a backdrop tap / back press dismisses. Default true (never a dead end). */\n dismissible?: boolean;\n /** Fired once, AFTER the exit animation, on any dismiss. Wire to the host's resolve. */\n onDismiss: () => void;\n children: React.ReactNode;\n};\n\nconst _CenteredModal = forwardRef<CenteredModalHandle, CenteredModalProps>(\n ({ theme, dismissible = true, onDismiss, children }, ref) => {\n const progress = useRef(new Animated.Value(0)).current;\n const [open, setOpen] = useState(true);\n const closingRef = useRef(false);\n const reduced = useReducedMotion();\n\n // Entrance: spring the card in (scale + fade); the backdrop fades up in lock-step.\n // Reduce motion: a short fade to the settled card, no spring/scale.\n useEffect(() => {\n const anim = reduced\n ? Animated.timing(progress, {\n toValue: 1,\n duration: REDUCED_FADE_MS,\n useNativeDriver: true,\n })\n : Animated.spring(progress, {\n toValue: 1,\n useNativeDriver: true,\n friction: CENTERED_MODAL_ANIM.enterSpring.friction,\n tension: CENTERED_MODAL_ANIM.enterSpring.tension,\n });\n anim.start();\n return () => anim.stop();\n }, [progress, reduced]);\n\n const close = useCallback(() => {\n if (closingRef.current) return;\n closingRef.current = true;\n Animated.timing(progress, {\n toValue: 0,\n duration: reduced ? REDUCED_FADE_MS : CENTERED_MODAL_ANIM.exitMs,\n easing: Easing.in(Easing.cubic),\n useNativeDriver: true,\n }).start(() => {\n setOpen(false);\n onDismiss();\n });\n }, [progress, onDismiss, reduced]);\n\n useImperativeHandle(ref, () => ({ close }), [close]);\n\n // Android hardware back -> dismiss (when allowed). Always consume so it never pops a route.\n useEffect(() => {\n const sub = BackHandler.addEventListener(\"hardwareBackPress\", () => {\n if (dismissible) close();\n return true;\n });\n return () => sub.remove();\n }, [dismissible, close]);\n\n const onBackdrop = useCallback(() => {\n if (dismissible) close();\n }, [dismissible, close]);\n\n const backdropOpacity = progress.interpolate({\n inputRange: [0, 1],\n outputRange: [0, CENTERED_MODAL_ANIM.backdropOpacity],\n });\n // Reduce motion: the card fades in already settled (no zoom).\n const cardScale = reduced\n ? 1\n : progress.interpolate({\n inputRange: [0, 1],\n outputRange: [CENTERED_MODAL_ANIM.scaleFrom, 1],\n });\n\n return (\n <Modal\n visible={open}\n transparent\n animationType=\"none\"\n statusBarTranslucent\n onRequestClose={dismissible ? close : undefined}\n >\n {/* Dimmed backdrop (fades with the entrance). */}\n <Animated.View\n style={[styles.backdrop, { opacity: backdropOpacity }]}\n pointerEvents=\"none\"\n />\n\n {/* Full-screen tap target: a tap outside the card dismisses. */}\n <Pressable\n style={styles.fill}\n onPress={onBackdrop}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Dismiss\"\n >\n <SafeAreaView style={styles.center} pointerEvents=\"box-none\">\n {/* Inner Pressable swallows taps so the card itself never dismisses. */}\n <Pressable onPress={() => {}} style={styles.cardWrap}>\n <Animated.View\n accessibilityViewIsModal\n accessibilityRole=\"alert\"\n style={[\n styles.card,\n {\n backgroundColor: theme.colors.surface,\n borderRadius: theme.radius.lg,\n padding: theme.spacing.lg,\n gap: theme.spacing.md,\n opacity: progress,\n transform: [{ scale: cardScale }],\n },\n ]}\n >\n {children}\n </Animated.View>\n </Pressable>\n </SafeAreaView>\n </Pressable>\n </Modal>\n );\n },\n);\n\n_CenteredModal.displayName = \"CenteredModal\";\n\nexport const CenteredModal = React.memo(_CenteredModal);\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n backdrop: { position: \"absolute\", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: \"#000\" },\n center: { flex: 1, alignItems: \"center\", justifyContent: \"center\", padding: 24 },\n cardWrap: { width: \"100%\", maxWidth: 420 },\n card: {\n width: \"100%\",\n // Soft elevation so the popup reads as lifted above the app in both themes.\n shadowColor: \"#000\",\n shadowOffset: { width: 0, height: 8 },\n shadowOpacity: 0.28,\n shadowRadius: 24,\n elevation: 12,\n },\n});\n\nexport default CenteredModal;\n","/**\n * DoneCheck — the animated \"done\" payoff glyph shared by the review gate's and the\n * questionnaire's thank-you panes. One component, two call sites, one feel.\n *\n * The beat is the house success beat, lifted from StatusCard (design-refs/\n * EXTRACTED-SPEC.md rows 14/16): the glyph springs in with a slight overshoot\n * (STATUS_POP_SPRING, scale STATUS_POP_SCALE_FROM→1) while the ring settles behind it.\n * No new motion values are invented here — every number comes from motionSpec.\n *\n * It is a Text glyph in a themed circle, NOT an SVG path: `react-native-svg` is not a\n * peer of this kit, and adding a NATIVE dependency to draw a checkmark would force every\n * host into a rebuild. The five review stars are already glyphs, so this matches the\n * house idiom.\n *\n * Reduce motion: the final frame, instantly — never a frozen mid-pop.\n *\n * Accessibility: purely decorative. The thank-you copy next to it carries the meaning,\n * so the glyph is hidden from screen readers rather than announced as \"heavy check mark\".\n */\nimport React, { useEffect, useRef } from \"react\";\nimport { Animated, StyleSheet } from \"react-native\";\n\nimport { STATUS_POP_SCALE_FROM, STATUS_POP_SPRING } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport type { OnboardingTheme } from \"../theme/types\";\n\nexport type DoneCheckProps = {\n /** The (already merged) active theme — the ring reads `colors.success`. */\n theme: OnboardingTheme;\n /** Diameter of the ring. Defaults to a size that balances the modal heading. */\n size?: number;\n};\n\nconst _DoneCheck: React.FC<DoneCheckProps> = ({ theme, size = 48 }) => {\n const reduced = useReducedMotion();\n const pop = useRef(new Animated.Value(reduced ? 1 : 0)).current;\n\n useEffect(() => {\n if (reduced) {\n pop.setValue(1);\n return;\n }\n const anim = Animated.spring(pop, {\n toValue: 1,\n friction: STATUS_POP_SPRING.friction,\n tension: STATUS_POP_SPRING.tension,\n useNativeDriver: true,\n });\n anim.start();\n return () => anim.stop();\n }, [pop, reduced]);\n\n const scale = pop.interpolate({\n inputRange: [0, 1],\n outputRange: [STATUS_POP_SCALE_FROM, 1],\n });\n\n return (\n <Animated.View\n accessibilityElementsHidden\n importantForAccessibility=\"no-hide-descendants\"\n style={[\n styles.ring,\n {\n width: size,\n height: size,\n borderRadius: theme.radius.full,\n backgroundColor: theme.colors.success,\n opacity: pop,\n transform: [{ scale }],\n },\n ]}\n >\n <Animated.Text\n style={[\n styles.glyph,\n { color: theme.colors.onPrimary, fontSize: Math.round(size * 0.5), fontFamily: theme.fonts.bold },\n ]}\n >\n ✓\n </Animated.Text>\n </Animated.View>\n );\n};\n\nexport const DoneCheck = React.memo(_DoneCheck);\nDoneCheck.displayName = \"DoneCheck\";\n\nconst styles = StyleSheet.create({\n ring: { alignItems: \"center\", justifyContent: \"center\", alignSelf: \"center\" },\n glyph: { includeFontPadding: false, textAlign: \"center\" },\n});\n\nexport default DoneCheck;\n","/**\n * CardHandoff — the card-to-card transition from the Wire Activation design:\n * \"cards hand off, they don't cut\". When `transitionKey` changes, the outgoing\n * child leaves left (translateX 0→-26, fade, 180ms) in an absolute layer while\n * the incoming child arrives from the right (translateX +26→0, fade, 220ms)\n * delayed by the 80ms exit lead — one moving surface, ~300ms total.\n *\n * Variants (per child):\n * - \"slide\": questions — the directional stepper motion above.\n * - \"spring\": the InterstitialCard value beat — scale 0.96→1 spring pop\n * (the shell's springier variant, kept from AnimatedCard).\n * - \"fade\": loaders — enter/exit as a plain 120ms fade so the \"thinking\"\n * state hands off to the first card without a hard cut.\n *\n * `direction` mirrors the whole slide for BACK navigation, so a step the user\n * returns to comes back from the side it left toward. Spatial consistency: if\n * \"next\" pushes left, \"back\" must pull right, or the stack loses its geography.\n *\n * `layout` picks how the moving surface is sized. \"fill\" (default) is the\n * full-screen flow, where the pane owns the viewport. \"auto\" is for a pane\n * inside an auto-height container (the CenteredModal card): `flex: 1` there\n * resolves to a ZERO-height child under Yoga — flex-basis 0 with no free space\n * to grow into — so the in-flow layer must size to its own content instead.\n *\n * Reduce motion: every handoff becomes a 120ms crossfade, no translate/scale.\n * All values run on the native driver (transform/opacity only); in-flight\n * animations are stopped when superseded and on unmount.\n *\n * This SUPERSEDES the enter-only AnimatedCard: same keyed-remount contract from\n * OnboardingFlow (the child renderer stays keyed on the message id), plus the\n * paired exit layer the design calls for.\n */\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Animated, Easing, StyleSheet } from \"react-native\";\nimport {\n CARD_ENTER_MS,\n CARD_ENTER_SCALE_FROM,\n CARD_EXIT_LEAD_MS,\n CARD_EXIT_MS,\n CARD_SLIDE_PX,\n CARD_SPRING,\n LOADER_HANDOFF_FADE_MS,\n REDUCED_FADE_MS,\n WIRE_BEZIER,\n scaledMs,\n} from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\n\nconst easeWire = Easing.bezier(...WIRE_BEZIER);\n\nexport type CardHandoffVariant = \"slide\" | \"spring\" | \"fade\";\n\n/** Which way the stack is moving. \"backward\" mirrors the slide (see the header note). */\nexport type CardHandoffDirection = \"forward\" | \"backward\";\n\n/** How the moving surface is sized. \"auto\" = a pane in an auto-height container. */\nexport type CardHandoffLayout = \"fill\" | \"auto\";\n\nexport type CardHandoffProps = {\n /** Identity of the current child (e.g. the message id). A change runs the handoff. */\n transitionKey: string;\n /** How the CURRENT child enters (and, snapshotted, how it will later exit). */\n variant?: CardHandoffVariant;\n /** Travel direction of THIS transition. Default \"forward\". */\n direction?: CardHandoffDirection;\n /** Sizing mode. Default \"fill\" (the full-screen flow). */\n layout?: CardHandoffLayout;\n children: React.ReactNode;\n};\n\ntype Snapshot = { key: string; node: React.ReactNode; variant: CardHandoffVariant };\n\nconst _CardHandoff: React.FC<CardHandoffProps> = ({\n transitionKey,\n variant = \"slide\",\n direction = \"forward\",\n layout = \"fill\",\n children,\n}) => {\n const reduced = useReducedMotion();\n const [leaving, setLeaving] = useState<Snapshot | null>(null);\n\n const enterT = useRef(new Animated.Value(0)).current;\n const exitT = useRef(new Animated.Value(0)).current;\n // The previous render's child, snapshotted so it can play the exit layer.\n const prev = useRef<Snapshot>({ key: transitionKey, node: children, variant });\n const running = useRef<{ enter?: Animated.CompositeAnimation; exit?: Animated.CompositeAnimation }>({});\n const mounted = useRef(false);\n\n // One orchestration effect, run every render: refresh the snapshot while the key\n // is stable; on a key change, snapshot the old child into the exit layer and run\n // the paired exit+enter. (No deps array on purpose — `children` is a fresh node\n // every parent render and must keep the snapshot current.)\n useEffect(() => {\n const last = prev.current;\n prev.current = { key: transitionKey, node: children, variant };\n\n // First mount: enter only (the design's initial reveal), nothing exits.\n if (!mounted.current) {\n mounted.current = true;\n running.current.enter = startEnter(enterT, variant, reduced, 0);\n return;\n }\n if (last.key === transitionKey) return;\n\n running.current.enter?.stop();\n running.current.exit?.stop();\n setLeaving(last);\n enterT.setValue(0);\n exitT.setValue(0);\n\n const exitDuration = reduced\n ? REDUCED_FADE_MS\n : last.variant === \"fade\"\n ? LOADER_HANDOFF_FADE_MS\n : CARD_EXIT_MS;\n const exit = Animated.timing(exitT, {\n toValue: 1,\n duration: scaledMs(exitDuration),\n easing: easeWire,\n useNativeDriver: true,\n });\n running.current.exit = exit;\n exit.start();\n\n const enter = startEnter(enterT, variant, reduced, reduced ? 0 : CARD_EXIT_LEAD_MS, () =>\n setLeaving(null),\n );\n running.current.enter = enter;\n });\n\n // Stop anything in flight on unmount (leaked animations drain the JS thread).\n useEffect(\n () => () => {\n running.current.enter?.stop();\n running.current.exit?.stop();\n },\n [],\n );\n\n const enterStyle = {\n opacity: enterT,\n transform: transformFor(variant, enterT, reduced, \"enter\", direction),\n };\n\n return (\n <>\n {leaving ? (\n <Animated.View\n pointerEvents=\"none\"\n style={[\n StyleSheet.absoluteFill,\n {\n opacity: exitT.interpolate({ inputRange: [0, 1], outputRange: [1, 0] }),\n // The CURRENT direction drives BOTH layers: one transition, one geography.\n transform: transformFor(leaving.variant, exitT, reduced, \"exit\", direction),\n },\n ]}\n >\n {leaving.node}\n </Animated.View>\n ) : null}\n <Animated.View key={variant} style={[layout === \"fill\" ? styles.fill : null, enterStyle]}>\n {children}\n </Animated.View>\n </>\n );\n};\n\n/** Kick off the enter animation for a variant (spring for the value beat, timing otherwise). */\nconst startEnter = (\n value: Animated.Value,\n variant: CardHandoffVariant,\n reduced: boolean,\n delay: number,\n onDone?: () => void,\n): Animated.CompositeAnimation => {\n value.setValue(0);\n const anim =\n !reduced && variant === \"spring\"\n ? Animated.spring(value, {\n toValue: 1,\n delay: scaledMs(delay),\n damping: CARD_SPRING.damping,\n stiffness: CARD_SPRING.stiffness,\n mass: CARD_SPRING.mass,\n useNativeDriver: true,\n })\n : Animated.timing(value, {\n toValue: 1,\n delay: scaledMs(delay),\n duration: scaledMs(\n reduced\n ? REDUCED_FADE_MS\n : variant === \"fade\"\n ? LOADER_HANDOFF_FADE_MS\n : CARD_ENTER_MS,\n ),\n easing: easeWire,\n useNativeDriver: true,\n });\n anim.start(({ finished }) => {\n if (finished) onDone?.();\n });\n return anim;\n};\n\n/**\n * Transform track per variant/layer; reduce motion = opacity-only crossfade.\n *\n * `travel` mirrors the X axis: forward pushes the stack left (new arrives from the\n * right), backward pulls it right (new arrives from the left).\n */\nconst transformFor = (\n variant: CardHandoffVariant,\n t: Animated.Value,\n reduced: boolean,\n layer: \"enter\" | \"exit\",\n travel: CardHandoffDirection,\n) => {\n if (reduced || variant === \"fade\") return [];\n if (variant === \"spring\" && layer === \"enter\") {\n return [{ scale: t.interpolate({ inputRange: [0, 1], outputRange: [CARD_ENTER_SCALE_FROM, 1] }) }];\n }\n const slide = travel === \"forward\" ? CARD_SLIDE_PX : -CARD_SLIDE_PX;\n return [\n {\n translateX: t.interpolate({\n inputRange: [0, 1],\n outputRange: layer === \"enter\" ? [slide, 0] : [0, -slide],\n }),\n },\n ];\n};\n\nexport const CardHandoff = React.memo(_CardHandoff);\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n});\n","/**\n * ModalPaneHost — \"slide between panes inside a CenteredModal\", the shared primitive\n * behind BOTH the review gate's phase changes and the questionnaire's step changes.\n * One primitive, two call sites: the two gates must never drift apart on feel.\n *\n * It does NOT reimplement the slide. `CardHandoff` already owns the design's\n * \"cards hand off, they don't cut\" motion (exit left 180ms / enter right 220ms, 80ms\n * lead, reduce-motion crossfade), so this delegates to it in `layout=\"auto\"` mode and\n * adds the ONE thing a modal needs that a full-screen flow does not: a card that\n * resizes instead of snapping.\n *\n * WHY the height animation exists: the CenteredModal card is auto-height, so the moment\n * a taller/shorter pane mounts, the card would jump to its new height in a single frame\n * while the old pane is still sliding out — the exact \"jarring change\" the slide was\n * added to remove. Measuring the pane and easing the card to it keeps one continuous\n * surface.\n *\n * WHY it is the only non-native-driven value in the kit: height is a layout prop, so it\n * cannot ride the native driver. That is a deliberate, bounded exception — ONE property\n * on ONE small card, for ~220ms, while nothing is scrolling. The panes' own opacity and\n * translate (inside CardHandoff) stay on the native driver, and the two values live on\n * different views, so they never contend. Everything else in the kit stays transform/\n * opacity-only.\n *\n * Height is eased ONLY on a pane change. A multiline box growing as the user types also\n * fires onLayout, and animating that would make typing feel laggy — those resize\n * instantly. Reduce motion: the height snaps too (movement removed, crossfade kept).\n *\n * `header` is the STATIC slot: chrome that belongs to the card rather than to any one pane\n * (the questionnaire's back icon + step dots). It sits inside the measured container but\n * OUTSIDE the CardHandoff, which buys two things a caller cannot get by rendering it above\n * the host:\n * 1. It never slides, so it is never DUPLICATED mid-handoff. Anything inside CardHandoff\n * exists twice for ~300ms (the outgoing layer and the incoming one) — fine for a\n * question that is genuinely changing, wrong for chrome that is not. Two dot rows\n * cross-fading past each other is a bug, not a transition.\n * 2. Its size is part of the measured height, so dropping the header (form → thanks)\n * rides the same eased resize as the pane swap instead of snapping the card.\n */\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Animated, Easing, StyleSheet, View, type LayoutChangeEvent } from \"react-native\";\n\nimport { CARD_ENTER_MS, WIRE_BEZIER, scaledMs } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport { CardHandoff, type CardHandoffDirection } from \"./CardHandoff\";\n\nconst easeWire = Easing.bezier(...WIRE_BEZIER);\n\nexport type ModalPaneHostProps = {\n /** Identity of the pane on screen (phase name / step key). A change runs the handoff. */\n paneKey: string;\n /** Travel direction — \"backward\" mirrors the slide when the user steps back. */\n direction?: CardHandoffDirection;\n /**\n * Card-level chrome pinned above the sliding pane: measured with it, but never moved\n * and never duplicated by the handoff. Omit it (or pass null) and nothing renders —\n * dropping it between pane changes animates the card's height rather than snapping it.\n * The node owns its own bottom spacing; the host adds none (it has no theme).\n */\n header?: React.ReactNode;\n children: React.ReactNode;\n};\n\nconst _ModalPaneHost: React.FC<ModalPaneHostProps> = ({\n paneKey,\n direction = \"forward\",\n header,\n children,\n}) => {\n const reduced = useReducedMotion();\n const height = useRef(new Animated.Value(0)).current;\n /** Last height we settled on. null until the first real measurement lands. */\n const measured = useRef<number | null>(null);\n /** Drives the height style on only AFTER a real measurement, so nothing renders at 0. */\n const [sized, setSized] = useState(false);\n /** Set when the pane changed, cleared by the next measurement it causes. */\n const paneChanged = useRef(false);\n const running = useRef<Animated.CompositeAnimation | null>(null);\n\n // Runs on mount and on every pane change, always BEFORE the resulting onLayout (which\n // arrives from native after the commit) — so the next measurement knows why it fired.\n useEffect(() => {\n paneChanged.current = true;\n }, [paneKey]);\n\n useEffect(() => () => running.current?.stop(), []);\n\n const onLayout = useCallback(\n (event: LayoutChangeEvent) => {\n const next = Math.round(event.nativeEvent.layout.height);\n if (!next) return;\n const previous = measured.current;\n if (previous !== null && Math.abs(previous - next) < 1) return;\n\n const first = previous === null;\n const ease = !first && !reduced && paneChanged.current;\n paneChanged.current = false;\n measured.current = next;\n running.current?.stop();\n\n // First measurement, a reduce-motion user, or a plain content resize (typing):\n // take the new height immediately.\n if (!ease) {\n height.setValue(next);\n if (first) setSized(true);\n return;\n }\n\n const anim = Animated.timing(height, {\n toValue: next,\n duration: scaledMs(CARD_ENTER_MS),\n easing: easeWire,\n // height is layout, not transform — see the header note.\n useNativeDriver: false,\n });\n running.current = anim;\n anim.start();\n },\n [height, reduced],\n );\n\n return (\n <Animated.View style={sized ? { height, overflow: \"hidden\" } : undefined}>\n <View onLayout={onLayout} style={styles.pane}>\n {header}\n <CardHandoff transitionKey={paneKey} direction={direction} layout=\"auto\" variant=\"slide\">\n {children}\n </CardHandoff>\n </View>\n </Animated.View>\n );\n};\n\nexport const ModalPaneHost = React.memo(_ModalPaneHost);\nModalPaneHost.displayName = \"ModalPaneHost\";\n\nconst styles = StyleSheet.create({\n pane: { width: \"100%\" },\n});\n\nexport default ModalPaneHost;\n","/**\n * StepDots — the \"how many steps, and which one am I on\" row for a multi-step modal.\n *\n * It replaces the questionnaire's textual counter (\"Question 2 of 3\"). Malik's device\n * feedback 2026-07-16: \"instead of 1 out of 3 or 2-3, had points on top to explain the\n * number of steps\". A dot row says the same two things — how long this is, how far in you\n * are — without spending a line of copy next to the question the user should be reading.\n *\n * NOT the same component as `StepProgress`: that one is the ONBOARDING flow's bar, and it\n * deliberately refuses to show a count because the flow's length is model-decided and a\n * number would be a promise the model may not keep. The questionnaire is the opposite\n * case — a fixed 3-field server contract — so here the count is knowable and honest.\n *\n * Motion: a dot fills by crossfading a `colors.primary` layer over a `colors.border` base,\n * at the design system's selection-fill duration (SELECT_FILL_MS, spec rows 2/3/5/6 — the\n * same token every other \"this is now selected\" fill in the kit uses). Opacity only, on the\n * native driver: no color interpolation (that would force `useNativeDriver: false`, and the\n * kit keeps its one non-native exception in ModalPaneHost's height).\n *\n * Reduce motion: `stateChangeDuration` collapses the fill to 0ms, so the state snaps —\n * the house convention for state changes (see StepProgress).\n *\n * Accessibility: sighted users read the dots; screen readers must not be handed three\n * unlabelled circles. The ROW is one progressbar node carrying \"Step 2 of 3\" plus the\n * numeric value, and the dots themselves are hidden as decoration.\n */\nimport React, { useEffect, useRef } from \"react\";\nimport { Animated, Easing, StyleSheet, View } from \"react-native\";\n\nimport { SELECT_FILL_MS, WIRE_BEZIER, scaledMs, stateChangeDuration } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport type { OnboardingTheme } from \"../theme/types\";\n\nconst easeWire = Easing.bezier(...WIRE_BEZIER);\n\nexport type StepDotsProps = {\n /** The (already merged) active theme — dots read `colors.border` / `colors.primary`. */\n theme: OnboardingTheme;\n /** How many steps there are (how many dots to draw). */\n count: number;\n /** 0-based index of the step on screen. */\n index: number;\n};\n\ntype DotProps = {\n theme: OnboardingTheme;\n /** True for the current step and every step behind it — the row reads as progress. */\n filled: boolean;\n size: number;\n};\n\nconst Dot: React.FC<DotProps> = ({ theme, filled, size }) => {\n const reduced = useReducedMotion();\n const fill = useRef(new Animated.Value(filled ? 1 : 0)).current;\n\n useEffect(() => {\n const anim = Animated.timing(fill, {\n toValue: filled ? 1 : 0,\n duration: scaledMs(stateChangeDuration(reduced, SELECT_FILL_MS)),\n easing: easeWire,\n useNativeDriver: true,\n });\n anim.start();\n return () => anim.stop();\n }, [fill, filled, reduced]);\n\n return (\n <View\n style={{\n width: size,\n height: size,\n borderRadius: theme.radius.full,\n backgroundColor: theme.colors.border,\n }}\n >\n <Animated.View\n style={[\n StyleSheet.absoluteFill,\n {\n borderRadius: theme.radius.full,\n backgroundColor: theme.colors.primary,\n opacity: fill,\n },\n ]}\n />\n </View>\n );\n};\n\nconst _StepDots: React.FC<StepDotsProps> = ({ theme, count, index }) => (\n <View\n style={[styles.row, { gap: theme.spacing.sm }]}\n accessibilityRole=\"progressbar\"\n accessibilityLabel={`Step ${index + 1} of ${count}`}\n accessibilityValue={{ min: 1, max: count, now: index + 1 }}\n >\n {Array.from({ length: count }, (_, i) => (\n <View key={i} accessibilityElementsHidden importantForAccessibility=\"no-hide-descendants\">\n <Dot theme={theme} filled={i <= index} size={theme.spacing.sm} />\n </View>\n ))}\n </View>\n);\n\nexport const StepDots = React.memo(_StepDots);\nStepDots.displayName = \"StepDots\";\n\nconst styles = StyleSheet.create({\n row: { flexDirection: \"row\", alignItems: \"center\", justifyContent: \"center\" },\n});\n\nexport default StepDots;\n","/**\n * haptics.ts — the physical half of the kit's feedback layer: a tap you feel.\n *\n * `expo-haptics` is an OPTIONAL peer, loaded lazily via a guarded dynamic import so the\n * core kit never depends on it — the exact contract `reviews/storeReview.ts` uses for\n * `expo-store-review`. A host that has not installed it (or a platform without a taptic\n * engine) simply feels nothing: every call resolves to `false` and NOTHING throws. A\n * missed haptic must never break a gate.\n *\n * The module is deliberately fire-and-forget. Callers `void play(...)` from a press\n * handler and never await it, so a slow/absent native module can't delay a tap.\n *\n * Tones map to intent, not to a device API:\n * • \"selection\" — a value changed (picking a star).\n * • \"light\" — a light impact (moving to the next question).\n * • \"success\" — a task completed (the submit payoff, under the done check).\n *\n * NOT gated on reduce-motion: `prefers-reduced-motion` is a VESTIBULAR accommodation about\n * on-screen movement. Haptics are a non-visual channel and are often the accessibility\n * affordance a reduce-motion user relies on, so silencing them here would be the wrong\n * trade. Hosts that want no haptics leave `expo-haptics` uninstalled.\n */\n\n/** What a haptic is for, in product terms. Mapped to the native API inside `play`. */\nexport type HapticTone = \"selection\" | \"light\" | \"success\";\n\n/**\n * Play a haptic when the optional peer is available. Resolves `true` when a haptic was\n * actually requested, `false` when the peer is absent or the native call failed. NEVER\n * throws and never rejects — the result is advisory (tests/analytics), not control flow.\n */\nexport const play = async (tone: HapticTone): Promise<boolean> => {\n try {\n const mod = await import(\"expo-haptics\");\n if (!mod) return false;\n if (tone === \"selection\") {\n await mod.selectionAsync();\n return true;\n }\n if (tone === \"light\") {\n await mod.impactAsync(mod.ImpactFeedbackStyle.Light);\n return true;\n }\n await mod.notificationAsync(mod.NotificationFeedbackType.Success);\n return true;\n } catch {\n // Peer not installed, unsupported platform, or the native call failed — stay silent.\n return false;\n }\n};\n\n/**\n * Fire-and-forget `play`. The call site reads as the intent (\"a star was tapped\"), and a\n * rejected/absent native module can never surface as an unhandled rejection.\n */\nexport const playHaptic = (tone: HapticTone): void => {\n void play(tone);\n};\n","/**\n * feedbackForm — pure sizing helpers for the 1–4★ feedback form, kept out of the\n * React component so the \"≈4 lines tall, capped at 5\" rule is verifiable in\n * isolation (the reviews module's correctness lives in these pure functions, the\n * same convention as `decision.ts` / `presentation.ts`).\n *\n * Malik's ask: the feedback field should be a multiline box \"around 3 to 5 lines\"\n * tall, not a single-line input. We size it from the theme's body line-height so\n * it scales with the app's font config.\n */\nimport type { OnboardingFonts } from \"../theme/types\";\nimport { bodyStyle } from \"../theme/typography\";\n\n/** Lines the box shows at rest, and the cap it can grow to. */\nexport const FEEDBACK_MIN_LINES = 4;\nexport const FEEDBACK_MAX_LINES = 5;\n\nexport interface FeedbackInputHeights {\n /** Resting height — the box opens at ~4 lines so it reads as \"write a few words\". */\n minHeight: number;\n /** Growth cap — it never balloons past ~5 lines; scroll takes over beyond that. */\n maxHeight: number;\n}\n\n/**\n * Derive the multiline feedback box's min/max height from the theme's body\n * line-height. `minHeight = MIN_LINES × lineHeight`, capped at\n * `MAX_LINES × lineHeight`, plus the field's vertical padding (top + bottom) so\n * the requested number of text lines is actually visible inside the padding.\n */\nexport const feedbackInputHeights = (\n fonts: OnboardingFonts,\n verticalPadding = 0,\n): FeedbackInputHeights => {\n const lineHeight = bodyStyle(fonts).lineHeight ?? Math.round(fonts.baseSize * fonts.scale * 1.5);\n const pad = verticalPadding * 2;\n return {\n minHeight: lineHeight * FEEDBACK_MIN_LINES + pad,\n maxHeight: lineHeight * FEEDBACK_MAX_LINES + pad,\n };\n};\n","/**\n * mergeThemeOver — merge a partial theme over an ARBITRARY base theme.\n *\n * Sibling of `mergeTheme` (defaultTheme.ts), which merges over the DEFAULT theme only.\n * Gates need the other shape: a `theme` prop merged over whatever the host's active\n * ThemeContext currently is. That helper was copy-pasted verbatim into ReviewGate and\n * QuestionnaireGate; it lives here once instead, so a new theme section can never be\n * added to one gate and forgotten in the other.\n *\n * Two levels deep, matching `mergeTheme`: the theme is intentionally shallow, so each\n * known sub-object is merged and scalars overwrite.\n */\nimport type { OnboardingTheme } from \"./types\";\n\nexport const mergeThemeOver = (\n base: OnboardingTheme,\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return base;\n return {\n colors: { ...base.colors, ...override.colors },\n fonts: { ...base.fonts, ...override.fonts },\n radius: { ...base.radius, ...override.radius },\n spacing: { ...base.spacing, ...override.spacing },\n button: { ...base.button, ...override.button },\n };\n};\n","/**\n * decision.ts — the pure decision logic for the review gate.\n *\n * `decideReview` is the AI seam, mirroring `selectTourSteps` exactly: ONE function that\n * turns an optional injected decision into the live verdict. No injected decision → the\n * local rules stand; a server decision present → it OVERRIDES them. Building the seam now\n * is the whole cost of being AI-ready: today the host passes local rules only; later the\n * Wire server computes `{fire, reason}` from the onboarding learnings and the host passes\n * it straight in — zero app changes.\n *\n * // v1 (local rules only)\n * const verdict = decideReview(evaluateGate(rules, signals));\n *\n * // AI on (server-provided decision wins)\n * const verdict = decideReview(evaluateGate(rules, signals), serverDecision);\n *\n * `evaluateGate`, `routeRating`, and `buildReviewSubmission` are pure so the gate logic\n * is verifiable in isolation (the kit has no test runner; correctness lives in these).\n */\nimport type {\n RatingRoute,\n ReviewDecision,\n ReviewSubmission,\n} from \"./types\";\n\n/**\n * The seam. `decision` absent → the local verdict stands; present → it overrides.\n * Same contract philosophy as `selectTourSteps(catalog, selection?)`.\n */\nexport const decideReview = (\n local: ReviewDecision,\n decision?: ReviewDecision,\n): ReviewDecision => decision ?? local;\n\n/** The signals the local rules evaluate against (read from injected sync storage + host). */\nexport interface GateSignals {\n /** Sessions observed on this device (incl. the current one). */\n sessions: number;\n /** Tracked app events observed (host-owned). */\n events: number;\n /** Epoch ms of the last time the gate was shown, or null if never. */\n lastShownAt: number | null;\n /** Whether the once-per-version gate is already satisfied. */\n seen: boolean;\n /** Current epoch ms (injected so the function stays pure). */\n now: number;\n}\n\n/** The resolved local rules (defaults applied). */\nexport interface GateRules {\n enabled: boolean;\n minSessions: number;\n minEvents: number;\n cooldownDays: number;\n oncePerVersion: boolean;\n}\n\n/** Fill a partial `ReviewConfig` with the rule defaults. */\nexport const resolveRules = (config: {\n enabled?: boolean;\n minSessions?: number;\n minEvents?: number;\n cooldownDays?: number;\n oncePerVersion?: boolean;\n}): GateRules => ({\n enabled: config.enabled ?? true,\n minSessions: config.minSessions ?? 0,\n minEvents: config.minEvents ?? 0,\n cooldownDays: config.cooldownDays ?? 0,\n oncePerVersion: config.oncePerVersion ?? true,\n});\n\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Deterministic v1 local decision. Order: disabled → once-gate → min-sessions →\n * min-events → cooldown → fire. Reasons mirror the server evaluator's vocabulary.\n */\nexport const evaluateGate = (rules: GateRules, s: GateSignals): ReviewDecision => {\n if (!rules.enabled) return { fire: false, reason: \"disabled\" };\n if (rules.oncePerVersion && s.seen) return { fire: false, reason: \"already_shown\" };\n if (s.sessions < rules.minSessions) return { fire: false, reason: \"min_sessions\" };\n if (s.events < rules.minEvents) return { fire: false, reason: \"min_events\" };\n if (rules.cooldownDays > 0 && s.lastShownAt != null) {\n const elapsedDays = (s.now - s.lastShownAt) / MS_PER_DAY;\n if (elapsedDays < rules.cooldownDays) return { fire: false, reason: \"cooldown\" };\n }\n return { fire: true, reason: \"local_rules_met\" };\n};\n\n/**\n * Route a rating. 5 stars → the native store review; 1-4 → the feedback form. The\n * sentiment question itself is neutral — this is the ONLY place 5 is treated specially,\n * never a button labeled \"rate us 5 stars\" (see the store-policy notes in the README).\n */\nexport const routeRating = (stars: number): RatingRoute =>\n stars >= 5 ? \"store\" : \"feedback\";\n\n/** Build the `POST /v1/reviews` body. Feedback text/contact belong ONLY here, never in events. */\nexport const buildReviewSubmission = (input: {\n stars: number;\n feedbackText?: string;\n suggestion?: string;\n contact?: string;\n sessionId?: string;\n source?: string;\n meta?: Record<string, unknown>;\n}): ReviewSubmission => {\n const body: ReviewSubmission = { stars: input.stars };\n const text = input.feedbackText?.trim();\n if (text) body.feedback_text = text;\n const suggestion = input.suggestion?.trim();\n if (suggestion) body.suggestion = suggestion;\n const contact = input.contact?.trim();\n if (contact) body.contact = contact;\n if (input.sessionId) body.session_id = input.sessionId;\n if (input.source) body.source = input.source;\n if (input.meta && Object.keys(input.meta).length > 0) body.meta = input.meta;\n return body;\n};\n","/**\n * decision.ts - pure decision logic for the questionnaire gate.\n *\n * `decideQuestionnaire` is the AI seam, mirroring `decideReview` exactly: ONE function\n * that turns an optional injected decision into the live verdict. No injected decision →\n * the local rules stand; a server decision present → it OVERRIDES them. The local firing\n * rules (`evaluateGate` / `resolveRules`) and their signals are the SAME generic, pure\n * helpers the review gate uses - reused here rather than duplicated, since a questionnaire\n * verdict is structurally the same `{fire, reason}` contract.\n *\n * `buildQuestionnaireSubmission` is pure too, so the \"opinion required, empties omitted\"\n * shaping of the POST body is verifiable in isolation (the kit has no runtime test runner).\n */\nimport { decideReview, evaluateGate, resolveRules } from \"../reviews/decision\";\nimport type {\n QuestionnaireAnswers,\n QuestionnaireDecision,\n QuestionnaireMeta,\n QuestionnaireSubmission,\n} from \"./types\";\n\n// Re-export the generic local-rule helpers under the questionnaire's own namespace so a\n// host wires the fallback without reaching into the reviews module.\nexport { evaluateGate, resolveRules } from \"../reviews/decision\";\nexport type { GateSignals, GateRules } from \"../reviews/decision\";\n\n/**\n * The seam. `decision` absent → the local verdict stands; present → it overrides. Same\n * contract philosophy as `decideReview(local, decision?)`.\n */\nexport const decideQuestionnaire = (\n local: QuestionnaireDecision,\n decision?: QuestionnaireDecision,\n): QuestionnaireDecision => decideReview(local, decision);\n\n/**\n * Build the `POST /v1/questionnaires/{id}/responses` body. `opinion` is always sent as a\n * string (trimmed, possibly \"\" now that its step is skippable — the live server still\n * rejects that, see steps.ts REQUIRED_STEPS); `improve`/`suggestions` are trimmed and sent\n * as `null` when empty. The\n * `meta` bucket carries the non-PII correlation fields (user_id / device_key / session_count),\n * each defaulting to null. Free text lives ONLY here, never in analytics events.\n */\nexport const buildQuestionnaireSubmission = (input: {\n answers: QuestionnaireAnswers;\n sessionId?: string | null;\n meta?: QuestionnaireMeta;\n}): QuestionnaireSubmission => {\n const opinion = input.answers.opinion.trim();\n const improve = input.answers.improve?.trim();\n const suggestions = input.answers.suggestions?.trim();\n return {\n session_id: input.sessionId ?? null,\n answers: {\n opinion,\n improve: improve ? improve : null,\n suggestions: suggestions ? suggestions : null,\n },\n meta: {\n user_id: input.meta?.user_id ?? null,\n device_key: input.meta?.device_key ?? null,\n session_count: input.meta?.session_count ?? null,\n },\n };\n};\n","/**\n * steps.ts — the pure multi-step machine behind the questionnaire popup.\n *\n * The gate asks ONE question per step. Skippability is per-step (`QuestionnaireStep.required`)\n * and, after Malik's device test 2026-07-16, it is the INVERSE of what this kit shipped for a\n * year: `opinion` (step 1) is SKIPPABLE — the old mandatory-opinion `canSend` gate is gone —\n * and `suggestions` (the LAST step) is REQUIRED, because \"i want at least something forced\".\n * The user picks WHICH thing they say; they do not get to say nothing at all.\n *\n * The step logic is the interesting part of the component, so it lives here as pure\n * functions: no React, no react-native, no JSX. The gate is then a thin renderer over this\n * state, and `steps.test.ts` can verify advance / skip / back / the required gate under\n * node:test without mounting anything.\n *\n * The wire shape is NOT this module's business: it builds `QuestionnaireAnswers`, and\n * `buildQuestionnaireSubmission` (decision.ts) still owns the POST body exactly as before.\n *\n * The step ORDER is the server contract's field order (opinion → improve → suggestions),\n * so `toAnswers` can stay a plain projection and the submission never depends on how the\n * user navigated.\n */\nimport type { QuestionnaireAnswers, QuestionnaireDefinition } from \"./types\";\n\n/** The three answer fields, which are also the three steps. */\nexport type QuestionnaireStepKey = \"opinion\" | \"improve\" | \"suggestions\";\n\n/** One question, fully resolved for rendering. */\nexport interface QuestionnaireStep {\n /** The answer field this step fills. */\n key: QuestionnaireStepKey;\n /** The question shown to the user (tenant-configurable). */\n label: string;\n /** The greyed-out example inside the input. */\n placeholder: string;\n /**\n * When true the step cannot be skipped and cannot be committed blank — the gate hides\n * Skip and disables Send until there is non-whitespace text. Only `suggestions` (the\n * last step) carries it; see `REQUIRED_STEPS`.\n */\n required: boolean;\n}\n\n/**\n * Which steps are mandatory. Malik, after testing on device 2026-07-16: \"The any\n * suggestions or feedback <the last step> is mandatory, i want at least something forced.\"\n *\n * Exactly one step is forced, and it is the LAST one, which is the only placement that\n * works: the user has already been offered two cheap ways to say something and declined\n * them, so the mandatory box lands as \"then tell us anything\" rather than as a toll gate\n * in front of a popup they never asked for. Forcing step 1 (the old behaviour) taxed the\n * arrival; forcing step 3 taxes the exit, after the cost is sunk.\n *\n * ⚠️ SERVER DEPENDENCY: this is the exact INVERSE of what the live server enforces today.\n * `POST /v1/questionnaires/{id}/responses` validates `answers.opinion` with minLength=1 and\n * 422s an empty one. Since step 1 is now skippable, a skipped step 1 produces `opinion: \"\"`\n * and the server rejects the whole body — INCLUDING the suggestions text this module just\n * forced out of the user. The transport is fire-and-forget (it never reads the response),\n * so that rejection is SILENT: the user sees the thank-you either way. This client is\n * therefore correct only once the server drops `opinion`'s minLength. Do not paper over it\n * here — no placeholder opinion, no field reordering, no client-side guard.\n */\nexport const REQUIRED_STEPS: Record<QuestionnaireStepKey, boolean> = {\n opinion: false,\n improve: false,\n suggestions: true,\n};\n\n/**\n * Fallback questions used when the tenant configures no labels.\n *\n * NOTE the copy change: the old defaults tagged `improve`/`suggestions` \"(optional)\".\n * That was already wrong once step 1 stopped being mandatory, and it is wronger now that\n * `suggestions` is the one REQUIRED step. Requiredness is carried by the CONTROLS — Skip\n * is absent and Send is disabled on a required step — not by label text, which is tenant-\n * configurable and would drift out of sync with `REQUIRED_STEPS` the moment it changed.\n */\nexport const DEFAULT_STEP_LABELS: Record<QuestionnaireStepKey, string> = {\n opinion: \"What do you think about the app?\",\n improve: \"How can we improve?\",\n suggestions: \"Any suggestions?\",\n};\n\n/** Per-field placeholders, carried over unchanged from the single-screen form. */\nexport const STEP_PLACEHOLDERS: Record<QuestionnaireStepKey, string> = {\n opinion: \"e.g. it feels fast and clear\",\n improve: \"e.g. fewer steps to start\",\n suggestions: \"e.g. a dark theme\",\n};\n\n/** Which way the last move went — drives the slide direction (spatial consistency). */\nexport type StepDirection = \"forward\" | \"backward\";\n\n/** Answers captured so far, keyed by step. A skipped step records \"\". */\nexport type StepDrafts = Partial<Record<QuestionnaireStepKey, string>>;\n\n/** The whole machine state. Immutable: every transition returns a new object. */\nexport interface QuestionnaireStepState {\n /** Index into the step list. */\n index: number;\n /** What has been typed/skipped so far. */\n drafts: StepDrafts;\n /** Direction of the last transition, for the pane slide. */\n direction: StepDirection;\n /** True once the LAST step is answered or skipped — the gate submits and thanks. */\n done: boolean;\n}\n\n/**\n * Resolve the tenant's labels into the ordered step list. All three steps always render:\n * the server contract is a fixed 3-field capture, not an arbitrary question builder.\n */\nexport const buildQuestionnaireSteps = (\n questionnaire: Pick<\n QuestionnaireDefinition,\n \"opinion_label\" | \"improve_label\" | \"suggestions_label\"\n >,\n): QuestionnaireStep[] => [\n {\n key: \"opinion\",\n label: questionnaire.opinion_label ?? DEFAULT_STEP_LABELS.opinion,\n placeholder: STEP_PLACEHOLDERS.opinion,\n required: REQUIRED_STEPS.opinion,\n },\n {\n key: \"improve\",\n label: questionnaire.improve_label ?? DEFAULT_STEP_LABELS.improve,\n placeholder: STEP_PLACEHOLDERS.improve,\n required: REQUIRED_STEPS.improve,\n },\n {\n key: \"suggestions\",\n label: questionnaire.suggestions_label ?? DEFAULT_STEP_LABELS.suggestions,\n placeholder: STEP_PLACEHOLDERS.suggestions,\n required: REQUIRED_STEPS.suggestions,\n },\n];\n\n/** The starting state: first question, nothing answered. */\nexport const initialStepState = (): QuestionnaireStepState => ({\n index: 0,\n drafts: {},\n direction: \"forward\",\n done: false,\n});\n\n/** The step currently on screen, or undefined once the list is exhausted. */\nexport const currentStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n): QuestionnaireStep | undefined => steps[state.index];\n\n/** Whether `index` is the final step (the one whose commit submits). */\nexport const isLastStep = (steps: readonly QuestionnaireStep[], index: number): boolean =>\n index >= steps.length - 1;\n\n/** Back navigation is available on every step except the first. */\nexport const canGoBack = (state: QuestionnaireStepState): boolean => state.index > 0;\n\n/**\n * Whether the step on screen may be skipped — false on a required step, which is how the\n * gate knows to render no Skip control at all rather than a Skip that silently does nothing.\n */\nexport const canSkipStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n): boolean => !(steps[state.index]?.required ?? false);\n\n/**\n * Whether `value` satisfies the step on screen — i.e. whether committing it will actually\n * move. Optional steps accept anything (including \"\"); a required step needs non-whitespace\n * text, because \" \" is not \"at least something\". The gate reads this to disable Send.\n *\n * The SAME predicate `commitStep` enforces, so a disabled Send and a refused commit can\n * never disagree about what counts as answered.\n */\nexport const canCommitStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n value: string,\n): boolean => {\n const step = steps[state.index];\n if (!step) return false;\n return !step.required || value.trim().length > 0;\n};\n\n/**\n * Record `value` for the CURRENT step WITHOUT navigating.\n *\n * This is the shared \"the text on screen is now part of the answers\" primitive: `commitStep`\n * is exactly this plus the forward move, and the gate's Back does this before `goBack`. It\n * exists because the gate's inputs are UNCONTROLLED, so the step on screen holds its text\n * only in the component's draft ref until something folds it in here — meaning EVERY way of\n * leaving a step has to stash first or the text is silently destroyed.\n */\nexport const stashDraft = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n value: string,\n): QuestionnaireStepState => {\n const step = steps[state.index];\n if (!step) return state;\n return { ...state, drafts: { ...state.drafts, [step.key]: value } };\n};\n\n/**\n * Record `value` for the CURRENT step and move on. On the last step this sets `done`\n * (the gate reads that as \"submit now\") and leaves the index parked, so `toAnswers` is\n * called with every draft present.\n *\n * A required step refuses a blank `value` and returns the state UNCHANGED. That is the\n * single enforcement point for the mandatory last step: `skipStep` is defined as committing\n * \"\", so it becomes a no-op there for free, and the gate's disabled Send is belt-and-braces\n * over a machine that already cannot be walked past.\n */\nexport const commitStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n value: string,\n): QuestionnaireStepState => {\n const step = steps[state.index];\n if (!step) return state;\n if (!canCommitStep(steps, state, value)) return state;\n const { drafts } = stashDraft(steps, state, value);\n const last = isLastStep(steps, state.index);\n return {\n index: last ? state.index : state.index + 1,\n drafts,\n direction: \"forward\",\n done: last,\n };\n};\n\n/**\n * Skip the current step. Deliberately the SAME transition as answering with nothing —\n * \"skipped\" and \"left blank\" are one concept, so there is one code path and no way for\n * the two to drift. On a REQUIRED step that identity is what makes skipping impossible:\n * committing \"\" is refused, so this returns the state unchanged.\n */\nexport const skipStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n): QuestionnaireStepState => commitStep(steps, state, \"\");\n\n/** Go back one step, keeping every draft so the user's earlier text is still there. */\nexport const goBack = (state: QuestionnaireStepState): QuestionnaireStepState =>\n state.index <= 0 ? state : { ...state, index: state.index - 1, direction: \"backward\" };\n\n/**\n * Project the drafts onto the answers contract. Missing/skipped steps become \"\" — the\n * exact input `buildQuestionnaireSubmission` already expects, which trims and maps the\n * two optional fields to null. The wire shape is unchanged by the multi-step rework.\n *\n * `opinion` can now legitimately be \"\" (step 1 is skippable), which the live server still\n * rejects with a 422 — see the REQUIRED_STEPS note above. That is a server fix, not a\n * reason to fabricate a value here.\n */\nexport const toAnswers = (drafts: StepDrafts): QuestionnaireAnswers => ({\n opinion: drafts.opinion ?? \"\",\n improve: drafts.improve ?? \"\",\n suggestions: drafts.suggestions ?? \"\",\n});\n","/**\n * transport.ts - kit → Wire server requests for the questionnaire module, all fire-and-forget\n * (a pre-onboarding questionnaire must NEVER break the app). Mirrors `submitReview`: a thin\n * fetch wrapper, Bearer tenant key, swallow every error.\n *\n * • submitQuestionnaireResponse → POST {serverUrl}/v1/questionnaires/{id}/responses\n * • fetchQuestionnaireDecision → GET {serverUrl}/v1/questionnaires/decision (best-effort)\n *\n * The decision fetch is HARD fail-open on the \"never show\" side: an unreachable endpoint, a\n * non-2xx (incl. 404), a missing `fetch`, or bad JSON all resolve to null, so a host wiring\n * pure server-directed firing simply shows nothing - exactly the reviews decision seam.\n */\nimport type {\n QuestionnaireDecisionResponse,\n QuestionnaireSubmission,\n QuestionnaireTarget,\n} from \"./types\";\n\n/**\n * POST a questionnaire response. Fire-and-forget: a missing target, a missing id, a build\n * error, a missing `fetch`, or a network failure is swallowed and the call returns immediately.\n */\nexport const submitQuestionnaireResponse = (\n target: QuestionnaireTarget | undefined,\n id: string,\n submission: QuestionnaireSubmission,\n): void => {\n if (!target?.serverUrl || !id) return;\n try {\n const base = target.serverUrl.replace(/\\/$/, \"\");\n const url = `${base}/v1/questionnaires/${encodeURIComponent(id)}/responses`;\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;\n void fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(submission),\n }).catch(() => {\n /* best-effort, swallow */\n });\n } catch {\n /* URL/JSON/missing-fetch - swallow */\n }\n};\n\n/** Options for the best-effort decision fetch. `deviceKey` groups a device's sessions server-side. */\nexport interface FetchQuestionnaireDecisionOptions {\n /** The onboarding/session id to correlate with, when known. */\n sessionId?: string;\n /** A stable, non-PII device id - the decision endpoint reads it for min-sessions. */\n deviceKey?: string;\n}\n\n/**\n * Best-effort fetch of the server firing decision. Returns the parsed\n * `{ fire, reason, questionnaire }` on a 2xx, else null. NEVER throws - any failure resolves\n * to null (fail-safe: the host shows nothing). The kit does not call this internally; a host\n * that wants server-directed firing awaits it and passes the result to `useQuestionnaireGate`\n * (the same AI seam the reviews gate uses).\n */\nexport const fetchQuestionnaireDecision = async (\n target: QuestionnaireTarget | undefined,\n options: FetchQuestionnaireDecisionOptions = {},\n): Promise<QuestionnaireDecisionResponse | null> => {\n if (!target?.serverUrl) return null;\n try {\n const base = target.serverUrl.replace(/\\/$/, \"\");\n const params = new URLSearchParams();\n if (options.sessionId) params.set(\"session_id\", options.sessionId);\n if (options.deviceKey) params.set(\"device_key\", options.deviceKey);\n const qs = params.toString();\n const url = `${base}/v1/questionnaires/decision${qs ? `?${qs}` : \"\"}`;\n const headers: Record<string, string> = {};\n if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;\n const res = await fetch(url, { headers });\n if (!res || !res.ok) return null;\n const json = (await res.json()) as QuestionnaireDecisionResponse | null;\n return json ?? null;\n } catch {\n /* unreachable / non-2xx / bad JSON / missing-fetch - never show */\n return null;\n }\n};\n","/**\n * QuestionnaireGate - the multi-step questionnaire popup.\n *\n * ONE question per step. Steps 1-2 are skippable; the LAST step is REQUIRED (Malik's\n * device test 2026-07-16: \"i want at least something forced\"). The user chooses which\n * thing they tell us, not whether they tell us anything. `steps.ts` owns that rule and\n * every transition as pure functions, unit-tested under node:test without mounting React;\n * this component is a thin renderer over that machine.\n *\n * The CHROME (back icon + step dots) is a static header, deliberately NOT part of the\n * sliding pane - see the four notes below. Only the question, its box and its controls move.\n *\n * - No title. The gate used to render `questionnaire.title` as a heading ON EVERY STEP,\n * directly above the step's own question. Two asking-texts stacked, one of them the same\n * string three times, and mid-slide the outgoing and incoming panes each drew their own\n * copy so it was briefly on screen TWICE. Malik saw it on the last step, where the\n * forced question most needs the focus. The question IS the heading now; it renders once.\n * - No \"Question 2 of 3\" counter. `StepDots` says it without spending a line next to the\n * question, which is what the user is supposed to be reading.\n * - Back is a top-left icon, not a link in the button stack, and it is simply absent on\n * step 1 rather than present-but-dead.\n * - No \"Not now\". Per-step Skip is the only in-card opt-out. `questionnaire_dismissed`\n * moved to the modal's dismiss path (backdrop tap / Android back) - see `handleDismissed`.\n *\n * The wire shape is UNCHANGED. `buildQuestionnaireSubmission` still builds the exact same\n * `POST /v1/questionnaires/{id}/responses` body from the same three answers; a skipped\n * step is simply an empty answer, which is what the builder already handled.\n *\n * ⚠️ This gate now REQUIRES the server to accept an empty `answers.opinion` - step 1 is\n * skippable and the live endpoint still 422s a blank opinion, silently (the transport is\n * fire-and-forget). See the REQUIRED_STEPS note in steps.ts. Server fix, not a client one.\n *\n * Motion: `ModalPaneHost` slides step→step (and mirrors the slide on Back) and resizes the\n * card; `StepDots` fills; `DoneCheck` plays the submit payoff. All shared, all reduce-motion\n * aware. Haptics are lazy + optional (`haptics/haptics.ts`) and silently absent otherwise.\n *\n * The form NEVER asks for identity (no name / email / contact field): the host already\n * identifies the user via `sessionId` + `meta` (user_id, device_key, session_count), which is\n * all the POST body carries alongside the answers. Every visual value comes from the\n * OnboardingTheme; analytics are callback-based (no PII - answers go ONLY in the POST body).\n */\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport { Pressable, StyleSheet, Text, TextInput, View } from \"react-native\";\n\nimport { Button } from \"../components/Button\";\nimport { CenteredModal, type CenteredModalHandle } from \"../components/CenteredModal\";\nimport { DoneCheck } from \"../components/DoneCheck\";\nimport { ModalPaneHost } from \"../components/ModalPaneHost\";\nimport { StepDots } from \"../components/StepDots\";\nimport { playHaptic } from \"../haptics/haptics\";\nimport { feedbackInputHeights } from \"../reviews/feedbackForm\";\nimport { mergeThemeOver } from \"../theme/mergeThemeOver\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport { bodyStyle, captionStyle, headingStyle } from \"../theme/typography\";\nimport { buildQuestionnaireSubmission } from \"./decision\";\nimport {\n buildQuestionnaireSteps,\n canGoBack,\n canSkipStep,\n commitStep,\n currentStep,\n goBack,\n initialStepState,\n isLastStep,\n skipStep,\n stashDraft,\n toAnswers,\n type QuestionnaireStepState,\n type StepDrafts,\n} from \"./steps\";\nimport { submitQuestionnaireResponse } from \"./transport\";\nimport type { QuestionnaireGateProps } from \"./types\";\n\ntype Phase = \"form\" | \"thanks\";\n\nconst _QuestionnaireGate: React.FC<QuestionnaireGateProps> = ({\n questionnaire,\n target,\n sessionId,\n meta,\n onEvent,\n onResolved,\n onShown,\n theme: themeOverride,\n dismissible = true,\n}) => {\n const active = useOnboardingTheme();\n const t = useMemo(() => mergeThemeOver(active, themeOverride), [active, themeOverride]);\n const modalRef = useRef<CenteredModalHandle>(null);\n\n const id = questionnaire.id;\n const steps = useMemo(\n () =>\n buildQuestionnaireSteps({\n opinion_label: questionnaire.opinion_label,\n improve_label: questionnaire.improve_label,\n suggestions_label: questionnaire.suggestions_label,\n }),\n [questionnaire.opinion_label, questionnaire.improve_label, questionnaire.suggestions_label],\n );\n\n const [phase, setPhase] = useState<Phase>(\"form\");\n const [state, setState] = useState<QuestionnaireStepState>(initialStepState);\n // Mirrored so the press handlers read the live state without re-subscribing every render\n // (the same ref-over-callback idiom the fire-once effect below uses).\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // The text for the step ON SCREEN. Deliberately a ref, not state: the inputs stay\n // UNCONTROLLED (`defaultValue`), so a keystroke never round-trips through React and the\n // box never lags or flickers on a low-end device. Each step's input is keyed, so it\n // remounts per step and `defaultValue` restores the earlier answer when the user steps Back.\n const draftRef = useRef(\"\");\n\n // ...but the REQUIRED last step does gate Send on the text, and a ref cannot re-render the\n // button. So we mirror ONE bit - \"is there non-whitespace text?\" - into state, and set it\n // only when that bit FLIPS. Typing a 200-character answer costs exactly one re-render (on\n // the first character), not 200: the middle ground between an uncontrolled box and a\n // control that has to know about its content.\n const [answered, setAnswered] = useState(false);\n const answeredRef = useRef(false);\n\n /** Point the draft at `value` and resync the flag. Used on every step transition. */\n const seedDraft = useCallback((value: string) => {\n draftRef.current = value;\n const has = value.trim().length > 0;\n answeredRef.current = has;\n setAnswered(has);\n }, []);\n\n /** Typing: always record, re-render only on the empty↔filled flip. */\n const handleChangeText = useCallback((text: string) => {\n draftRef.current = text;\n const has = text.trim().length > 0;\n if (has === answeredRef.current) return;\n answeredRef.current = has;\n setAnswered(has);\n }, []);\n\n // Fire questionnaire_prompt_shown exactly ONCE per mount. The callbacks are read through refs\n // (not effect deps) so an inline `onShown`/`onEvent` - recreated every render, as real hosts\n // idiomatically pass - never re-runs the effect. Empty deps + the shownRef guard make this a\n // true fire-once, immune to prop-identity churn.\n const shownRef = useRef(false);\n const onShownRef = useRef(onShown);\n const onEventRef = useRef(onEvent);\n onShownRef.current = onShown;\n onEventRef.current = onEvent;\n React.useEffect(() => {\n if (shownRef.current) return;\n shownRef.current = true;\n onShownRef.current?.();\n onEventRef.current?.({ name: \"questionnaire_prompt_shown\", id });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const resolveTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n React.useEffect(() => {\n return () => {\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n };\n }, []);\n\n // Set the instant we POST, so the dismiss path below can tell \"the user walked away\"\n // from \"the modal closed because the run finished\".\n const submittedRef = useRef(false);\n\n /**\n * The modal finished its exit animation. This is now the ONLY source of\n * `questionnaire_dismissed`.\n *\n * WHY it moved: the event used to fire from the in-card \"Not now\" link, which Malik cut.\n * Deleting the link without moving the event would have quietly zeroed a metric the\n * server counts. Dismissal is still very much reachable - `CenteredModal` dismisses on a\n * backdrop tap and on Android hardware back whenever `dismissible` - so the event belongs\n * on that path, not on one button that happened to trigger it.\n *\n * It also FIXES a hole: backdrop-tap and hardware-back dismissals never fired the event\n * before, so \"dismissed\" only ever counted the users who found the link. Every real\n * dismissal counts now, which means the number will legitimately RISE - it is a fuller\n * count, not a regression.\n *\n * The submit path closes the modal too (after the thank-you), hence the guard: finishing\n * is not dismissing. Read through `onEventRef` for the same prop-identity reason as the\n * fire-once effect above.\n */\n const handleDismissed = useCallback(() => {\n if (!submittedRef.current) {\n onEventRef.current?.({ name: \"questionnaire_dismissed\", id });\n }\n onResolved?.();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, onResolved]);\n\n // The run is over: POST the answers and play the payoff. Identity is NEVER collected here -\n // the host already sends user_id / device_key / session via `sessionId` + `meta`.\n const finish = useCallback(\n (drafts: StepDrafts) => {\n const submission = buildQuestionnaireSubmission({\n answers: toAnswers(drafts),\n sessionId,\n meta,\n });\n submitQuestionnaireResponse(target, id, submission);\n submittedRef.current = true;\n onEvent?.({ name: \"questionnaire_submitted\", id });\n playHaptic(\"success\");\n setPhase(\"thanks\");\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n resolveTimer.current = setTimeout(() => {\n modalRef.current?.close();\n }, 1500);\n },\n [sessionId, meta, target, id, onEvent],\n );\n\n // Apply a machine transition: either submit (last step) or seed the next step's draft.\n // A REFUSED transition (blank text on the required step) returns the same state object,\n // so bail: no haptic, no re-render, nothing to tell the user that the disabled button\n // already told them.\n const applyTransition = useCallback(\n (next: QuestionnaireStepState) => {\n if (next === stateRef.current) return;\n setState(next);\n if (next.done) {\n finish(next.drafts);\n return;\n }\n seedDraft(next.drafts[steps[next.index]?.key ?? \"opinion\"] ?? \"\");\n playHaptic(\"light\");\n },\n [finish, seedDraft, steps],\n );\n\n const handleNext = useCallback(() => {\n applyTransition(commitStep(steps, stateRef.current, draftRef.current));\n }, [applyTransition, steps]);\n\n const handleSkip = useCallback(() => {\n applyTransition(skipStep(steps, stateRef.current));\n }, [applyTransition, steps]);\n\n const handleBack = useCallback(() => {\n // Stash the CURRENT step's text before leaving it. The inputs are uncontrolled, so that\n // text lives ONLY in draftRef until something folds it into the drafts; Back without this\n // destroyed it, and the keyed input silently remounted blank when the user stepped\n // forward again. Same primitive `commitStep` uses for Next — one way to record an answer.\n const next = goBack(stashDraft(steps, stateRef.current, draftRef.current));\n setState(next);\n seedDraft(next.drafts[steps[next.index]?.key ?? \"opinion\"] ?? \"\");\n playHaptic(\"light\");\n }, [seedDraft, steps]);\n\n const step = currentStep(steps, state);\n const last = isLastStep(steps, state.index);\n // The mandatory last step: no Skip control at all, and Send stays disabled until there is\n // text. `answered` tracks the live box; `canSkipStep` is the machine's own read of the\n // same `required` flag it enforces in `commitStep`, so the two can never disagree.\n const canSkip = canSkipStep(steps, state);\n const sendDisabled = (step?.required ?? false) && !answered;\n\n // A multiline box ~4 lines tall (capped at ~5), derived from the theme's body line-height so\n // it scales with the app's font config; padding is folded in so the lines are visible. Every\n // step uses the SAME box, which also keeps the card's height near-steady between steps.\n const answerBox = feedbackInputHeights(t.fonts, t.spacing.md);\n\n const linkStyle = [captionStyle(t.fonts), styles.link, { color: t.colors.textMuted }];\n\n /**\n * The card's chrome: back icon hard left, dots centred. Handed to `ModalPaneHost`'s\n * static slot, so it is measured with the pane but never slides and never doubles\n * mid-handoff. The two side spacers are equal-flex so the dots sit at the true centre\n * whether or not Back is there — the row must not shift between step 1 and step 2.\n */\n const header =\n phase === \"form\" ? (\n <View style={[styles.header, { marginBottom: t.spacing.md }]}>\n <View style={styles.headerSide}>\n {/* Absent on step 1 rather than disabled: there is nothing to go back to, and a\n greyed-out control is just a question the user has to answer. */}\n {canGoBack(state) && (\n <Pressable\n onPress={handleBack}\n hitSlop={12}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Back to the previous question\"\n >\n {/* A Text glyph, not an icon component: `react-native-svg` is not a peer of\n this kit and no vector library is worth forcing every host into a native\n rebuild for one chevron. Same call DoneCheck's ✓ and the review stars made. */}\n <Text style={[headingStyle(t.fonts), styles.backGlyph, { color: t.colors.textMuted }]}>\n ‹\n </Text>\n </Pressable>\n )}\n </View>\n <StepDots theme={t} count={steps.length} index={state.index} />\n <View style={styles.headerSide} />\n </View>\n ) : null;\n\n const formPane = step ? (\n <View style={{ gap: t.spacing.md }}>\n {/* The question is the heading. There is no separate title above it — see the file\n header: that was the text Malik saw repeated. */}\n <Text style={[headingStyle(t.fonts), { color: t.colors.text }]}>{step.label}</Text>\n <TextInput\n // Keyed per step so each question gets a fresh input seeded with its own answer.\n key={step.key}\n defaultValue={state.drafts[step.key] ?? \"\"}\n onChangeText={handleChangeText}\n placeholder={step.placeholder}\n placeholderTextColor={t.colors.textMuted}\n accessibilityLabel={step.label}\n multiline\n textAlignVertical=\"top\"\n style={[\n bodyStyle(t.fonts),\n styles.input,\n {\n color: t.colors.text,\n backgroundColor: t.colors.background,\n borderRadius: t.radius.md,\n borderColor: t.colors.border,\n padding: t.spacing.md,\n minHeight: answerBox.minHeight,\n maxHeight: answerBox.maxHeight,\n },\n ]}\n />\n\n {/* Gated ONLY on the required step. Steps 1-2 send/advance whatever the box holds,\n because skipping is a first-class answer there and there is nothing to gate on. */}\n <Button\n title={last ? \"Send\" : \"Next\"}\n onPress={handleNext}\n variant=\"primary\"\n fullWidth\n disabled={sendDisabled}\n />\n\n {/* Skip step — the only in-card opt-out, and gone entirely on the required step\n rather than rendered as a control that would refuse to do anything. */}\n {canSkip && (\n <Pressable\n onPress={handleSkip}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Skip this question\"\n >\n <Text style={linkStyle}>Skip step</Text>\n </Pressable>\n )}\n </View>\n ) : null;\n\n const thanksPane = (\n <View style={{ gap: t.spacing.md }}>\n <DoneCheck theme={t} />\n <Text style={[headingStyle(t.fonts), styles.centerText, { color: t.colors.text }]}>\n Thank you\n </Text>\n <Text style={[bodyStyle(t.fonts), styles.centerText, { color: t.colors.textMuted }]}>\n This helps us make it better.\n </Text>\n </View>\n );\n\n return (\n <CenteredModal ref={modalRef} theme={t} dismissible={dismissible} onDismiss={handleDismissed}>\n <ModalPaneHost\n paneKey={phase === \"thanks\" ? \"thanks\" : (step?.key ?? \"done\")}\n direction={state.direction}\n header={header}\n >\n {phase === \"thanks\" ? thanksPane : formPane}\n </ModalPaneHost>\n </CenteredModal>\n );\n};\n\nexport const QuestionnaireGate = React.memo(_QuestionnaireGate);\nQuestionnaireGate.displayName = \"QuestionnaireGate\";\n\nconst styles = StyleSheet.create({\n input: { borderWidth: 1 },\n link: { textAlign: \"center\", textDecorationLine: \"underline\" },\n centerText: { textAlign: \"center\" },\n header: { flexDirection: \"row\", alignItems: \"center\" },\n // Equal flex on both sides keeps the dots optically centred whether Back is drawn or not.\n // `flex-start` matters: without it the back Pressable stretches across the whole left\n // third of the card, so a tap anywhere near the dots would navigate back.\n headerSide: { flex: 1, alignItems: \"flex-start\" },\n backGlyph: { includeFontPadding: false },\n});\n\nexport default QuestionnaireGate;\n","/**\n * Module-level runtime for the coachmark engine: the injected sync storage, the\n * global `isTestingCoachmark` flag, and the seen-gate helpers built on top.\n *\n * WHY module singletons (not just context): the tour hooks and the anchor\n * registry are driven imperatively from anywhere in the tree (a screen deep\n * under the navigator), while the storage + testing flag are configured once at\n * the root by `CoachmarkProvider`. Singletons let a hook read the gate without\n * every call site threading the storage through props. The provider is still the\n * single writer — it calls `setCoachmarkStorage` / `setCoachmarkTesting` on mount.\n */\nimport type { CoachmarkStorage } from \"./types\";\n\nlet storageSingleton: CoachmarkStorage | null = null;\nlet testing = false;\n// The coachmarks feature kill switch (from GET /v1/features). Default true = fail-open: with no\n// flags fetched, coachmarks behave exactly as before. CoachmarkProvider writes it from the\n// resolved flags. Disabled → the tour never ARMS and the overlay `show()` is a no-op, so nothing\n// paints and — critically — no once-gate is written, so re-enabling replays the tour correctly.\nlet coachmarksEnabled = true;\n\n/**\n * Set the coachmarks master switch (from the resolved feature flags). Default true (fail-open).\n * Written by CoachmarkProvider; read imperatively by the tour arm + the overlay store.\n */\nexport const setCoachmarksEnabled = (value: boolean): void => {\n coachmarksEnabled = value;\n};\n\n/** Whether the coachmarks module is enabled. False → tours/overlays are silently skipped. */\nexport const areCoachmarksEnabled = (): boolean => coachmarksEnabled;\n\n/** Set (or clear) the injected sync gate storage. Called by CoachmarkProvider. */\nexport const setCoachmarkStorage = (storage: CoachmarkStorage | null): void => {\n storageSingleton = storage;\n};\n\n/** The currently-injected gate storage, or null if no provider is mounted. */\nexport const getCoachmarkStorage = (): CoachmarkStorage | null => storageSingleton;\n\n/**\n * Toggle the global QA replay flag. When true, EVERY seen-gate reads as unseen\n * and every seen-write is suppressed, so every tour + showcase replays on each\n * mount. The app flips ONE boolean to QA the whole coachmark surface.\n */\nexport const setCoachmarkTesting = (value: boolean): void => {\n testing = value;\n};\n\n/** Whether replay-everything QA mode is on. */\nexport const isCoachmarkTesting = (): boolean => testing;\n\n/** Gate key for a tour: `wire_coachmark_<tourId>_seen`. */\nexport const coachmarkGateKey = (tourId: string): string =>\n `wire_coachmark_${tourId}_seen`;\n\n/** Gate key for a feature showcase: `wire_showcase_<id>_seen`. */\nexport const showcaseGateKey = (showcaseId: string): string =>\n `wire_showcase_${showcaseId}_seen`;\n\n/** Marker value written for a seen gate. */\nconst SEEN_VALUE = \"1\";\n\n/**\n * Read a seen gate. Testing mode ALWAYS reports unseen (so everything replays).\n * A missing storage (no provider) also reports unseen — the safe default is to\n * show the hint rather than silently swallow it. `storageOverride` /\n * `testingOverride` let a self-contained component (e.g. FeatureShowcase) pass\n * its own storage without relying on the provider singleton.\n */\nexport const hasSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): boolean => {\n if (testingOverride ?? testing) return false;\n const storage = storageOverride ?? storageSingleton;\n if (!storage) return false;\n try {\n return storage.getItem(key) === SEEN_VALUE;\n } catch {\n return false;\n }\n};\n\n/**\n * Mark a gate seen. Suppressed in testing mode (so replay never persists) and a\n * no-op without storage. Best-effort — a throwing adapter never breaks the tour.\n */\nexport const markSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): void => {\n if (testingOverride ?? testing) return;\n const storage = storageOverride ?? storageSingleton;\n if (!storage) return;\n try {\n storage.setItem(key, SEEN_VALUE);\n } catch {\n // Best-effort: a failed write just means the hint may show once more.\n }\n};\n","/**\n * The fail-open defaults + a tolerant parser for the server's flags payload.\n *\n * THE CONTRACT: fail-open, never fail-dark. An absent server object, a missing module key, a\n * malformed value, or an unreachable endpoint must resolve to the MOST PERMISSIVE state — every\n * module ON, onboarding `ai` — so a control-plane outage can only ever be more permissive than\n * the dashboard intends. It can never dark a tenant's activation. Matches the server's own\n * documented fail-open default (FEATURES.md: \"local defaults — every module on, onboarding ai\").\n */\nimport type { OnboardingMode, WireFeatures } from \"./types\";\n\n/**\n * ALL ON, onboarding `ai`. Frozen + module-level so its reference is stable across every call\n * (consumers that list resolved flags in an effect dep array never loop on a fresh identity).\n */\nexport const defaultWireFeatures: WireFeatures = Object.freeze({\n coachmarks: Object.freeze({ enabled: true }),\n showcase: Object.freeze({ enabled: true }),\n onboarding: Object.freeze({ mode: \"ai\" as OnboardingMode }),\n review: Object.freeze({ enabled: true }),\n questionnaire: Object.freeze({ enabled: true }),\n announcements: Object.freeze({ enabled: true }),\n}) as WireFeatures;\n\nconst VALID_MODES: readonly OnboardingMode[] = [\"ai\", \"static\", \"off\"];\n\n/** Read a `{ enabled: boolean }` module, defaulting to ON when absent/malformed (fail-open). */\nconst readEnabled = (raw: unknown): { enabled: boolean } => {\n if (raw && typeof raw === \"object\" && typeof (raw as { enabled?: unknown }).enabled === \"boolean\") {\n return { enabled: (raw as { enabled: boolean }).enabled };\n }\n return { enabled: true };\n};\n\n/**\n * Narrow the server's (untrusted) JSON to a complete `WireFeatures`. Every field is filled with\n * its fail-open default when the server omits it or sends the wrong type, so a partial or\n * malformed payload degrades PERMISSIVELY rather than throwing. A non-object input (null, array,\n * string) → the full defaults. Never throws.\n */\nexport const parseWireFeatures = (raw: unknown): WireFeatures => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return defaultWireFeatures;\n const src = raw as Record<string, unknown>;\n const modeRaw = (src.onboarding as { mode?: unknown } | undefined)?.mode;\n const mode: OnboardingMode =\n typeof modeRaw === \"string\" && VALID_MODES.includes(modeRaw as OnboardingMode)\n ? (modeRaw as OnboardingMode)\n : \"ai\";\n return {\n coachmarks: readEnabled(src.coachmarks),\n showcase: readEnabled(src.showcase),\n onboarding: { mode },\n review: readEnabled(src.review),\n questionnaire: readEnabled(src.questionnaire),\n announcements: readEnabled(src.announcements),\n };\n};\n\n/** Value-equality of two resolved flags — lets the hook hold a stable reference across churn. */\nexport const featuresEqual = (a: WireFeatures, b: WireFeatures): boolean =>\n a === b ||\n (a.coachmarks.enabled === b.coachmarks.enabled &&\n a.showcase.enabled === b.showcase.enabled &&\n a.onboarding.mode === b.onboarding.mode &&\n a.review.enabled === b.review.enabled &&\n a.questionnaire.enabled === b.questionnaire.enabled &&\n a.announcements.enabled === b.announcements.enabled);\n","/**\n * The last-known-flags cache — persisted through the host's optional `storage`.\n *\n * WHY: the fetch is best-effort and fail-open. When the control plane is unreachable we serve the\n * LAST value we saw rather than snapping to defaults, so a tenant that intentionally disabled a\n * module during an incident keeps it disabled across an outage instead of flapping back on. That\n * is \"stale-while-error\": a fresh cache (< TTL) is trusted, and on a fetch error even a STALE\n * cache is served (any age beats a guess). Every operation is best-effort — a broken/hung storage\n * degrades to defaults, never a throw and never a stuck gate (mirrors persistedSession).\n */\nimport { parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\n/**\n * TTL for a cached flags entry, aligned to the server's `Cache-Control: private, max-age=300`.\n * A cache younger than this is \"fresh\"; older is \"stale\" (still served on a fetch error).\n */\nexport const DEFAULT_FEATURES_TTL_MS = 300_000;\n\n/** Ceiling on the storage read so a hung adapter degrades to defaults, never a stuck resolve. */\nconst READ_TIMEOUT_MS = 1_500;\n\n/** Storage key for a tenant's cached flags, e.g. `wireai:features:acme`. */\nexport const featuresCacheKey = (appId?: string): string =>\n `wireai:features:${appId && appId.length > 0 ? appId : \"default\"}`;\n\n/** A cached flags entry: the resolved flags + the epoch-ms they were fetched. */\nexport interface CachedFeatures {\n features: WireFeatures;\n /** Age of the entry in ms at read time. */\n ageMs: number;\n}\n\nconst withTimeout = <T>(p: Promise<T>, ms: number): Promise<T | undefined> => {\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), ms);\n });\n return Promise.race([p, timeout]).finally(() => clearTimeout(timer));\n};\n\n/** Whether a cache entry is still within the TTL (server max-age aligned). */\nexport const isFeaturesFresh = (ageMs: number, ttlMs: number = DEFAULT_FEATURES_TTL_MS): boolean =>\n ageMs >= 0 && ageMs < ttlMs;\n\n/**\n * Read the cached flags for `key`, or `undefined` when absent/corrupt/timed-out. Returns the\n * value AND its age so a caller can apply a TTL (fresh) or ignore it (stale-while-error). Never\n * throws; never hangs past the read timeout. The stored value is re-parsed through\n * `parseWireFeatures`, so a partially-corrupt entry still degrades fail-open.\n */\nexport const readCachedFeatures = async (\n storage: WireOnboardingStorage,\n key: string,\n): Promise<CachedFeatures | undefined> => {\n let raw: string | null | undefined;\n try {\n raw = await withTimeout(storage.getItem(key), READ_TIMEOUT_MS);\n } catch {\n return undefined;\n }\n if (!raw) return undefined;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && typeof (parsed as { ts?: unknown }).ts === \"number\") {\n const ts = (parsed as { ts: number }).ts;\n return {\n features: parseWireFeatures((parsed as { features?: unknown }).features),\n ageMs: Date.now() - ts,\n };\n }\n } catch {\n // Corrupt entry → treat as absent; the caller falls back to defaults / a fresh fetch.\n }\n return undefined;\n};\n\n/** Persist `{ features, ts }` under `key` — fire-and-forget, all errors swallowed. */\nexport const writeCachedFeatures = (\n storage: WireOnboardingStorage,\n key: string,\n features: WireFeatures,\n): void => {\n try {\n void storage\n .setItem(key, JSON.stringify({ features, ts: Date.now() }))\n .catch(() => {});\n } catch {\n // Best-effort: a failed write just means the next launch has no cache to fall back to.\n }\n};\n","/**\n * fetchWireFeatures — read the per-module kill switches from `GET {serverUrl}/v1/features`.\n *\n * Contract (server: chohra-med/wireai-onboarding-server, routers/onboarding.py):\n * GET {serverUrl}/v1/features\n * Authorization: Bearer {apiKey}\n * 200 → { coachmarks:{enabled}, showcase:{enabled}, onboarding:{mode}, review:{enabled},\n * announcements:{enabled} } (Cache-Control: private, max-age=300)\n *\n * THE CONTRACT — fail-open, never fail-dark. Unreachable, timed-out, unauthorized (401),\n * server-error (5xx), or malformed JSON all resolve to the LAST CACHED value, else the\n * all-on defaults. No throw ever reaches the host: this is timeout-capped and swallows every\n * error, exactly like the session's best-effort reads. A control-plane outage can only ever be\n * MORE permissive than the dashboard intends — it can never dark a tenant's activation.\n */\nimport { readCachedFeatures, featuresCacheKey, writeCachedFeatures } from \"./cache\";\nimport { defaultWireFeatures, parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\nconst DEFAULT_TIMEOUT_MS = 4_000;\n\n/** The fail-open fallback: last cached value (any age — stale-while-error), else defaults. */\nconst failOpen = async (\n storage: WireOnboardingStorage | undefined,\n key: string,\n): Promise<WireFeatures> => {\n if (!storage) return defaultWireFeatures;\n const cached = await readCachedFeatures(storage, key);\n return cached?.features ?? defaultWireFeatures;\n};\n\n/** GET with a hard timeout via AbortController (falls back to no-abort where unsupported). */\nconst fetchWithTimeout = async (\n url: string,\n apiKey: string,\n timeoutMs: number,\n): Promise<Response> => {\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : undefined;\n const timer = setTimeout(() => controller?.abort(), timeoutMs);\n try {\n return await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\", Authorization: `Bearer ${apiKey}` },\n signal: controller?.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n};\n\n/**\n * Resolve the tenant's feature flags. Attempts the network once; on ANY failure returns the\n * cached value (any age), else the all-on defaults. On success, persists the fresh value to the\n * cache (fire-and-forget) and returns it. Never throws.\n *\n * const flags = await fetchWireFeatures({ serverUrl, apiKey, appId, storage });\n * if (!flags.coachmarks.enabled) { /* skip the tour * / }\n */\nexport const fetchWireFeatures = async (\n config?: WireFeaturesConfig,\n): Promise<WireFeatures> => {\n const key = featuresCacheKey(config?.appId);\n const storage = config?.storage;\n\n // Nothing to fetch (no creds) → cache, else defaults. Lets a host mount the provider before\n // its config is ready without ever darking.\n if (!config?.serverUrl || !config?.apiKey) return failOpen(storage, key);\n\n const url = `${config.serverUrl.replace(/\\/$/, \"\")}/v1/features`;\n const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;\n\n try {\n const res = await fetchWithTimeout(url, config.apiKey, timeoutMs);\n // 401 (bad/rotated key), 5xx, any non-2xx → last-known, never dark.\n if (!res || !res.ok) return failOpen(storage, key);\n const json: unknown = await res.json(); // throws on malformed body → caught below\n const features = parseWireFeatures(json);\n if (storage) writeCachedFeatures(storage, key, features);\n return features;\n } catch {\n // Timeout/abort, network error, missing fetch, or malformed JSON — all fail open.\n return failOpen(storage, key);\n }\n};\n","/**\n * useWireFeatures — resolve the tenant's feature flags for a component tree, once per mount.\n *\n * Returns the all-on defaults immediately (fail-open), then swaps to the fetched value when the\n * network resolves. When no `serverUrl`+`apiKey` is supplied it never fetches and just returns\n * defaults, so a host that never adopts flags sees ZERO behavior change and ZERO network calls.\n *\n * frequent_rules #11 (unstable inline props): the config is idiomatically passed inline\n * (`config={{ serverUrl, apiKey }}`), a fresh identity every render. We stabilize the fetch key\n * by VALUE so the effect fires once per real credential change, and we only swap the returned\n * flags object when its VALUES change — so a host that lists the returned flags in an effect dep\n * array settles in a bounded number of commits instead of looping (enforced by the canary suite).\n */\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { defaultWireFeatures, featuresEqual } from \"./defaults\";\nimport { fetchWireFeatures } from \"./fetchWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\n/** Hold a stable reference for a value while its CONTENT is unchanged (see reviews/equality.ts). */\nconst useStableValue = <T,>(value: T, isEqual: (a: T, b: T) => boolean): T => {\n const ref = useRef(value);\n if (!isEqual(ref.current, value)) ref.current = value;\n return ref.current;\n};\n\n/** The credential slice that actually drives a refetch — stabilized by value. */\nconst sameFetchKey = (a: WireFeaturesConfig | undefined, b: WireFeaturesConfig | undefined): boolean =>\n a?.serverUrl === b?.serverUrl && a?.apiKey === b?.apiKey && a?.appId === b?.appId;\n\nexport const useWireFeatures = (config?: WireFeaturesConfig): WireFeatures => {\n const stableConfig = useStableValue(config, sameFetchKey);\n const [flags, setFlags] = useState<WireFeatures>(defaultWireFeatures);\n\n const canFetch = !!stableConfig?.serverUrl && !!stableConfig?.apiKey;\n\n useEffect(() => {\n if (!canFetch) {\n // No creds → stay on the all-on defaults (and reset if creds were removed).\n setFlags((prev) => (featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures));\n return;\n }\n let alive = true;\n // fetchWireFeatures never throws — the .then always runs with a fail-open value.\n void fetchWireFeatures(stableConfig).then((next) => {\n if (!alive) return;\n // Only adopt a NEW reference on a real value change, so a host effect keyed on the\n // returned flags doesn't loop (frequent_rules #11).\n setFlags((prev) => (featuresEqual(prev, next) ? prev : next));\n });\n return () => {\n alive = false;\n };\n }, [canFetch, stableConfig]);\n\n return flags;\n};\n","/**\n * WireFeaturesProvider + useResolvedFeatures — the OPTIONAL one-fetch-serves-all-modules layer.\n *\n * Mount `WireFeaturesProvider` once near your app root with the tenant `config` and it fetches the\n * flags ONCE; every gated surface below it (coachmarks / showcase / reviews) reads the same\n * resolved value from context instead of each fetching its own. It is entirely optional: with no\n * provider, every surface falls back to its own lazy fetch (when given a config) or to the all-on\n * defaults, so modules work with zero setup and a host that never adopts flags is unchanged.\n *\n * NOTE on the built npm subpaths: React context is shared across the kit's subpath entries in the\n * SOURCE-consumption path (the monorepo apps) and in this test suite — one module instance, one\n * context. If you consume the built `@wireai/activation/*` subpaths as separate bundles, pass the\n * resolved flags (or a `featuresConfig`) to each surface explicitly instead of relying on context.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\n\nimport { defaultWireFeatures } from \"./defaults\";\nimport { useWireFeatures } from \"./useWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\nconst CONTEXT_SYMBOL = Symbol.for(\"wireai.features.context\");\nconst globalObj = global as any;\n\nif (!globalObj[CONTEXT_SYMBOL]) {\n globalObj[CONTEXT_SYMBOL] = createContext<WireFeatures | null>(null);\n}\nconst WireFeaturesContext = globalObj[CONTEXT_SYMBOL];\n\nexport interface WireFeaturesProviderProps {\n /** Tenant creds (+ optional storage) to fetch the flags once for the whole tree. */\n config?: WireFeaturesConfig;\n /**\n * Pre-resolved flags to provide directly instead of fetching (e.g. you already have them, or\n * you drive them from your own remote-config). Takes precedence over `config`.\n */\n flags?: WireFeatures;\n children: React.ReactNode;\n}\n\n/**\n * Fetch (or accept) the flags once and broadcast them to descendants. The provider VALUE is\n * memoized (performance rule #6) so a fresh object each render doesn't re-render every consumer.\n */\nexport const WireFeaturesProvider: React.FC<WireFeaturesProviderProps> = ({\n config,\n flags,\n children,\n}) => {\n // Always call the hook (rules of hooks); when `flags` is supplied we pass no config so it\n // never fetches and the explicit flags win below.\n const fetched = useWireFeatures(flags ? undefined : config);\n const value = flags ?? fetched;\n const stable = useMemo(() => value, [value]);\n return <WireFeaturesContext.Provider value={stable}>{children}</WireFeaturesContext.Provider>;\n};\n\nWireFeaturesProvider.displayName = \"WireFeaturesProvider\";\n\n/** Raw context read — `null` when no `WireFeaturesProvider` is mounted above. */\nexport const useWireFeaturesContext = (): WireFeatures | null =>\n useContext(WireFeaturesContext);\n\n/** Options for `useResolvedFeatures`: an explicit override and/or a lazy-fetch config. */\nexport interface ResolveFeaturesOptions {\n /** Explicit flags — win over everything (a surface's own `features` prop). */\n flags?: WireFeatures;\n /** Lazy-fetch config, used ONLY when there is no explicit `flags` and no provider above. */\n config?: WireFeaturesConfig;\n}\n\n/**\n * The resolution every gated surface uses. Precedence:\n * 1. explicit `options.flags` (a surface's own prop) →\n * 2. the nearest `WireFeaturesProvider` (context) →\n * 3. a lazy fetch from `options.config` (serverUrl + apiKey) →\n * 4. the all-on defaults.\n * Always fail-open, always a stable reference for a given value (so it's safe in effect deps).\n */\nexport const useResolvedFeatures = (options?: ResolveFeaturesOptions): WireFeatures => {\n const ctx = useWireFeaturesContext();\n // Only lazily fetch when nothing else provides the flags — otherwise pass no config so the\n // hook stays inert (defaults, no network). The hook is always called (rules of hooks).\n const shouldFetch = !options?.flags && ctx == null;\n const fetched = useWireFeatures(shouldFetch ? options?.config : undefined);\n return options?.flags ?? ctx ?? fetched ?? defaultWireFeatures;\n};\n","/**\n * equality.ts — tiny, dependency-free value-equality helpers used to STABILIZE\n * references across renders.\n *\n * WHY this exists: real integrators pass inline objects — `config={{ id: 'x' }}`,\n * `decision={{ fire: true }}` — whose IDENTITY changes every render even though\n * their VALUES do not. If the review hook let those unstable references flow into\n * a `useMemo`/`useEffect` dependency list (or handed a fresh verdict object back\n * every render), a host that depends on the returned value would re-run its own\n * effect forever → \"Maximum update depth exceeded\". A library must tolerate inline\n * props without looping; these helpers are how the hook holds a stable reference\n * whenever the underlying values are unchanged.\n *\n * Pure (no React import) so it runs under the kit's node:test runner.\n */\nimport type { ReviewDecision } from \"./types\";\n\n/**\n * One-level value-equality of two plain objects (or primitives). Same-reference is\n * equal; two objects are equal when they have the same keys and each value is\n * `Object.is`-equal. Good enough for the flat `config` / `decision` shapes the gate\n * accepts (all leaf values are primitives).\n */\nexport const shallowEqual = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true;\n if (\n a == null ||\n b == null ||\n typeof a !== \"object\" ||\n typeof b !== \"object\"\n ) {\n return false;\n }\n const ak = Object.keys(a as Record<string, unknown>);\n const bk = Object.keys(b as Record<string, unknown>);\n if (ak.length !== bk.length) return false;\n for (const k of ak) {\n if (!Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k])) {\n return false;\n }\n }\n return true;\n};\n\n/**\n * Structural equality of two review verdicts by their contract fields (`fire`,\n * `reason`). A `null`/`undefined` verdict equals only another absent one. Used to\n * decide whether the hook can keep returning the SAME verdict object (so a host\n * that lists `controller.decision` in an effect dep array never loops).\n */\nexport const sameDecision = (a?: ReviewDecision | null, b?: ReviewDecision | null): boolean => {\n if (a == null || b == null) return a == b;\n return a.fire === b.fire && a.reason === b.reason;\n};\n","/**\n * Runtime helpers for the review gate: the `wire_review_*` gate keys and small\n * typed storage accessors. The gate reuses the SAME injected sync storage + global\n * testing flag as the coachmark engine (see coachmarks/runtime), so a host that\n * mounted CoachmarkProvider gets review gating for free — no second storage to wire.\n */\nimport type { CoachmarkStorage } from \"../coachmarks/types\";\nimport { getCoachmarkStorage } from \"../coachmarks/runtime\";\n\n/** Once-gate key. Keyed by app version when `oncePerVersion` is on, so a new release re-enables. */\nexport const reviewSeenKey = (id: string, version?: string): string =>\n version ? `wire_review_${id}_${version}_seen` : `wire_review_${id}_seen`;\n\n/** Last-shown timestamp key (epoch ms), for the cooldown rule. */\nexport const reviewLastShownKey = (id: string): string => `wire_review_${id}_last`;\n\n/** Session-count key, incremented once per gate mount, for the min-sessions rule. */\nexport const reviewSessionsKey = (id: string): string => `wire_review_${id}_sessions`;\n\n/** Resolve the storage to use: an explicit override, else the provider-injected singleton. */\nexport const resolveStorage = (\n override?: CoachmarkStorage | null,\n): CoachmarkStorage | null => override ?? getCoachmarkStorage();\n\n/** Read an integer from sync storage (0 on a missing/unparseable/throwing read). */\nexport const readInt = (storage: CoachmarkStorage | null, key: string): number => {\n if (!storage) return 0;\n try {\n const raw = storage.getItem(key);\n const n = raw == null ? 0 : parseInt(raw, 10);\n return Number.isFinite(n) ? n : 0;\n } catch {\n return 0;\n }\n};\n\n/** Write an integer to sync storage. Best-effort — a throwing adapter never breaks the gate. */\nexport const writeInt = (storage: CoachmarkStorage | null, key: string, value: number): void => {\n if (!storage) return;\n try {\n storage.setItem(key, String(value));\n } catch {\n // Best-effort.\n }\n};\n","/**\n * Runtime helpers for the questionnaire gate: the `wire_questionnaire_*` gate keys. The\n * gate reuses the SAME injected sync storage + global testing flag as the coachmark engine\n * (via `resolveStorage`/`readInt`/`writeInt`, re-exported from the reviews runtime), so a\n * host that mounted CoachmarkProvider gets questionnaire gating for free - no second storage\n * to wire. Once-per-user is keyed on the questionnaire `id`.\n */\nexport { resolveStorage, readInt, writeInt } from \"../reviews/runtime\";\n\n/** Once-gate key. Keyed by app version when `oncePerVersion` is on, so a new release re-enables. */\nexport const questionnaireSeenKey = (id: string, version?: string): string =>\n version ? `wire_questionnaire_${id}_${version}_seen` : `wire_questionnaire_${id}_seen`;\n\n/** Last-shown timestamp key (epoch ms), for the cooldown rule. */\nexport const questionnaireLastShownKey = (id: string): string =>\n `wire_questionnaire_${id}_last`;\n\n/** Session-count key, incremented once per gate mount, for the min-sessions rule. */\nexport const questionnaireSessionsKey = (id: string): string =>\n `wire_questionnaire_${id}_sessions`;\n","/**\n * useQuestionnaireGate - owns WHEN the questionnaire gate shows.\n *\n * v1 decision = local rules from `config` (enabled / minSessions / minEvents / cooldownDays\n * / oncePerVersion), evaluated against the same injected sync storage as the coachmark\n * engine (`wire_questionnaire_*` keys). The AI seam: pass a server-provided `decision` and it\n * OVERRIDES the local rules (see decideQuestionnaire). The whole cost of being AI-ready is\n * passing that object straight through - mirroring `useReviewGate` exactly.\n *\n * Fallback chain (matches the server design): (1) a server `decision` wins immediately;\n * (2) no decision → after `timeoutFallbackMs` the local rules take over; (3) the once-gate\n * (`wire_questionnaire_<id>_seen`) always applies locally, so a server bug can never re-spam\n * the popup. The global `isTestingCoachmark` flag force-shows the gate for QA replay, and the\n * `questionnaire` master switch (a disabled tenant) wins over everything.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { hasSeenGate, isCoachmarkTesting, markSeenGate } from \"../coachmarks/runtime\";\nimport { useResolvedFeatures } from \"../features/WireFeaturesProvider\";\nimport { sameDecision, shallowEqual } from \"../reviews/equality\";\nimport { decideQuestionnaire, evaluateGate, resolveRules } from \"./decision\";\nimport {\n questionnaireLastShownKey,\n questionnaireSeenKey,\n questionnaireSessionsKey,\n readInt,\n resolveStorage,\n writeInt,\n} from \"./runtime\";\nimport type {\n QuestionnaireDecision,\n QuestionnaireGateController,\n UseQuestionnaireGateOptions,\n} from \"./types\";\n\n/**\n * Hold a stable reference for a value while its CONTENT is unchanged. Integrators pass inline\n * `config` / `decision` objects (idiomatic React) whose identity flips every render; feeding\n * those straight into the deps below would recompute the verdict - and mint a fresh verdict\n * object - on every render, which loops any host that lists the returned verdict in its own\n * effect. Comparing by value here keeps the reference (and everything derived from it) stable.\n */\nconst useStableValue = <T,>(value: T, isEqual: (a: T, b: T) => boolean): T => {\n const ref = useRef(value);\n if (!isEqual(ref.current, value)) ref.current = value;\n return ref.current;\n};\n\nexport const useQuestionnaireGate = ({\n config: configProp,\n decision: decisionProp,\n events = 0,\n storage,\n isTesting,\n features,\n featuresConfig,\n}: UseQuestionnaireGateOptions): QuestionnaireGateController => {\n // Tolerate inline-identity props: only adopt a new reference on a real value change.\n const config = useStableValue(configProp, shallowEqual);\n const decision = useStableValue(decisionProp, (a, b) => sameDecision(a, b));\n\n // The questionnaire MASTER switch. Disabled → the gate never fires, composing as an extra\n // AND over the local rules + the server decision seam below (fail-open: defaults to enabled).\n const featureEnabled = useResolvedFeatures({ flags: features, config: featuresConfig })\n .questionnaire.enabled;\n\n const testing = isTesting ?? isCoachmarkTesting();\n const seenKey = questionnaireSeenKey(\n config.id,\n config.oncePerVersion === false ? undefined : config.appVersion,\n );\n const lastKey = questionnaireLastShownKey(config.id);\n const sessionsKey = questionnaireSessionsKey(config.id);\n\n // Read (and bump) the session counter ONCE per mount: this mount is a new session.\n const sessions = useState(() => {\n const store = resolveStorage(storage);\n const next = readInt(store, sessionsKey) + 1;\n writeInt(store, sessionsKey, next);\n return next;\n })[0];\n\n // Gate the local rules behind an optional client-side timeout, so a reachable server gets a\n // window to answer first. A present `decision` bypasses the wait entirely.\n const hasServerDecision = decision != null;\n const timeoutMs = config.timeoutFallbackMs;\n const waits = !hasServerDecision && timeoutMs != null && timeoutMs > 0;\n const [elapsed, setElapsed] = useState(!waits);\n useEffect(() => {\n if (!waits) {\n setElapsed(true);\n return;\n }\n const timer = setTimeout(() => setElapsed(true), timeoutMs as number);\n return () => clearTimeout(timer);\n }, [waits, timeoutMs]);\n\n const { visible, verdict } = useMemo(() => {\n // Master kill switch wins over everything, including QA replay: a tenant that turned the\n // questionnaire OFF must never see it, whatever the rules, the server decision, or testing say.\n if (!featureEnabled)\n return {\n visible: false,\n verdict: { fire: false, reason: \"feature_disabled\" } as QuestionnaireDecision,\n };\n\n // QA replay: force-show, bypassing rules + gates (safe: only via __DEV__ && bool).\n if (testing)\n return {\n visible: true,\n verdict: { fire: true, reason: \"testing\" } as QuestionnaireDecision,\n };\n\n const store = resolveStorage(storage);\n const local = evaluateGate(resolveRules(config), {\n sessions,\n events,\n lastShownAt: readInt(store, lastKey) || null,\n seen: hasSeenGate(seenKey, storage, isTesting),\n now: Date.now(),\n });\n const resolved = decideQuestionnaire(local, decision);\n // (3) the once-gate always wins locally, even over a server \"fire\".\n const alreadySeen = hasSeenGate(seenKey, storage, isTesting);\n const ready = hasServerDecision || elapsed;\n return { visible: ready && resolved.fire && !alreadySeen, verdict: resolved };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n featureEnabled,\n testing,\n config,\n decision,\n events,\n sessions,\n elapsed,\n hasServerDecision,\n seenKey,\n lastKey,\n storage,\n isTesting,\n ]);\n\n // Stable callbacks + a stable controller object, so a host can safely list any of them in its\n // own effect deps without the effect re-firing every render.\n const shownRef = useRef(false);\n const markShown = useCallback(() => {\n if (shownRef.current) return;\n shownRef.current = true;\n writeInt(resolveStorage(storage), lastKey, Date.now());\n }, [storage, lastKey]);\n const markResolved = useCallback(() => {\n markSeenGate(seenKey, storage, isTesting);\n }, [seenKey, storage, isTesting]);\n\n return useMemo<QuestionnaireGateController>(\n () => ({ visible, decision: verdict, markShown, markResolved }),\n [visible, verdict, markShown, markResolved],\n );\n};\n"]}
1
+ {"version":3,"sources":["../../src/theme/defaultTheme.ts","../../src/theme/ThemeContext.tsx","../../src/theme/typography.ts","../../src/motion/motionSpec.ts","../../src/motion/useReducedMotion.ts","../../src/components/Button.tsx","../../src/motion/centeredModalMotion.ts","../../src/components/CenteredModal.tsx","../../src/components/DoneCheck.tsx","../../src/components/CardHandoff.tsx","../../src/components/ModalPaneHost.tsx","../../src/components/StepDots.tsx","../../src/haptics/haptics.ts","../../src/reviews/feedbackForm.ts","../../src/theme/mergeThemeOver.ts","../../src/reviews/decision.ts","../../src/questionnaire/decision.ts","../../src/questionnaire/steps.ts","../../src/questionnaire/transport.ts","../../src/questionnaire/QuestionnaireGate.tsx","../../src/coachmarks/runtime.ts","../../src/features/defaults.ts","../../src/features/cache.ts","../../src/features/fetchWireFeatures.ts","../../src/features/useWireFeatures.ts","../../src/features/WireFeaturesProvider.tsx","../../src/reviews/equality.ts","../../src/reviews/runtime.ts","../../src/questionnaire/runtime.ts","../../src/questionnaire/useQuestionnaireGate.ts"],"names":["createContext","useContext","useState","useEffect","AccessibilityInfo","useRef","Animated","useCallback","jsx","Pressable","Text","React","StyleSheet","forwardRef","Easing","useImperativeHandle","BackHandler","jsxs","Modal","styles","SafeAreaView","Fragment","easeWire","View","useMemo","_a","_b","_c","TextInput","useStableValue","testing"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * defaultOnboardingTheme — a neutral, light, brand-agnostic baseline. Consumers\n * pass a `Partial<OnboardingTheme>` that is deep-merged over this (see\n * `mergeTheme`), so they only override what differs from neutral.\n */\nimport type { OnboardingTheme } from \"./types\";\n\nexport const defaultOnboardingTheme: OnboardingTheme = {\n colors: {\n background: \"#FFFFFF\",\n surface: \"#F7F7F8\",\n text: \"#101114\",\n textMuted: \"#6B7280\",\n primary: \"#111111\",\n onPrimary: \"#FFFFFF\",\n primarySoft: \"rgba(17,17,17,0.06)\",\n border: \"#E4E4E7\",\n borderStrong: \"#C7C7CC\",\n disabled: \"#EBEBEB\",\n success: \"#16A34A\",\n warning: \"#D97706\",\n error: \"#DC2626\",\n info: \"#2563EB\",\n },\n fonts: {\n regular: undefined,\n medium: undefined,\n bold: undefined,\n baseSize: 16,\n scale: 1,\n },\n radius: {\n sm: 8,\n md: 12,\n lg: 16,\n full: 9999,\n },\n spacing: {\n xs: 4,\n sm: 8,\n md: 16,\n lg: 24,\n xl: 32,\n },\n // Circled (pill) CTA by default; an app can pass `button: { radius: 12 }` for\n // a rounded rectangle, or override height/paddingX to match its design system.\n button: {\n radius: 9999,\n height: 52,\n paddingX: 24,\n },\n};\n\n/**\n * Deep-merge a partial theme over the default. Two levels deep is enough — the\n * theme is intentionally shallow (colors/fonts/radius/spacing), so we merge each\n * known sub-object and leave scalars to overwrite.\n */\nexport const mergeTheme = (\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return defaultOnboardingTheme;\n return {\n colors: { ...defaultOnboardingTheme.colors, ...override.colors },\n fonts: { ...defaultOnboardingTheme.fonts, ...override.fonts },\n radius: { ...defaultOnboardingTheme.radius, ...override.radius },\n spacing: { ...defaultOnboardingTheme.spacing, ...override.spacing },\n button: { ...defaultOnboardingTheme.button, ...override.button },\n };\n};\n","/**\n * ThemeContext — provides the resolved OnboardingTheme to every shell element and\n * themed card via `useOnboardingTheme()`. WHY a context rather than prop-drilling:\n * the cards are mounted by the SDK's ComponentRenderer (not by us), so we can't\n * pass them props directly — they must read the theme from context.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\nimport { mergeTheme } from \"./defaultTheme\";\nimport type { OnboardingTheme } from \"./types\";\n\nconst OnboardingThemeContext = createContext<OnboardingTheme | null>(null);\n\nexport type OnboardingThemeProviderProps = {\n /** Partial overrides merged over the neutral default theme. */\n theme?: Partial<OnboardingTheme>;\n children: React.ReactNode;\n};\n\nexport const OnboardingThemeProvider: React.FC<OnboardingThemeProviderProps> = ({\n theme,\n children,\n}) => {\n const resolved = useMemo(() => mergeTheme(theme), [theme]);\n return (\n <OnboardingThemeContext.Provider value={resolved}>\n {children}\n </OnboardingThemeContext.Provider>\n );\n};\n\n/**\n * Read the active theme. Falls back to the default theme when used outside a\n * provider so a stray card never crashes — it just renders neutral.\n */\nexport const useOnboardingTheme = (): OnboardingTheme => {\n const ctx = useContext(OnboardingThemeContext);\n return ctx ?? mergeTheme();\n};\n","/**\n * typography — derive concrete RN text styles from the theme's font config, so\n * every label/title/caption in the kit scales from one `baseSize` + `scale` and\n * picks the right family. Cards call these instead of hardcoding fontSize/weight.\n */\nimport type { TextStyle } from \"react-native\";\nimport type { OnboardingFonts } from \"./types\";\n\nconst round = (n: number) => Math.round(n);\n\n/** Body text — the reference size. */\nexport const bodyStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.regular,\n fontSize: round(f.baseSize * f.scale),\n lineHeight: round(f.baseSize * f.scale * 1.5),\n});\n\n/** Slightly smaller secondary/hint text. */\nexport const captionStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.regular,\n fontSize: round(f.baseSize * 0.8125 * f.scale),\n lineHeight: round(f.baseSize * 0.8125 * f.scale * 1.5),\n});\n\n/** Emphasised label (e.g. a card question). */\nexport const labelStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.medium ?? f.bold,\n fontSize: round(f.baseSize * f.scale),\n lineHeight: round(f.baseSize * f.scale * 1.4),\n fontWeight: f.medium ? undefined : (\"600\" as const),\n});\n\n/** Heading (status title, done block). */\nexport const headingStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.bold,\n fontSize: round(f.baseSize * 1.25 * f.scale),\n lineHeight: round(f.baseSize * 1.25 * f.scale * 1.3),\n fontWeight: f.bold ? undefined : (\"700\" as const),\n});\n\n/** Button label. */\nexport const buttonLabelStyle = (f: OnboardingFonts): TextStyle => ({\n fontFamily: f.bold ?? f.medium,\n fontSize: round(f.baseSize * f.scale),\n fontWeight: f.bold ? undefined : (\"600\" as const),\n});\n","/**\n * motionSpec — the single source of truth for every animation value in the kit,\n * extracted 1:1 from the Wire Activation card-interactions design canvas\n * (see design-refs/EXTRACTED-SPEC.md for the row-by-row mapping).\n *\n * Pure constants + pure helpers only — NO react-native import — so the spec is\n * unit-testable under node:test and components can't drift from the design\n * without a red test.\n */\n\n/** The design system's \"ease-wire\" curve: cubic-bezier(0.16, 1, 0.3, 1). */\nexport const WIRE_BEZIER = [0.16, 1, 0.3, 1] as const;\n\n/** Design-system duration tokens (colors_and_type.css --duration-*). */\nexport const DURATION_FAST_MS = 150;\nexport const DURATION_BASE_MS = 300;\nexport const DURATION_SLOW_MS = 500;\n\n/** Reduce-motion fallback: a short fade to the final frame, never a frozen mid-state. */\nexport const REDUCED_FADE_MS = 120;\n\n// ── Press feedback (spec rows 1, 4, 20) ─────────────────────────────────────\nexport const ROW_PRESS_SCALE = 0.975;\nexport const CHIP_PRESS_SCALE = 0.94;\nexport const BUTTON_PRESS_SCALE = 0.975;\n/** Reduce-motion press feedback: opacity dip instead of scale. */\nexport const REDUCED_PRESS_OPACITY = 0.85;\nexport const PRESS_SPRING = { friction: 8, tension: 220 } as const;\nexport const BUTTON_PRESS_SPRING = { friction: 8, tension: 240 } as const;\n\n// ── Selection state changes (spec rows 2, 3, 5, 6) ──────────────────────────\nexport const SELECT_FILL_MS = 180;\nexport const CHIP_FILL_MS = 160;\nexport const CHECK_SPRING = { friction: 6, tension: 180 } as const;\nexport const CHECK_SCALE_FROM = 0.6;\n\n// ── Card-to-card handoff (spec rows 7-10) ───────────────────────────────────\nexport const CARD_ENTER_MS = 220;\nexport const CARD_EXIT_MS = 180;\n/** The exit starts this long BEFORE the enter (enter is delayed by this). */\nexport const CARD_EXIT_LEAD_MS = 80;\nexport const CARD_SLIDE_PX = 26;\nexport const CARD_ENTER_SCALE_FROM = 0.96;\n/** The interstitial keeps the shell's springier value-beat (AnimatedCard idiom). */\nexport const CARD_SPRING = { damping: 14, stiffness: 180, mass: 1 } as const;\n/** Loader-to-card handoff: the loader just fades out. */\nexport const LOADER_HANDOFF_FADE_MS = 120;\n\n// ── InterstitialCard reveal (spec rows 11-13) ───────────────────────────────\nexport const INTERSTITIAL_HEAD_MS = 500;\nexport const INTERSTITIAL_HEAD_STAGGER_MS = 100;\nexport const INTERSTITIAL_ITEM_MS = 300;\nexport const INTERSTITIAL_ITEM_STAGGER_MS = 90;\nexport const INTERSTITIAL_ITEM_BASE_DELAY_MS = 200;\nexport const INTERSTITIAL_CHECK_DELAY_MS = 200;\nexport const INTERSTITIAL_CHECK_SCALE_FROM = 0.4;\n\n/** Delay before work item `index` begins its reveal (row lands after the head). */\nexport const interstitialItemDelay = (index: number): number =>\n INTERSTITIAL_ITEM_BASE_DELAY_MS + index * INTERSTITIAL_ITEM_STAGGER_MS;\n\n/** Delay before work item `index`'s check pops (200ms after its row starts). */\nexport const interstitialCheckDelay = (index: number): number =>\n interstitialItemDelay(index) + INTERSTITIAL_CHECK_DELAY_MS;\n\n// ── Status / completion payoff (spec rows 14-16) ────────────────────────────\nexport const STATUS_POP_SPRING = { friction: 6, tension: 200 } as const;\nexport const STATUS_POP_SCALE_FROM = 0.4;\nexport const STATUS_BURST_MS = 500;\nexport const STATUS_BURST_SCALE_FROM = 0.4;\nexport const STATUS_BURST_SCALE_TO = 1.5;\nexport const STATUS_BURST_OPACITY_FROM = 0.5;\nexport const STATUS_COPY_MS = 300;\nexport const STATUS_COPY_STAGGER_MS = 80;\n/** Copy starts settling once the badge pop is visibly underway. */\nexport const STATUS_COPY_BASE_DELAY_MS = 200;\n\n/** Delay before payoff copy line `index` fades up. */\nexport const statusCopyDelay = (index: number): number =>\n STATUS_COPY_BASE_DELAY_MS + index * STATUS_COPY_STAGGER_MS;\n\n// ── Loading treatment (spec rows 17-19) ─────────────────────────────────────\nexport const LOADER_PULSE_MS = 1600;\nexport const LOADER_PULSE_MIN_OPACITY = 0.35;\nexport const LOADER_ORBIT_MS = 2400;\n/** Skeleton lines appear only when the fetch runs past this. */\nexport const SKELETON_DELAY_MS = 300;\nexport const SKELETON_PULSE_MS = 1500;\nexport const SKELETON_MIN_OPACITY = 0.45;\n\n// ── Progress bar (spec row 21) ──────────────────────────────────────────────\nexport const PROGRESS_MS = 400;\n\n// ── Dev/QA duration scale (slow-mo for judging motion) ──────────────────────\n// A module-level multiplier applied to every timing DURATION (and stagger\n// delay) at animation start. 1 = design speed; 2 = half-speed slow-mo. Springs\n// are physics-based (friction/tension) and do NOT scale. This is a dev/QA tool\n// (the playground's tweak panel drives it) — production code never calls the\n// setter, so the default 1 keeps shipped motion exactly on spec.\n\nlet durationScale = 1;\n\n/** Set the global duration multiplier (clamped to 0.1-10; invalid resets to 1). */\nexport const setMotionDurationScale = (scale: number): void => {\n durationScale = Number.isFinite(scale) && scale > 0 ? Math.min(10, Math.max(0.1, scale)) : 1;\n};\n\nexport const getMotionDurationScale = (): number => durationScale;\n\n/** Apply the current duration scale to a spec duration/delay (rounded ms). */\nexport const scaledMs = (ms: number): number => Math.round(ms * durationScale);\n\n// ── Reduce-motion helpers (pure, shared by every animated component) ────────\n\nexport type EntranceSpec = {\n /** Duration to animate with (falls back to the short fade under reduce motion). */\n duration: number;\n /** Whether transforms (translate/scale) may move; false = opacity-only fade. */\n useTransform: boolean;\n};\n\n/** Entrances: full motion normally; a 120ms opacity-only fade under reduce motion. */\nexport const entranceSpec = (reduced: boolean, durationMs: number): EntranceSpec =>\n reduced\n ? { duration: REDUCED_FADE_MS, useTransform: false }\n : { duration: durationMs, useTransform: true };\n\n/** State changes (select fills etc.): snap instantly under reduce motion. */\nexport const stateChangeDuration = (reduced: boolean, durationMs: number): number =>\n reduced ? 0 : durationMs;\n\n/** Looping/ambient animations run only when motion is allowed. */\nexport const loopEnabled = (reduced: boolean): boolean => !reduced;\n","/**\n * useReducedMotion — the kit's ONE reduce-motion gate. Reads the OS setting via\n * AccessibilityInfo and stays subscribed to `reduceMotionChanged`, so every\n * animated component lands on its final frame (or a ~120ms fade) the moment the\n * user flips the setting — no restart needed.\n *\n * This closes the gap documented in ai_rules/rules/performance.md §3: every\n * animation in the kit must consume this hook (usually through the pure helpers\n * in motionSpec.ts: `entranceSpec` / `stateChangeDuration` / `loopEnabled`).\n */\nimport { useEffect, useState } from \"react\";\nimport { AccessibilityInfo } from \"react-native\";\n\n// Last-known value, module-level: cards remount every turn (keyed on message id),\n// and a `useState(false)` default would flash one animated frame per turn for a\n// reduce-motion user before the async read resolves.\nlet lastKnown = false;\n\nexport const useReducedMotion = (): boolean => {\n const [reduced, setReduced] = useState(lastKnown);\n\n useEffect(() => {\n let mounted = true;\n AccessibilityInfo.isReduceMotionEnabled()\n .then((value) => {\n lastKnown = value;\n if (mounted) setReduced(value);\n })\n .catch(() => {\n // Unavailable (e.g. some test envs): keep the last-known value.\n });\n const sub = AccessibilityInfo.addEventListener(\"reduceMotionChanged\", (value) => {\n lastKnown = value;\n setReduced(value);\n });\n return () => {\n mounted = false;\n sub?.remove();\n };\n }, []);\n\n return reduced;\n};\n","/**\n * Button — the kit's themed primary/outline button, replacing the SDK's hardcoded\n * `Btn`. Every color/radius/font comes from the active theme.\n *\n * Motion (design-refs/EXTRACTED-SPEC.md row 20): \"a footer button that answers\n * the tap\" — scale 1→0.975 spring on press-in, back on release, native driver.\n * Reduce motion: an opacity dip to 0.85 while pressed, no scale. Disabled keeps\n * the `disabled` token fill with no press handler (unchanged).\n */\nimport React, { useCallback, useRef } from \"react\";\nimport { Animated, Pressable, StyleSheet, Text } from \"react-native\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport { buttonLabelStyle } from \"../theme/typography\";\nimport {\n BUTTON_PRESS_SCALE,\n BUTTON_PRESS_SPRING,\n REDUCED_FADE_MS,\n REDUCED_PRESS_OPACITY,\n scaledMs,\n} from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\n\ntype Variant = \"primary\" | \"outline\";\n\ntype ButtonProps = {\n title: string;\n onPress?: () => void;\n variant?: Variant;\n disabled?: boolean;\n /** Stretch to the container width — for form-style CTAs (e.g. the review form's\n * \"Send feedback\"). Default false keeps the content-width pill used by cards. */\n fullWidth?: boolean;\n};\n\nconst _Button: React.FC<ButtonProps> = ({\n title,\n onPress,\n variant = \"primary\",\n disabled = false,\n fullWidth = false,\n}) => {\n const t = useOnboardingTheme();\n const reduced = useReducedMotion();\n const isPrimary = variant === \"primary\";\n\n // 0 = at rest, 1 = pressed. Scale normally; opacity dip under reduce motion.\n const pressT = useRef(new Animated.Value(0)).current;\n const pressTo = useCallback(\n (to: number) => {\n if (reduced) {\n Animated.timing(pressT, {\n toValue: to,\n duration: scaledMs(REDUCED_FADE_MS),\n useNativeDriver: true,\n }).start();\n return;\n }\n Animated.spring(pressT, {\n toValue: to,\n friction: BUTTON_PRESS_SPRING.friction,\n tension: BUTTON_PRESS_SPRING.tension,\n useNativeDriver: true,\n }).start();\n },\n [pressT, reduced],\n );\n const lastPress = useRef<number>(0);\n const handlePress = useCallback(() => {\n if (!onPress) return;\n const now = Date.now();\n if (now - lastPress.current < 500) return;\n lastPress.current = now;\n onPress();\n }, [onPress]);\n\n const handlePressIn = useCallback(() => pressTo(1), [pressTo]);\n const handlePressOut = useCallback(() => pressTo(0), [pressTo]);\n\n const scale = pressT.interpolate({\n inputRange: [0, 1],\n outputRange: [1, reduced ? 1 : BUTTON_PRESS_SCALE],\n });\n const opacity = pressT.interpolate({\n inputRange: [0, 1],\n outputRange: [1, reduced ? REDUCED_PRESS_OPACITY : 1],\n });\n\n return (\n <Pressable\n onPress={disabled ? undefined : handlePress}\n onPressIn={disabled ? undefined : handlePressIn}\n onPressOut={disabled ? undefined : handlePressOut}\n disabled={disabled}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled }}\n style={fullWidth ? styles.fill : undefined}\n >\n <Animated.View\n style={[\n styles.base,\n fullWidth && styles.fill,\n {\n borderRadius: t.button.radius,\n minHeight: t.button.height,\n paddingHorizontal: t.button.paddingX,\n opacity,\n transform: [{ scale }],\n },\n isPrimary\n ? { backgroundColor: disabled ? t.colors.disabled : t.colors.primary }\n : { borderWidth: 1.5, borderColor: disabled ? t.colors.border : t.colors.primary },\n ]}\n >\n <Text\n style={[\n buttonLabelStyle(t.fonts),\n {\n color: disabled\n ? t.colors.textMuted\n : isPrimary\n ? t.colors.onPrimary\n : t.colors.primary,\n },\n ]}\n >\n {title}\n </Text>\n </Animated.View>\n </Pressable>\n );\n};\n\nexport const Button = React.memo(_Button);\n\nconst styles = StyleSheet.create({\n base: { alignItems: \"center\", justifyContent: \"center\" },\n fill: { width: \"100%\" },\n});\n","/**\n * centeredModalMotion - the pure entrance spec for the content-agnostic CenteredModal shell.\n *\n * WHY split out: the shell UI (CenteredModal) is RN and cannot run under the kit's node:test\n * runner, but the entrance math is pure and worth pinning. Keep the animation spec here so both\n * the component and the tests read one source, and so any module (reviews, questionnaire) can\n * reuse the shell without depending on another feature module.\n *\n * The centered popup uses RN's built-in `Animated` (native driver), the same idiom as\n * CompletionView/CardHandoff, so the shell stays dependency-free (no reanimated).\n *\n * NOTE: `reviews/presentation.ts` re-exports these under their original names\n * (`REVIEW_MODAL_ANIM`, `entranceFrame`) for back-compat with the reviews public API.\n */\n\n/**\n * The entrance spec for the centered popup. Values chosen to match the boilerplate's\n * `animated-modal` feel (a springy zoom-in) with the kit's own native-driver idiom:\n * • backdrop fades 0 -> `backdropOpacity`\n * • card springs from `scaleFrom` -> 1 and fades 0 -> 1\n */\nexport const CENTERED_MODAL_ANIM = {\n /** Spring config for the card scale/opacity entrance (mirrors CompletionView's pop). */\n enterSpring: { friction: 7, tension: 80 },\n /** Exit timing in ms (fade + shrink back out before unmount). */\n exitMs: 160,\n /** Card scale at rest (progress 0); grows to 1 at progress 1. */\n scaleFrom: 0.9,\n /** Peak dim of the backdrop at progress 1. */\n backdropOpacity: 0.55,\n} as const;\n\n/** A single frame of the entrance, for a progress value in [0..1] (clamped). Pure, testable. */\nexport const centeredModalFrame = (\n progress: number,\n backdropMax: number = CENTERED_MODAL_ANIM.backdropOpacity,\n): { cardOpacity: number; cardScale: number; backdropOpacity: number } => {\n const p = progress < 0 ? 0 : progress > 1 ? 1 : progress;\n const { scaleFrom } = CENTERED_MODAL_ANIM;\n return {\n cardOpacity: p,\n cardScale: scaleFrom + (1 - scaleFrom) * p,\n backdropOpacity: backdropMax * p,\n };\n};\n","/**\n * CenteredModal - the content-agnostic centered-popup shell.\n *\n * Renders its children as an alert-style card in the MIDDLE of the screen, over a dimmed\n * backdrop, with a spring/fade entrance. It knows nothing about what it presents: the reviews\n * gate uses it (via the `ReviewModal` back-compat re-export) and the questionnaire module reuses\n * the same shell, neither depends on the other.\n *\n * Adapted from the mobile-launcher boilerplate's `animated-modal` (transparent RN Modal +\n * centered container + backdrop-tap dismiss + content stop-propagation + springy zoom-in), but\n * reimplemented on RN's built-in `Animated` (native driver) so the shell stays dependency-free:\n * the boilerplate uses react-native-reanimated, which the kit does not.\n *\n * Dismissal (backdrop tap / Android back / the imperative `close()` handle) animates the card\n * out, then fires `onDismiss`. It never auto-closes on resolve: the host keeps the card showing\n * whatever payoff it wants (a thank-you, a summary) until the user taps the backdrop to close,\n * exactly like CompletionView.\n */\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { Animated, BackHandler, Easing, Modal, Pressable, StyleSheet } from \"react-native\";\nimport { SafeAreaView } from \"react-native-safe-area-context\";\n\nimport type { OnboardingTheme } from \"../theme/types\";\nimport { REDUCED_FADE_MS } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport { CENTERED_MODAL_ANIM } from \"../motion/centeredModalMotion\";\n\n/** Imperative handle so an in-card \"Not now\"/\"Skip\" link can trigger the exit animation. */\nexport type CenteredModalHandle = { close: () => void };\n\nexport type CenteredModalProps = {\n /** The (already merged) active theme - card surface/radius/spacing come from here. */\n theme: OnboardingTheme;\n /** Whether a backdrop tap / back press dismisses. Default true (never a dead end). */\n dismissible?: boolean;\n /** Fired once, AFTER the exit animation, on any dismiss. Wire to the host's resolve. */\n onDismiss: () => void;\n children: React.ReactNode;\n};\n\nconst _CenteredModal = forwardRef<CenteredModalHandle, CenteredModalProps>(\n ({ theme, dismissible = true, onDismiss, children }, ref) => {\n const progress = useRef(new Animated.Value(0)).current;\n const [open, setOpen] = useState(true);\n const closingRef = useRef(false);\n const reduced = useReducedMotion();\n\n // Entrance: spring the card in (scale + fade); the backdrop fades up in lock-step.\n // Reduce motion: a short fade to the settled card, no spring/scale.\n useEffect(() => {\n const anim = reduced\n ? Animated.timing(progress, {\n toValue: 1,\n duration: REDUCED_FADE_MS,\n useNativeDriver: true,\n })\n : Animated.spring(progress, {\n toValue: 1,\n useNativeDriver: true,\n friction: CENTERED_MODAL_ANIM.enterSpring.friction,\n tension: CENTERED_MODAL_ANIM.enterSpring.tension,\n });\n anim.start();\n return () => anim.stop();\n }, [progress, reduced]);\n\n const close = useCallback(() => {\n if (closingRef.current) return;\n closingRef.current = true;\n Animated.timing(progress, {\n toValue: 0,\n duration: reduced ? REDUCED_FADE_MS : CENTERED_MODAL_ANIM.exitMs,\n easing: Easing.in(Easing.cubic),\n useNativeDriver: true,\n }).start(() => {\n setOpen(false);\n onDismiss();\n });\n }, [progress, onDismiss, reduced]);\n\n useImperativeHandle(ref, () => ({ close }), [close]);\n\n // Android hardware back -> dismiss (when allowed). Always consume so it never pops a route.\n useEffect(() => {\n const sub = BackHandler.addEventListener(\"hardwareBackPress\", () => {\n if (dismissible) close();\n return true;\n });\n return () => sub.remove();\n }, [dismissible, close]);\n\n const onBackdrop = useCallback(() => {\n if (dismissible) close();\n }, [dismissible, close]);\n\n const backdropOpacity = progress.interpolate({\n inputRange: [0, 1],\n outputRange: [0, CENTERED_MODAL_ANIM.backdropOpacity],\n });\n // Reduce motion: the card fades in already settled (no zoom).\n const cardScale = reduced\n ? 1\n : progress.interpolate({\n inputRange: [0, 1],\n outputRange: [CENTERED_MODAL_ANIM.scaleFrom, 1],\n });\n\n return (\n <Modal\n visible={open}\n transparent\n animationType=\"none\"\n statusBarTranslucent\n onRequestClose={dismissible ? close : undefined}\n >\n {/* Dimmed backdrop (fades with the entrance). */}\n <Animated.View\n style={[styles.backdrop, { opacity: backdropOpacity }]}\n pointerEvents=\"none\"\n />\n\n {/* Full-screen tap target: a tap outside the card dismisses. */}\n <Pressable\n style={styles.fill}\n onPress={onBackdrop}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Dismiss\"\n >\n <SafeAreaView style={styles.center} pointerEvents=\"box-none\">\n {/* Inner Pressable swallows taps so the card itself never dismisses. */}\n <Pressable onPress={() => {}} style={styles.cardWrap}>\n <Animated.View\n accessibilityViewIsModal\n accessibilityRole=\"alert\"\n style={[\n styles.card,\n {\n backgroundColor: theme.colors.surface,\n borderRadius: theme.radius.lg,\n padding: theme.spacing.lg,\n gap: theme.spacing.md,\n opacity: progress,\n transform: [{ scale: cardScale }],\n },\n ]}\n >\n {children}\n </Animated.View>\n </Pressable>\n </SafeAreaView>\n </Pressable>\n </Modal>\n );\n },\n);\n\n_CenteredModal.displayName = \"CenteredModal\";\n\nexport const CenteredModal = React.memo(_CenteredModal);\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n backdrop: { position: \"absolute\", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: \"#000\" },\n center: { flex: 1, alignItems: \"center\", justifyContent: \"center\", padding: 24 },\n cardWrap: { width: \"100%\", maxWidth: 420 },\n card: {\n width: \"100%\",\n // Soft elevation so the popup reads as lifted above the app in both themes.\n shadowColor: \"#000\",\n shadowOffset: { width: 0, height: 8 },\n shadowOpacity: 0.28,\n shadowRadius: 24,\n elevation: 12,\n },\n});\n\nexport default CenteredModal;\n","/**\n * DoneCheck — the animated \"done\" payoff glyph shared by the review gate's and the\n * questionnaire's thank-you panes. One component, two call sites, one feel.\n *\n * The beat is the house success beat, lifted from StatusCard (design-refs/\n * EXTRACTED-SPEC.md rows 14/16): the glyph springs in with a slight overshoot\n * (STATUS_POP_SPRING, scale STATUS_POP_SCALE_FROM→1) while the ring settles behind it.\n * No new motion values are invented here — every number comes from motionSpec.\n *\n * It is a Text glyph in a themed circle, NOT an SVG path: `react-native-svg` is not a\n * peer of this kit, and adding a NATIVE dependency to draw a checkmark would force every\n * host into a rebuild. The five review stars are already glyphs, so this matches the\n * house idiom.\n *\n * Reduce motion: the final frame, instantly — never a frozen mid-pop.\n *\n * Accessibility: purely decorative. The thank-you copy next to it carries the meaning,\n * so the glyph is hidden from screen readers rather than announced as \"heavy check mark\".\n */\nimport React, { useEffect, useRef } from \"react\";\nimport { Animated, StyleSheet } from \"react-native\";\n\nimport { STATUS_POP_SCALE_FROM, STATUS_POP_SPRING } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport type { OnboardingTheme } from \"../theme/types\";\n\nexport type DoneCheckProps = {\n /** The (already merged) active theme — the ring reads `colors.success`. */\n theme: OnboardingTheme;\n /** Diameter of the ring. Defaults to a size that balances the modal heading. */\n size?: number;\n};\n\nconst _DoneCheck: React.FC<DoneCheckProps> = ({ theme, size = 48 }) => {\n const reduced = useReducedMotion();\n const pop = useRef(new Animated.Value(reduced ? 1 : 0)).current;\n\n useEffect(() => {\n if (reduced) {\n pop.setValue(1);\n return;\n }\n const anim = Animated.spring(pop, {\n toValue: 1,\n friction: STATUS_POP_SPRING.friction,\n tension: STATUS_POP_SPRING.tension,\n useNativeDriver: true,\n });\n anim.start();\n return () => anim.stop();\n }, [pop, reduced]);\n\n const scale = pop.interpolate({\n inputRange: [0, 1],\n outputRange: [STATUS_POP_SCALE_FROM, 1],\n });\n\n return (\n <Animated.View\n accessibilityElementsHidden\n importantForAccessibility=\"no-hide-descendants\"\n style={[\n styles.ring,\n {\n width: size,\n height: size,\n borderRadius: theme.radius.full,\n backgroundColor: theme.colors.success,\n opacity: pop,\n transform: [{ scale }],\n },\n ]}\n >\n <Animated.Text\n style={[\n styles.glyph,\n { color: theme.colors.onPrimary, fontSize: Math.round(size * 0.5), fontFamily: theme.fonts.bold },\n ]}\n >\n ✓\n </Animated.Text>\n </Animated.View>\n );\n};\n\nexport const DoneCheck = React.memo(_DoneCheck);\nDoneCheck.displayName = \"DoneCheck\";\n\nconst styles = StyleSheet.create({\n ring: { alignItems: \"center\", justifyContent: \"center\", alignSelf: \"center\" },\n glyph: { includeFontPadding: false, textAlign: \"center\" },\n});\n\nexport default DoneCheck;\n","/**\n * CardHandoff — the card-to-card transition from the Wire Activation design:\n * \"cards hand off, they don't cut\". When `transitionKey` changes, the outgoing\n * child leaves left (translateX 0→-26, fade, 180ms) in an absolute layer while\n * the incoming child arrives from the right (translateX +26→0, fade, 220ms)\n * delayed by the 80ms exit lead — one moving surface, ~300ms total.\n *\n * Variants (per child):\n * - \"slide\": questions — the directional stepper motion above.\n * - \"spring\": the InterstitialCard value beat — scale 0.96→1 spring pop\n * (the shell's springier variant, kept from AnimatedCard).\n * - \"fade\": loaders — enter/exit as a plain 120ms fade so the \"thinking\"\n * state hands off to the first card without a hard cut.\n *\n * `direction` mirrors the whole slide for BACK navigation, so a step the user\n * returns to comes back from the side it left toward. Spatial consistency: if\n * \"next\" pushes left, \"back\" must pull right, or the stack loses its geography.\n *\n * `layout` picks how the moving surface is sized. \"fill\" (default) is the\n * full-screen flow, where the pane owns the viewport. \"auto\" is for a pane\n * inside an auto-height container (the CenteredModal card): `flex: 1` there\n * resolves to a ZERO-height child under Yoga — flex-basis 0 with no free space\n * to grow into — so the in-flow layer must size to its own content instead.\n *\n * Reduce motion: every handoff becomes a 120ms crossfade, no translate/scale.\n * All values run on the native driver (transform/opacity only); in-flight\n * animations are stopped when superseded and on unmount.\n *\n * This SUPERSEDES the enter-only AnimatedCard: same keyed-remount contract from\n * OnboardingFlow (the child renderer stays keyed on the message id), plus the\n * paired exit layer the design calls for.\n */\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Animated, Easing, StyleSheet } from \"react-native\";\nimport {\n CARD_ENTER_MS,\n CARD_ENTER_SCALE_FROM,\n CARD_EXIT_LEAD_MS,\n CARD_EXIT_MS,\n CARD_SLIDE_PX,\n CARD_SPRING,\n LOADER_HANDOFF_FADE_MS,\n REDUCED_FADE_MS,\n WIRE_BEZIER,\n scaledMs,\n} from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\n\nconst easeWire = Easing.bezier(...WIRE_BEZIER);\n\nexport type CardHandoffVariant = \"slide\" | \"spring\" | \"fade\";\n\n/** Which way the stack is moving. \"backward\" mirrors the slide (see the header note). */\nexport type CardHandoffDirection = \"forward\" | \"backward\";\n\n/** How the moving surface is sized. \"auto\" = a pane in an auto-height container. */\nexport type CardHandoffLayout = \"fill\" | \"auto\";\n\nexport type CardHandoffProps = {\n /** Identity of the current child (e.g. the message id). A change runs the handoff. */\n transitionKey: string;\n /** How the CURRENT child enters (and, snapshotted, how it will later exit). */\n variant?: CardHandoffVariant;\n /** Travel direction of THIS transition. Default \"forward\". */\n direction?: CardHandoffDirection;\n /** Sizing mode. Default \"fill\" (the full-screen flow). */\n layout?: CardHandoffLayout;\n children: React.ReactNode;\n};\n\ntype Snapshot = { key: string; node: React.ReactNode; variant: CardHandoffVariant };\n\nconst _CardHandoff: React.FC<CardHandoffProps> = ({\n transitionKey,\n variant = \"slide\",\n direction = \"forward\",\n layout = \"fill\",\n children,\n}) => {\n const reduced = useReducedMotion();\n const [leaving, setLeaving] = useState<Snapshot | null>(null);\n\n const enterT = useRef(new Animated.Value(0)).current;\n const exitT = useRef(new Animated.Value(0)).current;\n // The previous render's child, snapshotted so it can play the exit layer.\n const prev = useRef<Snapshot>({ key: transitionKey, node: children, variant });\n const running = useRef<{ enter?: Animated.CompositeAnimation; exit?: Animated.CompositeAnimation }>({});\n const mounted = useRef(false);\n\n // One orchestration effect, run every render: refresh the snapshot while the key\n // is stable; on a key change, snapshot the old child into the exit layer and run\n // the paired exit+enter. (No deps array on purpose — `children` is a fresh node\n // every parent render and must keep the snapshot current.)\n useEffect(() => {\n const last = prev.current;\n prev.current = { key: transitionKey, node: children, variant };\n\n // First mount: enter only (the design's initial reveal), nothing exits.\n if (!mounted.current) {\n mounted.current = true;\n running.current.enter = startEnter(enterT, variant, reduced, 0);\n return;\n }\n if (last.key === transitionKey) return;\n\n running.current.enter?.stop();\n running.current.exit?.stop();\n setLeaving(last);\n enterT.setValue(0);\n exitT.setValue(0);\n\n const exitDuration = reduced\n ? REDUCED_FADE_MS\n : last.variant === \"fade\"\n ? LOADER_HANDOFF_FADE_MS\n : CARD_EXIT_MS;\n const exit = Animated.timing(exitT, {\n toValue: 1,\n duration: scaledMs(exitDuration),\n easing: easeWire,\n useNativeDriver: true,\n });\n running.current.exit = exit;\n exit.start();\n\n const enter = startEnter(enterT, variant, reduced, reduced ? 0 : CARD_EXIT_LEAD_MS, () =>\n setLeaving(null),\n );\n running.current.enter = enter;\n });\n\n // Stop anything in flight on unmount (leaked animations drain the JS thread).\n useEffect(\n () => () => {\n running.current.enter?.stop();\n running.current.exit?.stop();\n },\n [],\n );\n\n const enterStyle = {\n opacity: enterT,\n transform: transformFor(variant, enterT, reduced, \"enter\", direction),\n };\n\n return (\n <>\n {leaving ? (\n <Animated.View\n pointerEvents=\"none\"\n style={[\n StyleSheet.absoluteFill,\n {\n opacity: exitT.interpolate({ inputRange: [0, 1], outputRange: [1, 0] }),\n // The CURRENT direction drives BOTH layers: one transition, one geography.\n transform: transformFor(leaving.variant, exitT, reduced, \"exit\", direction),\n },\n ]}\n >\n {leaving.node}\n </Animated.View>\n ) : null}\n <Animated.View key={variant} style={[layout === \"fill\" ? styles.fill : null, enterStyle]}>\n {children}\n </Animated.View>\n </>\n );\n};\n\n/** Kick off the enter animation for a variant (spring for the value beat, timing otherwise). */\nconst startEnter = (\n value: Animated.Value,\n variant: CardHandoffVariant,\n reduced: boolean,\n delay: number,\n onDone?: () => void,\n): Animated.CompositeAnimation => {\n value.setValue(0);\n const anim =\n !reduced && variant === \"spring\"\n ? Animated.spring(value, {\n toValue: 1,\n delay: scaledMs(delay),\n damping: CARD_SPRING.damping,\n stiffness: CARD_SPRING.stiffness,\n mass: CARD_SPRING.mass,\n useNativeDriver: true,\n })\n : Animated.timing(value, {\n toValue: 1,\n delay: scaledMs(delay),\n duration: scaledMs(\n reduced\n ? REDUCED_FADE_MS\n : variant === \"fade\"\n ? LOADER_HANDOFF_FADE_MS\n : CARD_ENTER_MS,\n ),\n easing: easeWire,\n useNativeDriver: true,\n });\n anim.start(({ finished }) => {\n if (finished) onDone?.();\n });\n return anim;\n};\n\n/**\n * Transform track per variant/layer; reduce motion = opacity-only crossfade.\n *\n * `travel` mirrors the X axis: forward pushes the stack left (new arrives from the\n * right), backward pulls it right (new arrives from the left).\n */\nconst transformFor = (\n variant: CardHandoffVariant,\n t: Animated.Value,\n reduced: boolean,\n layer: \"enter\" | \"exit\",\n travel: CardHandoffDirection,\n) => {\n if (reduced || variant === \"fade\") return [];\n if (variant === \"spring\" && layer === \"enter\") {\n return [{ scale: t.interpolate({ inputRange: [0, 1], outputRange: [CARD_ENTER_SCALE_FROM, 1] }) }];\n }\n const slide = travel === \"forward\" ? CARD_SLIDE_PX : -CARD_SLIDE_PX;\n return [\n {\n translateX: t.interpolate({\n inputRange: [0, 1],\n outputRange: layer === \"enter\" ? [slide, 0] : [0, -slide],\n }),\n },\n ];\n};\n\nexport const CardHandoff = React.memo(_CardHandoff);\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n});\n","/**\n * ModalPaneHost — \"slide between panes inside a CenteredModal\", the shared primitive\n * behind BOTH the review gate's phase changes and the questionnaire's step changes.\n * One primitive, two call sites: the two gates must never drift apart on feel.\n *\n * It does NOT reimplement the slide. `CardHandoff` already owns the design's\n * \"cards hand off, they don't cut\" motion (exit left 180ms / enter right 220ms, 80ms\n * lead, reduce-motion crossfade), so this delegates to it in `layout=\"auto\"` mode and\n * adds the ONE thing a modal needs that a full-screen flow does not: a card that\n * resizes instead of snapping.\n *\n * WHY the height animation exists: the CenteredModal card is auto-height, so the moment\n * a taller/shorter pane mounts, the card would jump to its new height in a single frame\n * while the old pane is still sliding out — the exact \"jarring change\" the slide was\n * added to remove. Measuring the pane and easing the card to it keeps one continuous\n * surface.\n *\n * WHY it is the only non-native-driven value in the kit: height is a layout prop, so it\n * cannot ride the native driver. That is a deliberate, bounded exception — ONE property\n * on ONE small card, for ~220ms, while nothing is scrolling. The panes' own opacity and\n * translate (inside CardHandoff) stay on the native driver, and the two values live on\n * different views, so they never contend. Everything else in the kit stays transform/\n * opacity-only.\n *\n * Height is eased ONLY on a pane change. A multiline box growing as the user types also\n * fires onLayout, and animating that would make typing feel laggy — those resize\n * instantly. Reduce motion: the height snaps too (movement removed, crossfade kept).\n *\n * `header` is the STATIC slot: chrome that belongs to the card rather than to any one pane\n * (the questionnaire's back icon + step dots). It sits inside the measured container but\n * OUTSIDE the CardHandoff, which buys two things a caller cannot get by rendering it above\n * the host:\n * 1. It never slides, so it is never DUPLICATED mid-handoff. Anything inside CardHandoff\n * exists twice for ~300ms (the outgoing layer and the incoming one) — fine for a\n * question that is genuinely changing, wrong for chrome that is not. Two dot rows\n * cross-fading past each other is a bug, not a transition.\n * 2. Its size is part of the measured height, so dropping the header (form → thanks)\n * rides the same eased resize as the pane swap instead of snapping the card.\n */\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Animated, Easing, StyleSheet, View, type LayoutChangeEvent } from \"react-native\";\n\nimport { CARD_ENTER_MS, WIRE_BEZIER, scaledMs } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport { CardHandoff, type CardHandoffDirection } from \"./CardHandoff\";\n\nconst easeWire = Easing.bezier(...WIRE_BEZIER);\n\nexport type ModalPaneHostProps = {\n /** Identity of the pane on screen (phase name / step key). A change runs the handoff. */\n paneKey: string;\n /** Travel direction — \"backward\" mirrors the slide when the user steps back. */\n direction?: CardHandoffDirection;\n /**\n * Card-level chrome pinned above the sliding pane: measured with it, but never moved\n * and never duplicated by the handoff. Omit it (or pass null) and nothing renders —\n * dropping it between pane changes animates the card's height rather than snapping it.\n * The node owns its own bottom spacing; the host adds none (it has no theme).\n */\n header?: React.ReactNode;\n children: React.ReactNode;\n};\n\nconst _ModalPaneHost: React.FC<ModalPaneHostProps> = ({\n paneKey,\n direction = \"forward\",\n header,\n children,\n}) => {\n const reduced = useReducedMotion();\n const height = useRef(new Animated.Value(0)).current;\n /** Last height we settled on. null until the first real measurement lands. */\n const measured = useRef<number | null>(null);\n /** Drives the height style on only AFTER a real measurement, so nothing renders at 0. */\n const [sized, setSized] = useState(false);\n /** Set when the pane changed, cleared by the next measurement it causes. */\n const paneChanged = useRef(false);\n const running = useRef<Animated.CompositeAnimation | null>(null);\n\n // Runs on mount and on every pane change, always BEFORE the resulting onLayout (which\n // arrives from native after the commit) — so the next measurement knows why it fired.\n useEffect(() => {\n paneChanged.current = true;\n }, [paneKey]);\n\n useEffect(() => () => running.current?.stop(), []);\n\n const onLayout = useCallback(\n (event: LayoutChangeEvent) => {\n const next = Math.round(event.nativeEvent.layout.height);\n if (!next) return;\n const previous = measured.current;\n if (previous !== null && Math.abs(previous - next) < 1) return;\n\n const first = previous === null;\n const ease = !first && !reduced && paneChanged.current;\n paneChanged.current = false;\n measured.current = next;\n running.current?.stop();\n\n // First measurement, a reduce-motion user, or a plain content resize (typing):\n // take the new height immediately.\n if (!ease) {\n height.setValue(next);\n if (first) setSized(true);\n return;\n }\n\n const anim = Animated.timing(height, {\n toValue: next,\n duration: scaledMs(CARD_ENTER_MS),\n easing: easeWire,\n // height is layout, not transform — see the header note.\n useNativeDriver: false,\n });\n running.current = anim;\n anim.start();\n },\n [height, reduced],\n );\n\n return (\n <Animated.View style={sized ? { height, overflow: \"hidden\" } : undefined}>\n <View onLayout={onLayout} style={styles.pane}>\n {header}\n <CardHandoff transitionKey={paneKey} direction={direction} layout=\"auto\" variant=\"slide\">\n {children}\n </CardHandoff>\n </View>\n </Animated.View>\n );\n};\n\nexport const ModalPaneHost = React.memo(_ModalPaneHost);\nModalPaneHost.displayName = \"ModalPaneHost\";\n\nconst styles = StyleSheet.create({\n pane: { width: \"100%\" },\n});\n\nexport default ModalPaneHost;\n","/**\n * StepDots — the \"how many steps, and which one am I on\" row for a multi-step modal.\n *\n * It replaces the questionnaire's textual counter (\"Question 2 of 3\"). Malik's device\n * feedback 2026-07-16: \"instead of 1 out of 3 or 2-3, had points on top to explain the\n * number of steps\". A dot row says the same two things — how long this is, how far in you\n * are — without spending a line of copy next to the question the user should be reading.\n *\n * NOT the same component as `StepProgress`: that one is the ONBOARDING flow's bar, and it\n * deliberately refuses to show a count because the flow's length is model-decided and a\n * number would be a promise the model may not keep. The questionnaire is the opposite\n * case — a fixed 3-field server contract — so here the count is knowable and honest.\n *\n * Motion: a dot fills by crossfading a `colors.primary` layer over a `colors.border` base,\n * at the design system's selection-fill duration (SELECT_FILL_MS, spec rows 2/3/5/6 — the\n * same token every other \"this is now selected\" fill in the kit uses). Opacity only, on the\n * native driver: no color interpolation (that would force `useNativeDriver: false`, and the\n * kit keeps its one non-native exception in ModalPaneHost's height).\n *\n * Reduce motion: `stateChangeDuration` collapses the fill to 0ms, so the state snaps —\n * the house convention for state changes (see StepProgress).\n *\n * Accessibility: sighted users read the dots; screen readers must not be handed three\n * unlabelled circles. The ROW is one progressbar node carrying \"Step 2 of 3\" plus the\n * numeric value, and the dots themselves are hidden as decoration.\n */\nimport React, { useEffect, useRef } from \"react\";\nimport { Animated, Easing, StyleSheet, View } from \"react-native\";\n\nimport { SELECT_FILL_MS, WIRE_BEZIER, scaledMs, stateChangeDuration } from \"../motion/motionSpec\";\nimport { useReducedMotion } from \"../motion/useReducedMotion\";\nimport type { OnboardingTheme } from \"../theme/types\";\n\nconst easeWire = Easing.bezier(...WIRE_BEZIER);\n\nexport type StepDotsProps = {\n /** The (already merged) active theme — dots read `colors.border` / `colors.primary`. */\n theme: OnboardingTheme;\n /** How many steps there are (how many dots to draw). */\n count: number;\n /** 0-based index of the step on screen. */\n index: number;\n};\n\ntype DotProps = {\n theme: OnboardingTheme;\n /** True for the current step and every step behind it — the row reads as progress. */\n filled: boolean;\n size: number;\n};\n\nconst Dot: React.FC<DotProps> = ({ theme, filled, size }) => {\n const reduced = useReducedMotion();\n const fill = useRef(new Animated.Value(filled ? 1 : 0)).current;\n\n useEffect(() => {\n const anim = Animated.timing(fill, {\n toValue: filled ? 1 : 0,\n duration: scaledMs(stateChangeDuration(reduced, SELECT_FILL_MS)),\n easing: easeWire,\n useNativeDriver: true,\n });\n anim.start();\n return () => anim.stop();\n }, [fill, filled, reduced]);\n\n return (\n <View\n style={{\n width: size,\n height: size,\n borderRadius: theme.radius.full,\n backgroundColor: theme.colors.border,\n }}\n >\n <Animated.View\n style={[\n StyleSheet.absoluteFill,\n {\n borderRadius: theme.radius.full,\n backgroundColor: theme.colors.primary,\n opacity: fill,\n },\n ]}\n />\n </View>\n );\n};\n\nconst _StepDots: React.FC<StepDotsProps> = ({ theme, count, index }) => (\n <View\n style={[styles.row, { gap: theme.spacing.sm }]}\n accessibilityRole=\"progressbar\"\n accessibilityLabel={`Step ${index + 1} of ${count}`}\n accessibilityValue={{ min: 1, max: count, now: index + 1 }}\n >\n {Array.from({ length: count }, (_, i) => (\n <View key={i} accessibilityElementsHidden importantForAccessibility=\"no-hide-descendants\">\n <Dot theme={theme} filled={i <= index} size={theme.spacing.sm} />\n </View>\n ))}\n </View>\n);\n\nexport const StepDots = React.memo(_StepDots);\nStepDots.displayName = \"StepDots\";\n\nconst styles = StyleSheet.create({\n row: { flexDirection: \"row\", alignItems: \"center\", justifyContent: \"center\" },\n});\n\nexport default StepDots;\n","/**\n * haptics.ts — the physical half of the kit's feedback layer: a tap you feel.\n *\n * `expo-haptics` is an OPTIONAL peer, loaded lazily via a guarded dynamic import so the\n * core kit never depends on it — the exact contract `reviews/storeReview.ts` uses for\n * `expo-store-review`. A host that has not installed it (or a platform without a taptic\n * engine) simply feels nothing: every call resolves to `false` and NOTHING throws. A\n * missed haptic must never break a gate.\n *\n * The module is deliberately fire-and-forget. Callers `void play(...)` from a press\n * handler and never await it, so a slow/absent native module can't delay a tap.\n *\n * Tones map to intent, not to a device API:\n * • \"selection\" — a value changed (picking a star).\n * • \"light\" — a light impact (moving to the next question).\n * • \"success\" — a task completed (the submit payoff, under the done check).\n *\n * NOT gated on reduce-motion: `prefers-reduced-motion` is a VESTIBULAR accommodation about\n * on-screen movement. Haptics are a non-visual channel and are often the accessibility\n * affordance a reduce-motion user relies on, so silencing them here would be the wrong\n * trade. Hosts that want no haptics leave `expo-haptics` uninstalled.\n */\n\n/** What a haptic is for, in product terms. Mapped to the native API inside `play`. */\nexport type HapticTone = \"selection\" | \"light\" | \"success\";\n\n/**\n * Play a haptic when the optional peer is available. Resolves `true` when a haptic was\n * actually requested, `false` when the peer is absent or the native call failed. NEVER\n * throws and never rejects — the result is advisory (tests/analytics), not control flow.\n */\nexport const play = async (tone: HapticTone): Promise<boolean> => {\n try {\n const mod = await import(\"expo-haptics\");\n if (!mod) return false;\n if (tone === \"selection\") {\n await mod.selectionAsync();\n return true;\n }\n if (tone === \"light\") {\n await mod.impactAsync(mod.ImpactFeedbackStyle.Light);\n return true;\n }\n await mod.notificationAsync(mod.NotificationFeedbackType.Success);\n return true;\n } catch {\n // Peer not installed, unsupported platform, or the native call failed — stay silent.\n return false;\n }\n};\n\n/**\n * Fire-and-forget `play`. The call site reads as the intent (\"a star was tapped\"), and a\n * rejected/absent native module can never surface as an unhandled rejection.\n */\nexport const playHaptic = (tone: HapticTone): void => {\n void play(tone);\n};\n","/**\n * feedbackForm — pure sizing helpers for the 1–4★ feedback form, kept out of the\n * React component so the \"≈4 lines tall, capped at 5\" rule is verifiable in\n * isolation (the reviews module's correctness lives in these pure functions, the\n * same convention as `decision.ts` / `presentation.ts`).\n *\n * Malik's ask: the feedback field should be a multiline box \"around 3 to 5 lines\"\n * tall, not a single-line input. We size it from the theme's body line-height so\n * it scales with the app's font config.\n */\nimport type { OnboardingFonts } from \"../theme/types\";\nimport { bodyStyle } from \"../theme/typography\";\n\n/** Lines the box shows at rest, and the cap it can grow to. */\nexport const FEEDBACK_MIN_LINES = 4;\nexport const FEEDBACK_MAX_LINES = 5;\n\nexport interface FeedbackInputHeights {\n /** Resting height — the box opens at ~4 lines so it reads as \"write a few words\". */\n minHeight: number;\n /** Growth cap — it never balloons past ~5 lines; scroll takes over beyond that. */\n maxHeight: number;\n}\n\n/**\n * Derive the multiline feedback box's min/max height from the theme's body\n * line-height. `minHeight = MIN_LINES × lineHeight`, capped at\n * `MAX_LINES × lineHeight`, plus the field's vertical padding (top + bottom) so\n * the requested number of text lines is actually visible inside the padding.\n */\nexport const feedbackInputHeights = (\n fonts: OnboardingFonts,\n verticalPadding = 0,\n): FeedbackInputHeights => {\n const lineHeight = bodyStyle(fonts).lineHeight ?? Math.round(fonts.baseSize * fonts.scale * 1.5);\n const pad = verticalPadding * 2;\n return {\n minHeight: lineHeight * FEEDBACK_MIN_LINES + pad,\n maxHeight: lineHeight * FEEDBACK_MAX_LINES + pad,\n };\n};\n","/**\n * mergeThemeOver — merge a partial theme over an ARBITRARY base theme.\n *\n * Sibling of `mergeTheme` (defaultTheme.ts), which merges over the DEFAULT theme only.\n * Gates need the other shape: a `theme` prop merged over whatever the host's active\n * ThemeContext currently is. That helper was copy-pasted verbatim into ReviewGate and\n * QuestionnaireGate; it lives here once instead, so a new theme section can never be\n * added to one gate and forgotten in the other.\n *\n * Two levels deep, matching `mergeTheme`: the theme is intentionally shallow, so each\n * known sub-object is merged and scalars overwrite.\n */\nimport type { OnboardingTheme } from \"./types\";\n\nexport const mergeThemeOver = (\n base: OnboardingTheme,\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return base;\n return {\n colors: { ...base.colors, ...override.colors },\n fonts: { ...base.fonts, ...override.fonts },\n radius: { ...base.radius, ...override.radius },\n spacing: { ...base.spacing, ...override.spacing },\n button: { ...base.button, ...override.button },\n };\n};\n","/**\n * decision.ts — the pure decision logic for the review gate.\n *\n * `decideReview` is the AI seam, mirroring `selectTourSteps` exactly: ONE function that\n * turns an optional injected decision into the live verdict. No injected decision → the\n * local rules stand; a server decision present → it OVERRIDES them. Building the seam now\n * is the whole cost of being AI-ready: today the host passes local rules only; later the\n * Wire server computes `{fire, reason}` from the onboarding learnings and the host passes\n * it straight in — zero app changes.\n *\n * // v1 (local rules only)\n * const verdict = decideReview(evaluateGate(rules, signals));\n *\n * // AI on (server-provided decision wins)\n * const verdict = decideReview(evaluateGate(rules, signals), serverDecision);\n *\n * `evaluateGate`, `routeRating`, and `buildReviewSubmission` are pure so the gate logic\n * is verifiable in isolation (the kit has no test runner; correctness lives in these).\n */\nimport type {\n RatingRoute,\n ReviewDecision,\n ReviewSubmission,\n} from \"./types\";\n\n/**\n * The seam. `decision` absent → the local verdict stands; present → it overrides.\n * Same contract philosophy as `selectTourSteps(catalog, selection?)`.\n */\nexport const decideReview = (\n local: ReviewDecision,\n decision?: ReviewDecision,\n): ReviewDecision => decision ?? local;\n\n/** The signals the local rules evaluate against (read from injected sync storage + host). */\nexport interface GateSignals {\n /** Sessions observed on this device (incl. the current one). */\n sessions: number;\n /** Tracked app events observed (host-owned). */\n events: number;\n /** Epoch ms of the last time the gate was shown, or null if never. */\n lastShownAt: number | null;\n /** Whether the once-per-version gate is already satisfied. */\n seen: boolean;\n /** Current epoch ms (injected so the function stays pure). */\n now: number;\n}\n\n/** The resolved local rules (defaults applied). */\nexport interface GateRules {\n enabled: boolean;\n minSessions: number;\n minEvents: number;\n cooldownDays: number;\n oncePerVersion: boolean;\n}\n\n/** Fill a partial `ReviewConfig` with the rule defaults. */\nexport const resolveRules = (config: {\n enabled?: boolean;\n minSessions?: number;\n minEvents?: number;\n cooldownDays?: number;\n oncePerVersion?: boolean;\n}): GateRules => ({\n enabled: config.enabled ?? true,\n minSessions: config.minSessions ?? 0,\n minEvents: config.minEvents ?? 0,\n cooldownDays: config.cooldownDays ?? 0,\n oncePerVersion: config.oncePerVersion ?? true,\n});\n\nconst MS_PER_DAY = 86_400_000;\n\n/**\n * Deterministic v1 local decision. Order: disabled → once-gate → min-sessions →\n * min-events → cooldown → fire. Reasons mirror the server evaluator's vocabulary.\n */\nexport const evaluateGate = (rules: GateRules, s: GateSignals): ReviewDecision => {\n if (!rules.enabled) return { fire: false, reason: \"disabled\" };\n if (rules.oncePerVersion && s.seen) return { fire: false, reason: \"already_shown\" };\n if (s.sessions < rules.minSessions) return { fire: false, reason: \"min_sessions\" };\n if (s.events < rules.minEvents) return { fire: false, reason: \"min_events\" };\n if (rules.cooldownDays > 0 && s.lastShownAt != null) {\n const elapsedDays = (s.now - s.lastShownAt) / MS_PER_DAY;\n if (elapsedDays < rules.cooldownDays) return { fire: false, reason: \"cooldown\" };\n }\n return { fire: true, reason: \"local_rules_met\" };\n};\n\n/**\n * Route a rating. 5 stars → the native store review; 1-4 → the feedback form. The\n * sentiment question itself is neutral — this is the ONLY place 5 is treated specially,\n * never a button labeled \"rate us 5 stars\" (see the store-policy notes in the README).\n */\nexport const routeRating = (stars: number): RatingRoute =>\n stars >= 5 ? \"store\" : \"feedback\";\n\n/** Build the `POST /v1/reviews` body. Feedback text/contact belong ONLY here, never in events. */\nexport const buildReviewSubmission = (input: {\n stars: number;\n feedbackText?: string;\n suggestion?: string;\n contact?: string;\n sessionId?: string;\n source?: string;\n meta?: Record<string, unknown>;\n}): ReviewSubmission => {\n const body: ReviewSubmission = { stars: input.stars };\n const text = input.feedbackText?.trim();\n if (text) body.feedback_text = text;\n const suggestion = input.suggestion?.trim();\n if (suggestion) body.suggestion = suggestion;\n const contact = input.contact?.trim();\n if (contact) body.contact = contact;\n if (input.sessionId) body.session_id = input.sessionId;\n if (input.source) body.source = input.source;\n if (input.meta && Object.keys(input.meta).length > 0) body.meta = input.meta;\n return body;\n};\n","/**\n * decision.ts - pure decision logic for the questionnaire gate.\n *\n * `decideQuestionnaire` is the AI seam, mirroring `decideReview` exactly: ONE function\n * that turns an optional injected decision into the live verdict. No injected decision →\n * the local rules stand; a server decision present → it OVERRIDES them. The local firing\n * rules (`evaluateGate` / `resolveRules`) and their signals are the SAME generic, pure\n * helpers the review gate uses - reused here rather than duplicated, since a questionnaire\n * verdict is structurally the same `{fire, reason}` contract.\n *\n * `buildQuestionnaireSubmission` is pure too, so the \"opinion required, empties omitted\"\n * shaping of the POST body is verifiable in isolation (the kit has no runtime test runner).\n */\nimport { decideReview, evaluateGate, resolveRules } from \"../reviews/decision\";\nimport type {\n QuestionnaireAnswers,\n QuestionnaireDecision,\n QuestionnaireMeta,\n QuestionnaireSubmission,\n} from \"./types\";\n\n// Re-export the generic local-rule helpers under the questionnaire's own namespace so a\n// host wires the fallback without reaching into the reviews module.\nexport { evaluateGate, resolveRules } from \"../reviews/decision\";\nexport type { GateSignals, GateRules } from \"../reviews/decision\";\n\n/**\n * The seam. `decision` absent → the local verdict stands; present → it overrides. Same\n * contract philosophy as `decideReview(local, decision?)`.\n */\nexport const decideQuestionnaire = (\n local: QuestionnaireDecision,\n decision?: QuestionnaireDecision,\n): QuestionnaireDecision => decideReview(local, decision);\n\n/**\n * Build the `POST /v1/questionnaires/{id}/responses` body. `opinion` is always sent as a\n * string (trimmed, possibly \"\" now that its step is skippable — the live server still\n * rejects that, see steps.ts REQUIRED_STEPS); `improve`/`suggestions` are trimmed and sent\n * as `null` when empty. The\n * `meta` bucket carries the non-PII correlation fields (user_id / device_key / session_count),\n * each defaulting to null. Free text lives ONLY here, never in analytics events.\n */\nexport const buildQuestionnaireSubmission = (input: {\n answers: QuestionnaireAnswers;\n sessionId?: string | null;\n meta?: QuestionnaireMeta;\n}): QuestionnaireSubmission => {\n const opinion = input.answers.opinion.trim();\n const improve = input.answers.improve?.trim();\n const suggestions = input.answers.suggestions?.trim();\n return {\n session_id: input.sessionId ?? null,\n answers: {\n opinion,\n improve: improve ? improve : null,\n suggestions: suggestions ? suggestions : null,\n },\n meta: {\n user_id: input.meta?.user_id ?? null,\n device_key: input.meta?.device_key ?? null,\n session_count: input.meta?.session_count ?? null,\n },\n };\n};\n","/**\n * steps.ts — the pure multi-step machine behind the questionnaire popup.\n *\n * The gate asks ONE question per step. Skippability is per-step (`QuestionnaireStep.required`)\n * and, after Malik's device test 2026-07-16, it is the INVERSE of what this kit shipped for a\n * year: `opinion` (step 1) is SKIPPABLE — the old mandatory-opinion `canSend` gate is gone —\n * and `suggestions` (the LAST step) is REQUIRED, because \"i want at least something forced\".\n * The user picks WHICH thing they say; they do not get to say nothing at all.\n *\n * The step logic is the interesting part of the component, so it lives here as pure\n * functions: no React, no react-native, no JSX. The gate is then a thin renderer over this\n * state, and `steps.test.ts` can verify advance / skip / back / the required gate under\n * node:test without mounting anything.\n *\n * The wire shape is NOT this module's business: it builds `QuestionnaireAnswers`, and\n * `buildQuestionnaireSubmission` (decision.ts) still owns the POST body exactly as before.\n *\n * The step ORDER is the server contract's field order (opinion → improve → suggestions),\n * so `toAnswers` can stay a plain projection and the submission never depends on how the\n * user navigated.\n */\nimport type { QuestionnaireAnswers, QuestionnaireDefinition } from \"./types\";\n\n/** The three answer fields, which are also the three steps. */\nexport type QuestionnaireStepKey = \"opinion\" | \"improve\" | \"suggestions\";\n\n/** One question, fully resolved for rendering. */\nexport interface QuestionnaireStep {\n /** The answer field this step fills. */\n key: QuestionnaireStepKey;\n /** The question shown to the user (tenant-configurable). */\n label: string;\n /** The greyed-out example inside the input. */\n placeholder: string;\n /**\n * When true the step cannot be skipped and cannot be committed blank — the gate hides\n * Skip and disables Send until there is non-whitespace text. Only `suggestions` (the\n * last step) carries it; see `REQUIRED_STEPS`.\n */\n required: boolean;\n}\n\n/**\n * Which steps are mandatory. Malik, after testing on device 2026-07-16: \"The any\n * suggestions or feedback <the last step> is mandatory, i want at least something forced.\"\n *\n * Exactly one step is forced, and it is the LAST one, which is the only placement that\n * works: the user has already been offered two cheap ways to say something and declined\n * them, so the mandatory box lands as \"then tell us anything\" rather than as a toll gate\n * in front of a popup they never asked for. Forcing step 1 (the old behaviour) taxed the\n * arrival; forcing step 3 taxes the exit, after the cost is sunk.\n *\n * ⚠️ SERVER DEPENDENCY: this is the exact INVERSE of what the live server enforces today.\n * `POST /v1/questionnaires/{id}/responses` validates `answers.opinion` with minLength=1 and\n * 422s an empty one. Since step 1 is now skippable, a skipped step 1 produces `opinion: \"\"`\n * and the server rejects the whole body — INCLUDING the suggestions text this module just\n * forced out of the user. The transport is fire-and-forget (it never reads the response),\n * so that rejection is SILENT: the user sees the thank-you either way. This client is\n * therefore correct only once the server drops `opinion`'s minLength. Do not paper over it\n * here — no placeholder opinion, no field reordering, no client-side guard.\n */\nexport const REQUIRED_STEPS: Record<QuestionnaireStepKey, boolean> = {\n opinion: false,\n improve: false,\n suggestions: true,\n};\n\n/**\n * Fallback questions used when the tenant configures no labels.\n *\n * NOTE the copy change: the old defaults tagged `improve`/`suggestions` \"(optional)\".\n * That was already wrong once step 1 stopped being mandatory, and it is wronger now that\n * `suggestions` is the one REQUIRED step. Requiredness is carried by the CONTROLS — Skip\n * is absent and Send is disabled on a required step — not by label text, which is tenant-\n * configurable and would drift out of sync with `REQUIRED_STEPS` the moment it changed.\n */\nexport const DEFAULT_STEP_LABELS: Record<QuestionnaireStepKey, string> = {\n opinion: \"What do you think about the app?\",\n improve: \"How can we improve?\",\n suggestions: \"Any suggestions?\",\n};\n\n/** Per-field placeholders, carried over unchanged from the single-screen form. */\nexport const STEP_PLACEHOLDERS: Record<QuestionnaireStepKey, string> = {\n opinion: \"e.g. it feels fast and clear\",\n improve: \"e.g. fewer steps to start\",\n suggestions: \"e.g. a dark theme\",\n};\n\n/** Which way the last move went — drives the slide direction (spatial consistency). */\nexport type StepDirection = \"forward\" | \"backward\";\n\n/** Answers captured so far, keyed by step. A skipped step records \"\". */\nexport type StepDrafts = Partial<Record<QuestionnaireStepKey, string>>;\n\n/** The whole machine state. Immutable: every transition returns a new object. */\nexport interface QuestionnaireStepState {\n /** Index into the step list. */\n index: number;\n /** What has been typed/skipped so far. */\n drafts: StepDrafts;\n /** Direction of the last transition, for the pane slide. */\n direction: StepDirection;\n /** True once the LAST step is answered or skipped — the gate submits and thanks. */\n done: boolean;\n}\n\n/**\n * Resolve the tenant's labels into the ordered step list. All three steps always render:\n * the server contract is a fixed 3-field capture, not an arbitrary question builder.\n */\nexport const buildQuestionnaireSteps = (\n questionnaire: Pick<\n QuestionnaireDefinition,\n \"opinion_label\" | \"improve_label\" | \"suggestions_label\"\n >,\n): QuestionnaireStep[] => [\n {\n key: \"opinion\",\n label: questionnaire.opinion_label ?? DEFAULT_STEP_LABELS.opinion,\n placeholder: STEP_PLACEHOLDERS.opinion,\n required: REQUIRED_STEPS.opinion,\n },\n {\n key: \"improve\",\n label: questionnaire.improve_label ?? DEFAULT_STEP_LABELS.improve,\n placeholder: STEP_PLACEHOLDERS.improve,\n required: REQUIRED_STEPS.improve,\n },\n {\n key: \"suggestions\",\n label: questionnaire.suggestions_label ?? DEFAULT_STEP_LABELS.suggestions,\n placeholder: STEP_PLACEHOLDERS.suggestions,\n required: REQUIRED_STEPS.suggestions,\n },\n];\n\n/** The starting state: first question, nothing answered. */\nexport const initialStepState = (): QuestionnaireStepState => ({\n index: 0,\n drafts: {},\n direction: \"forward\",\n done: false,\n});\n\n/** The step currently on screen, or undefined once the list is exhausted. */\nexport const currentStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n): QuestionnaireStep | undefined => steps[state.index];\n\n/** Whether `index` is the final step (the one whose commit submits). */\nexport const isLastStep = (steps: readonly QuestionnaireStep[], index: number): boolean =>\n index >= steps.length - 1;\n\n/** Back navigation is available on every step except the first. */\nexport const canGoBack = (state: QuestionnaireStepState): boolean => state.index > 0;\n\n/**\n * Whether the step on screen may be skipped — false on a required step, which is how the\n * gate knows to render no Skip control at all rather than a Skip that silently does nothing.\n */\nexport const canSkipStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n): boolean => !(steps[state.index]?.required ?? false);\n\n/**\n * Whether `value` satisfies the step on screen — i.e. whether committing it will actually\n * move. Optional steps accept anything (including \"\"); a required step needs non-whitespace\n * text, because \" \" is not \"at least something\". The gate reads this to disable Send.\n *\n * The SAME predicate `commitStep` enforces, so a disabled Send and a refused commit can\n * never disagree about what counts as answered.\n */\nexport const canCommitStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n value: string,\n): boolean => {\n const step = steps[state.index];\n if (!step) return false;\n return !step.required || value.trim().length > 0;\n};\n\n/**\n * Record `value` for the CURRENT step WITHOUT navigating.\n *\n * This is the shared \"the text on screen is now part of the answers\" primitive: `commitStep`\n * is exactly this plus the forward move, and the gate's Back does this before `goBack`. It\n * exists because the gate's inputs are UNCONTROLLED, so the step on screen holds its text\n * only in the component's draft ref until something folds it in here — meaning EVERY way of\n * leaving a step has to stash first or the text is silently destroyed.\n */\nexport const stashDraft = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n value: string,\n): QuestionnaireStepState => {\n const step = steps[state.index];\n if (!step) return state;\n return { ...state, drafts: { ...state.drafts, [step.key]: value } };\n};\n\n/**\n * Record `value` for the CURRENT step and move on. On the last step this sets `done`\n * (the gate reads that as \"submit now\") and leaves the index parked, so `toAnswers` is\n * called with every draft present.\n *\n * A required step refuses a blank `value` and returns the state UNCHANGED. That is the\n * single enforcement point for the mandatory last step: `skipStep` is defined as committing\n * \"\", so it becomes a no-op there for free, and the gate's disabled Send is belt-and-braces\n * over a machine that already cannot be walked past.\n */\nexport const commitStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n value: string,\n): QuestionnaireStepState => {\n const step = steps[state.index];\n if (!step) return state;\n if (!canCommitStep(steps, state, value)) return state;\n const { drafts } = stashDraft(steps, state, value);\n const last = isLastStep(steps, state.index);\n return {\n index: last ? state.index : state.index + 1,\n drafts,\n direction: \"forward\",\n done: last,\n };\n};\n\n/**\n * Skip the current step. Deliberately the SAME transition as answering with nothing —\n * \"skipped\" and \"left blank\" are one concept, so there is one code path and no way for\n * the two to drift. On a REQUIRED step that identity is what makes skipping impossible:\n * committing \"\" is refused, so this returns the state unchanged.\n */\nexport const skipStep = (\n steps: readonly QuestionnaireStep[],\n state: QuestionnaireStepState,\n): QuestionnaireStepState => commitStep(steps, state, \"\");\n\n/** Go back one step, keeping every draft so the user's earlier text is still there. */\nexport const goBack = (state: QuestionnaireStepState): QuestionnaireStepState =>\n state.index <= 0 ? state : { ...state, index: state.index - 1, direction: \"backward\" };\n\n/**\n * Project the drafts onto the answers contract. Missing/skipped steps become \"\" — the\n * exact input `buildQuestionnaireSubmission` already expects, which trims and maps the\n * two optional fields to null. The wire shape is unchanged by the multi-step rework.\n *\n * `opinion` can now legitimately be \"\" (step 1 is skippable), which the live server still\n * rejects with a 422 — see the REQUIRED_STEPS note above. That is a server fix, not a\n * reason to fabricate a value here.\n */\nexport const toAnswers = (drafts: StepDrafts): QuestionnaireAnswers => ({\n opinion: drafts.opinion ?? \"\",\n improve: drafts.improve ?? \"\",\n suggestions: drafts.suggestions ?? \"\",\n});\n","/**\n * transport.ts - kit → Wire server requests for the questionnaire module, all fire-and-forget\n * (a pre-onboarding questionnaire must NEVER break the app). Mirrors `submitReview`: a thin\n * fetch wrapper, Bearer tenant key, swallow every error.\n *\n * • submitQuestionnaireResponse → POST {serverUrl}/v1/questionnaires/{id}/responses\n * • fetchQuestionnaireDecision → GET {serverUrl}/v1/questionnaires/decision (best-effort)\n *\n * The decision fetch is HARD fail-open on the \"never show\" side: an unreachable endpoint, a\n * non-2xx (incl. 404), a missing `fetch`, or bad JSON all resolve to null, so a host wiring\n * pure server-directed firing simply shows nothing - exactly the reviews decision seam.\n */\nimport type {\n QuestionnaireDecisionResponse,\n QuestionnaireSubmission,\n QuestionnaireTarget,\n} from \"./types\";\n\n/**\n * POST a questionnaire response. Fire-and-forget: a missing target, a missing id, a build\n * error, a missing `fetch`, or a network failure is swallowed and the call returns immediately.\n */\nexport const submitQuestionnaireResponse = (\n target: QuestionnaireTarget | undefined,\n id: string,\n submission: QuestionnaireSubmission,\n): void => {\n if (!target?.serverUrl || !id) return;\n try {\n const base = target.serverUrl.replace(/\\/$/, \"\");\n const url = `${base}/v1/questionnaires/${encodeURIComponent(id)}/responses`;\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;\n void fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(submission),\n }).catch(() => {\n /* best-effort, swallow */\n });\n } catch {\n /* URL/JSON/missing-fetch - swallow */\n }\n};\n\n/** Options for the best-effort decision fetch. `deviceKey` groups a device's sessions server-side. */\nexport interface FetchQuestionnaireDecisionOptions {\n /** The onboarding/session id to correlate with, when known. */\n sessionId?: string;\n /** A stable, non-PII device id - the decision endpoint reads it for min-sessions. */\n deviceKey?: string;\n}\n\n/**\n * Best-effort fetch of the server firing decision. Returns the parsed\n * `{ fire, reason, questionnaire }` on a 2xx, else null. NEVER throws - any failure resolves\n * to null (fail-safe: the host shows nothing). The kit does not call this internally; a host\n * that wants server-directed firing awaits it and passes the result to `useQuestionnaireGate`\n * (the same AI seam the reviews gate uses).\n */\nexport const fetchQuestionnaireDecision = async (\n target: QuestionnaireTarget | undefined,\n options: FetchQuestionnaireDecisionOptions = {},\n): Promise<QuestionnaireDecisionResponse | null> => {\n if (!target?.serverUrl) return null;\n try {\n const base = target.serverUrl.replace(/\\/$/, \"\");\n const params = new URLSearchParams();\n if (options.sessionId) params.set(\"session_id\", options.sessionId);\n if (options.deviceKey) params.set(\"device_key\", options.deviceKey);\n const qs = params.toString();\n const url = `${base}/v1/questionnaires/decision${qs ? `?${qs}` : \"\"}`;\n const headers: Record<string, string> = {};\n if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;\n const res = await fetch(url, { headers });\n if (!res || !res.ok) return null;\n const json = (await res.json()) as QuestionnaireDecisionResponse | null;\n // A body without a boolean `fire` is not a decision — guard it exactly as the mirror\n // `fetchReviewDecision` does. Without this, a malformed 2xx body flows straight through:\n // `{}` reads as a truthy verdict whose `fire` is undefined (silently \"never fire\", killing\n // a questionnaire the local rules would have shown), and a stringy `{fire:\"yes\"}` reads as\n // FIRE while carrying no `questionnaire`, so the host renders a gate with an undefined\n // definition. Only a genuine boolean-`fire` body is a decision; everything else → null (the\n // server has no opinion → the local rules stand).\n if (!json || typeof json.fire !== \"boolean\") return null;\n return json;\n } catch {\n /* unreachable / non-2xx / bad JSON / missing-fetch - never show */\n return null;\n }\n};\n","/**\n * QuestionnaireGate - the multi-step questionnaire popup.\n *\n * ONE question per step. Steps 1-2 are skippable; the LAST step is REQUIRED (Malik's\n * device test 2026-07-16: \"i want at least something forced\"). The user chooses which\n * thing they tell us, not whether they tell us anything. `steps.ts` owns that rule and\n * every transition as pure functions, unit-tested under node:test without mounting React;\n * this component is a thin renderer over that machine.\n *\n * The CHROME (back icon + step dots) is a static header, deliberately NOT part of the\n * sliding pane - see the four notes below. Only the question, its box and its controls move.\n *\n * - No title. The gate used to render `questionnaire.title` as a heading ON EVERY STEP,\n * directly above the step's own question. Two asking-texts stacked, one of them the same\n * string three times, and mid-slide the outgoing and incoming panes each drew their own\n * copy so it was briefly on screen TWICE. Malik saw it on the last step, where the\n * forced question most needs the focus. The question IS the heading now; it renders once.\n * - No \"Question 2 of 3\" counter. `StepDots` says it without spending a line next to the\n * question, which is what the user is supposed to be reading.\n * - Back is a top-left icon, not a link in the button stack, and it is simply absent on\n * step 1 rather than present-but-dead.\n * - No \"Not now\". Per-step Skip is the only in-card opt-out. `questionnaire_dismissed`\n * moved to the modal's dismiss path (backdrop tap / Android back) - see `handleDismissed`.\n *\n * The wire shape is UNCHANGED. `buildQuestionnaireSubmission` still builds the exact same\n * `POST /v1/questionnaires/{id}/responses` body from the same three answers; a skipped\n * step is simply an empty answer, which is what the builder already handled.\n *\n * ⚠️ This gate now REQUIRES the server to accept an empty `answers.opinion` - step 1 is\n * skippable and the live endpoint still 422s a blank opinion, silently (the transport is\n * fire-and-forget). See the REQUIRED_STEPS note in steps.ts. Server fix, not a client one.\n *\n * Motion: `ModalPaneHost` slides step→step (and mirrors the slide on Back) and resizes the\n * card; `StepDots` fills; `DoneCheck` plays the submit payoff. All shared, all reduce-motion\n * aware. Haptics are lazy + optional (`haptics/haptics.ts`) and silently absent otherwise.\n *\n * The form NEVER asks for identity (no name / email / contact field): the host already\n * identifies the user via `sessionId` + `meta` (user_id, device_key, session_count), which is\n * all the POST body carries alongside the answers. Every visual value comes from the\n * OnboardingTheme; analytics are callback-based (no PII - answers go ONLY in the POST body).\n */\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport { Pressable, StyleSheet, Text, TextInput, View } from \"react-native\";\n\nimport { Button } from \"../components/Button\";\nimport { CenteredModal, type CenteredModalHandle } from \"../components/CenteredModal\";\nimport { DoneCheck } from \"../components/DoneCheck\";\nimport { ModalPaneHost } from \"../components/ModalPaneHost\";\nimport { StepDots } from \"../components/StepDots\";\nimport { playHaptic } from \"../haptics/haptics\";\nimport { feedbackInputHeights } from \"../reviews/feedbackForm\";\nimport { mergeThemeOver } from \"../theme/mergeThemeOver\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport { bodyStyle, captionStyle, headingStyle } from \"../theme/typography\";\nimport { buildQuestionnaireSubmission } from \"./decision\";\nimport {\n buildQuestionnaireSteps,\n canGoBack,\n canSkipStep,\n commitStep,\n currentStep,\n goBack,\n initialStepState,\n isLastStep,\n skipStep,\n stashDraft,\n toAnswers,\n type QuestionnaireStepState,\n type StepDrafts,\n} from \"./steps\";\nimport { submitQuestionnaireResponse } from \"./transport\";\nimport type { QuestionnaireGateProps } from \"./types\";\n\ntype Phase = \"form\" | \"thanks\";\n\nconst _QuestionnaireGate: React.FC<QuestionnaireGateProps> = ({\n questionnaire,\n target,\n sessionId,\n meta,\n onEvent,\n onResolved,\n onShown,\n theme: themeOverride,\n dismissible = true,\n}) => {\n const active = useOnboardingTheme();\n const t = useMemo(() => mergeThemeOver(active, themeOverride), [active, themeOverride]);\n const modalRef = useRef<CenteredModalHandle>(null);\n\n const id = questionnaire.id;\n const steps = useMemo(\n () =>\n buildQuestionnaireSteps({\n opinion_label: questionnaire.opinion_label,\n improve_label: questionnaire.improve_label,\n suggestions_label: questionnaire.suggestions_label,\n }),\n [questionnaire.opinion_label, questionnaire.improve_label, questionnaire.suggestions_label],\n );\n\n const [phase, setPhase] = useState<Phase>(\"form\");\n const [state, setState] = useState<QuestionnaireStepState>(initialStepState);\n // Mirrored so the press handlers read the live state without re-subscribing every render\n // (the same ref-over-callback idiom the fire-once effect below uses).\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // The text for the step ON SCREEN. Deliberately a ref, not state: the inputs stay\n // UNCONTROLLED (`defaultValue`), so a keystroke never round-trips through React and the\n // box never lags or flickers on a low-end device. Each step's input is keyed, so it\n // remounts per step and `defaultValue` restores the earlier answer when the user steps Back.\n const draftRef = useRef(\"\");\n\n // ...but the REQUIRED last step does gate Send on the text, and a ref cannot re-render the\n // button. So we mirror ONE bit - \"is there non-whitespace text?\" - into state, and set it\n // only when that bit FLIPS. Typing a 200-character answer costs exactly one re-render (on\n // the first character), not 200: the middle ground between an uncontrolled box and a\n // control that has to know about its content.\n const [answered, setAnswered] = useState(false);\n const answeredRef = useRef(false);\n\n /** Point the draft at `value` and resync the flag. Used on every step transition. */\n const seedDraft = useCallback((value: string) => {\n draftRef.current = value;\n const has = value.trim().length > 0;\n answeredRef.current = has;\n setAnswered(has);\n }, []);\n\n /** Typing: always record, re-render only on the empty↔filled flip. */\n const handleChangeText = useCallback((text: string) => {\n draftRef.current = text;\n const has = text.trim().length > 0;\n if (has === answeredRef.current) return;\n answeredRef.current = has;\n setAnswered(has);\n }, []);\n\n // Fire questionnaire_prompt_shown exactly ONCE per mount. The callbacks are read through refs\n // (not effect deps) so an inline `onShown`/`onEvent` - recreated every render, as real hosts\n // idiomatically pass - never re-runs the effect. Empty deps + the shownRef guard make this a\n // true fire-once, immune to prop-identity churn.\n const shownRef = useRef(false);\n const onShownRef = useRef(onShown);\n const onEventRef = useRef(onEvent);\n onShownRef.current = onShown;\n onEventRef.current = onEvent;\n React.useEffect(() => {\n if (shownRef.current) return;\n shownRef.current = true;\n onShownRef.current?.();\n onEventRef.current?.({ name: \"questionnaire_prompt_shown\", id });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const resolveTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n React.useEffect(() => {\n return () => {\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n };\n }, []);\n\n // Set the instant we POST, so the dismiss path below can tell \"the user walked away\"\n // from \"the modal closed because the run finished\".\n const submittedRef = useRef(false);\n\n /**\n * The modal finished its exit animation. This is now the ONLY source of\n * `questionnaire_dismissed`.\n *\n * WHY it moved: the event used to fire from the in-card \"Not now\" link, which Malik cut.\n * Deleting the link without moving the event would have quietly zeroed a metric the\n * server counts. Dismissal is still very much reachable - `CenteredModal` dismisses on a\n * backdrop tap and on Android hardware back whenever `dismissible` - so the event belongs\n * on that path, not on one button that happened to trigger it.\n *\n * It also FIXES a hole: backdrop-tap and hardware-back dismissals never fired the event\n * before, so \"dismissed\" only ever counted the users who found the link. Every real\n * dismissal counts now, which means the number will legitimately RISE - it is a fuller\n * count, not a regression.\n *\n * The submit path closes the modal too (after the thank-you), hence the guard: finishing\n * is not dismissing. Read through `onEventRef` for the same prop-identity reason as the\n * fire-once effect above.\n */\n const handleDismissed = useCallback(() => {\n if (!submittedRef.current) {\n onEventRef.current?.({ name: \"questionnaire_dismissed\", id });\n }\n onResolved?.();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id, onResolved]);\n\n // The run is over: POST the answers and play the payoff. Identity is NEVER collected here -\n // the host already sends user_id / device_key / session via `sessionId` + `meta`.\n const finish = useCallback(\n (drafts: StepDrafts) => {\n const submission = buildQuestionnaireSubmission({\n answers: toAnswers(drafts),\n sessionId,\n meta,\n });\n submitQuestionnaireResponse(target, id, submission);\n submittedRef.current = true;\n onEvent?.({ name: \"questionnaire_submitted\", id });\n playHaptic(\"success\");\n setPhase(\"thanks\");\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n resolveTimer.current = setTimeout(() => {\n modalRef.current?.close();\n }, 1500);\n },\n [sessionId, meta, target, id, onEvent],\n );\n\n // Apply a machine transition: either submit (last step) or seed the next step's draft.\n // A REFUSED transition (blank text on the required step) returns the same state object,\n // so bail: no haptic, no re-render, nothing to tell the user that the disabled button\n // already told them.\n const applyTransition = useCallback(\n (next: QuestionnaireStepState) => {\n if (next === stateRef.current) return;\n setState(next);\n if (next.done) {\n finish(next.drafts);\n return;\n }\n seedDraft(next.drafts[steps[next.index]?.key ?? \"opinion\"] ?? \"\");\n playHaptic(\"light\");\n },\n [finish, seedDraft, steps],\n );\n\n const handleNext = useCallback(() => {\n applyTransition(commitStep(steps, stateRef.current, draftRef.current));\n }, [applyTransition, steps]);\n\n const handleSkip = useCallback(() => {\n applyTransition(skipStep(steps, stateRef.current));\n }, [applyTransition, steps]);\n\n const handleBack = useCallback(() => {\n // Stash the CURRENT step's text before leaving it. The inputs are uncontrolled, so that\n // text lives ONLY in draftRef until something folds it into the drafts; Back without this\n // destroyed it, and the keyed input silently remounted blank when the user stepped\n // forward again. Same primitive `commitStep` uses for Next — one way to record an answer.\n const next = goBack(stashDraft(steps, stateRef.current, draftRef.current));\n setState(next);\n seedDraft(next.drafts[steps[next.index]?.key ?? \"opinion\"] ?? \"\");\n playHaptic(\"light\");\n }, [seedDraft, steps]);\n\n const step = currentStep(steps, state);\n const last = isLastStep(steps, state.index);\n // The mandatory last step: no Skip control at all, and Send stays disabled until there is\n // text. `answered` tracks the live box; `canSkipStep` is the machine's own read of the\n // same `required` flag it enforces in `commitStep`, so the two can never disagree.\n const canSkip = canSkipStep(steps, state);\n const sendDisabled = (step?.required ?? false) && !answered;\n\n // A multiline box ~4 lines tall (capped at ~5), derived from the theme's body line-height so\n // it scales with the app's font config; padding is folded in so the lines are visible. Every\n // step uses the SAME box, which also keeps the card's height near-steady between steps.\n const answerBox = feedbackInputHeights(t.fonts, t.spacing.md);\n\n const linkStyle = [captionStyle(t.fonts), styles.link, { color: t.colors.textMuted }];\n\n /**\n * The card's chrome: back icon hard left, dots centred. Handed to `ModalPaneHost`'s\n * static slot, so it is measured with the pane but never slides and never doubles\n * mid-handoff. The two side spacers are equal-flex so the dots sit at the true centre\n * whether or not Back is there — the row must not shift between step 1 and step 2.\n */\n const header =\n phase === \"form\" ? (\n <View style={[styles.header, { marginBottom: t.spacing.md }]}>\n <View style={styles.headerSide}>\n {/* Absent on step 1 rather than disabled: there is nothing to go back to, and a\n greyed-out control is just a question the user has to answer. */}\n {canGoBack(state) && (\n <Pressable\n onPress={handleBack}\n hitSlop={12}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Back to the previous question\"\n >\n {/* A Text glyph, not an icon component: `react-native-svg` is not a peer of\n this kit and no vector library is worth forcing every host into a native\n rebuild for one chevron. Same call DoneCheck's ✓ and the review stars made. */}\n <Text style={[headingStyle(t.fonts), styles.backGlyph, { color: t.colors.textMuted }]}>\n ‹\n </Text>\n </Pressable>\n )}\n </View>\n <StepDots theme={t} count={steps.length} index={state.index} />\n <View style={styles.headerSide} />\n </View>\n ) : null;\n\n const formPane = step ? (\n <View style={{ gap: t.spacing.md }}>\n {/* The question is the heading. There is no separate title above it — see the file\n header: that was the text Malik saw repeated. */}\n <Text style={[headingStyle(t.fonts), { color: t.colors.text }]}>{step.label}</Text>\n <TextInput\n // Keyed per step so each question gets a fresh input seeded with its own answer.\n key={step.key}\n defaultValue={state.drafts[step.key] ?? \"\"}\n onChangeText={handleChangeText}\n placeholder={step.placeholder}\n placeholderTextColor={t.colors.textMuted}\n accessibilityLabel={step.label}\n multiline\n textAlignVertical=\"top\"\n style={[\n bodyStyle(t.fonts),\n styles.input,\n {\n color: t.colors.text,\n backgroundColor: t.colors.background,\n borderRadius: t.radius.md,\n borderColor: t.colors.border,\n padding: t.spacing.md,\n minHeight: answerBox.minHeight,\n maxHeight: answerBox.maxHeight,\n },\n ]}\n />\n\n {/* Gated ONLY on the required step. Steps 1-2 send/advance whatever the box holds,\n because skipping is a first-class answer there and there is nothing to gate on. */}\n <Button\n title={last ? \"Send\" : \"Next\"}\n onPress={handleNext}\n variant=\"primary\"\n fullWidth\n disabled={sendDisabled}\n />\n\n {/* Skip step — the only in-card opt-out, and gone entirely on the required step\n rather than rendered as a control that would refuse to do anything. */}\n {canSkip && (\n <Pressable\n onPress={handleSkip}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Skip this question\"\n >\n <Text style={linkStyle}>Skip step</Text>\n </Pressable>\n )}\n </View>\n ) : null;\n\n const thanksPane = (\n <View style={{ gap: t.spacing.md }}>\n <DoneCheck theme={t} />\n <Text style={[headingStyle(t.fonts), styles.centerText, { color: t.colors.text }]}>\n Thank you\n </Text>\n <Text style={[bodyStyle(t.fonts), styles.centerText, { color: t.colors.textMuted }]}>\n This helps us make it better.\n </Text>\n </View>\n );\n\n return (\n <CenteredModal ref={modalRef} theme={t} dismissible={dismissible} onDismiss={handleDismissed}>\n <ModalPaneHost\n paneKey={phase === \"thanks\" ? \"thanks\" : (step?.key ?? \"done\")}\n direction={state.direction}\n header={header}\n >\n {phase === \"thanks\" ? thanksPane : formPane}\n </ModalPaneHost>\n </CenteredModal>\n );\n};\n\nexport const QuestionnaireGate = React.memo(_QuestionnaireGate);\nQuestionnaireGate.displayName = \"QuestionnaireGate\";\n\nconst styles = StyleSheet.create({\n input: { borderWidth: 1 },\n link: { textAlign: \"center\", textDecorationLine: \"underline\" },\n centerText: { textAlign: \"center\" },\n header: { flexDirection: \"row\", alignItems: \"center\" },\n // Equal flex on both sides keeps the dots optically centred whether Back is drawn or not.\n // `flex-start` matters: without it the back Pressable stretches across the whole left\n // third of the card, so a tap anywhere near the dots would navigate back.\n headerSide: { flex: 1, alignItems: \"flex-start\" },\n backGlyph: { includeFontPadding: false },\n});\n\nexport default QuestionnaireGate;\n","/**\n * Module-level runtime for the coachmark engine: the injected sync storage, the\n * global `isTestingCoachmark` flag, and the seen-gate helpers built on top.\n *\n * WHY module singletons (not just context): the tour hooks and the anchor\n * registry are driven imperatively from anywhere in the tree (a screen deep\n * under the navigator), while the storage + testing flag are configured once at\n * the root by `CoachmarkProvider`. Singletons let a hook read the gate without\n * every call site threading the storage through props. The provider is still the\n * single writer — it calls `setCoachmarkStorage` / `setCoachmarkTesting` on mount.\n */\nimport type { CoachmarkStorage } from \"./types\";\n\nlet storageSingleton: CoachmarkStorage | null = null;\nlet testing = false;\n// The coachmarks feature kill switch (from GET /v1/features). Default true = fail-open: with no\n// flags fetched, coachmarks behave exactly as before. CoachmarkProvider writes it from the\n// resolved flags. Disabled → the tour never ARMS and the overlay `show()` is a no-op, so nothing\n// paints and — critically — no once-gate is written, so re-enabling replays the tour correctly.\nlet coachmarksEnabled = true;\n\n/**\n * Set the coachmarks master switch (from the resolved feature flags). Default true (fail-open).\n * Written by CoachmarkProvider; read imperatively by the tour arm + the overlay store.\n */\nexport const setCoachmarksEnabled = (value: boolean): void => {\n coachmarksEnabled = value;\n};\n\n/** Whether the coachmarks module is enabled. False → tours/overlays are silently skipped. */\nexport const areCoachmarksEnabled = (): boolean => coachmarksEnabled;\n\n/** Set (or clear) the injected sync gate storage. Called by CoachmarkProvider. */\nexport const setCoachmarkStorage = (storage: CoachmarkStorage | null): void => {\n storageSingleton = storage;\n};\n\n/** The currently-injected gate storage, or null if no provider is mounted. */\nexport const getCoachmarkStorage = (): CoachmarkStorage | null => storageSingleton;\n\n/**\n * Toggle the global QA replay flag. When true, EVERY seen-gate reads as unseen\n * and every seen-write is suppressed, so every tour + showcase replays on each\n * mount. The app flips ONE boolean to QA the whole coachmark surface.\n */\nexport const setCoachmarkTesting = (value: boolean): void => {\n testing = value;\n};\n\n/** Whether replay-everything QA mode is on. */\nexport const isCoachmarkTesting = (): boolean => testing;\n\n/** Gate key for a tour: `wire_coachmark_<tourId>_seen`. */\nexport const coachmarkGateKey = (tourId: string): string =>\n `wire_coachmark_${tourId}_seen`;\n\n/** Gate key for a feature showcase: `wire_showcase_<id>_seen`. */\nexport const showcaseGateKey = (showcaseId: string): string =>\n `wire_showcase_${showcaseId}_seen`;\n\n/** Marker value written for a seen gate. */\nconst SEEN_VALUE = \"1\";\n\n/**\n * Read a seen gate. Testing mode ALWAYS reports unseen (so everything replays).\n * A missing storage (no provider) also reports unseen — the safe default is to\n * show the hint rather than silently swallow it. `storageOverride` /\n * `testingOverride` let a self-contained component (e.g. FeatureShowcase) pass\n * its own storage without relying on the provider singleton.\n */\nexport const hasSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): boolean => {\n if (testingOverride ?? testing) return false;\n const storage = storageOverride ?? storageSingleton;\n if (!storage) return false;\n try {\n return storage.getItem(key) === SEEN_VALUE;\n } catch {\n return false;\n }\n};\n\n/**\n * Mark a gate seen. Suppressed in testing mode (so replay never persists) and a\n * no-op without storage. Best-effort — a throwing adapter never breaks the tour.\n */\nexport const markSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): void => {\n if (testingOverride ?? testing) return;\n const storage = storageOverride ?? storageSingleton;\n if (!storage) return;\n try {\n storage.setItem(key, SEEN_VALUE);\n } catch {\n // Best-effort: a failed write just means the hint may show once more.\n }\n};\n","/**\n * The fail-open defaults + a tolerant parser for the server's flags payload.\n *\n * THE CONTRACT: fail-open, never fail-dark. An absent server object, a missing module key, a\n * malformed value, or an unreachable endpoint must resolve to the MOST PERMISSIVE state — every\n * module ON, onboarding `ai` — so a control-plane outage can only ever be more permissive than\n * the dashboard intends. It can never dark a tenant's activation. Matches the server's own\n * documented fail-open default (FEATURES.md: \"local defaults — every module on, onboarding ai\").\n */\nimport type { OnboardingMode, WireFeatures } from \"./types\";\n\n/**\n * ALL ON, onboarding `ai`. Frozen + module-level so its reference is stable across every call\n * (consumers that list resolved flags in an effect dep array never loop on a fresh identity).\n */\nexport const defaultWireFeatures: WireFeatures = Object.freeze({\n coachmarks: Object.freeze({ enabled: true }),\n showcase: Object.freeze({ enabled: true }),\n onboarding: Object.freeze({ mode: \"ai\" as OnboardingMode }),\n review: Object.freeze({ enabled: true }),\n questionnaire: Object.freeze({ enabled: true }),\n announcements: Object.freeze({ enabled: true }),\n}) as WireFeatures;\n\nconst VALID_MODES: readonly OnboardingMode[] = [\"ai\", \"static\", \"off\"];\n\n/** Read a `{ enabled: boolean }` module, defaulting to ON when absent/malformed (fail-open). */\nconst readEnabled = (raw: unknown): { enabled: boolean } => {\n if (raw && typeof raw === \"object\" && typeof (raw as { enabled?: unknown }).enabled === \"boolean\") {\n return { enabled: (raw as { enabled: boolean }).enabled };\n }\n return { enabled: true };\n};\n\n/**\n * Narrow the server's (untrusted) JSON to a complete `WireFeatures`. Every field is filled with\n * its fail-open default when the server omits it or sends the wrong type, so a partial or\n * malformed payload degrades PERMISSIVELY rather than throwing. A non-object input (null, array,\n * string) → the full defaults. Never throws.\n */\nexport const parseWireFeatures = (raw: unknown): WireFeatures => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return defaultWireFeatures;\n const src = raw as Record<string, unknown>;\n const modeRaw = (src.onboarding as { mode?: unknown } | undefined)?.mode;\n const mode: OnboardingMode =\n typeof modeRaw === \"string\" && VALID_MODES.includes(modeRaw as OnboardingMode)\n ? (modeRaw as OnboardingMode)\n : \"ai\";\n return {\n coachmarks: readEnabled(src.coachmarks),\n showcase: readEnabled(src.showcase),\n onboarding: { mode },\n review: readEnabled(src.review),\n questionnaire: readEnabled(src.questionnaire),\n announcements: readEnabled(src.announcements),\n };\n};\n\n/** Value-equality of two resolved flags — lets the hook hold a stable reference across churn. */\nexport const featuresEqual = (a: WireFeatures, b: WireFeatures): boolean =>\n a === b ||\n (a.coachmarks.enabled === b.coachmarks.enabled &&\n a.showcase.enabled === b.showcase.enabled &&\n a.onboarding.mode === b.onboarding.mode &&\n a.review.enabled === b.review.enabled &&\n a.questionnaire.enabled === b.questionnaire.enabled &&\n a.announcements.enabled === b.announcements.enabled);\n","/**\n * The last-known-flags cache — persisted through the host's optional `storage`.\n *\n * WHY: the fetch is best-effort and fail-open. When the control plane is unreachable we serve the\n * LAST value we saw rather than snapping to defaults, so a tenant that intentionally disabled a\n * module during an incident keeps it disabled across an outage instead of flapping back on. That\n * is \"stale-while-error\": a fresh cache (< TTL) is trusted, and on a fetch error even a STALE\n * cache is served (any age beats a guess). Every operation is best-effort — a broken/hung storage\n * degrades to defaults, never a throw and never a stuck gate (mirrors persistedSession).\n */\nimport { parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\n/**\n * TTL for a cached flags entry, aligned to the server's `Cache-Control: private, max-age=300`.\n * A cache younger than this is \"fresh\"; older is \"stale\" (still served on a fetch error).\n */\nexport const DEFAULT_FEATURES_TTL_MS = 300_000;\n\n/** Ceiling on the storage read so a hung adapter degrades to defaults, never a stuck resolve. */\nconst READ_TIMEOUT_MS = 1_500;\n\n/** Storage key for a tenant's cached flags, e.g. `wireai:features:acme`. */\nexport const featuresCacheKey = (appId?: string): string =>\n `wireai:features:${appId && appId.length > 0 ? appId : \"default\"}`;\n\n/** A cached flags entry: the resolved flags + the epoch-ms they were fetched. */\nexport interface CachedFeatures {\n features: WireFeatures;\n /** Age of the entry in ms at read time. */\n ageMs: number;\n}\n\nconst withTimeout = <T>(p: Promise<T>, ms: number): Promise<T | undefined> => {\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), ms);\n });\n return Promise.race([p, timeout]).finally(() => clearTimeout(timer));\n};\n\n/** Whether a cache entry is still within the TTL (server max-age aligned). */\nexport const isFeaturesFresh = (ageMs: number, ttlMs: number = DEFAULT_FEATURES_TTL_MS): boolean =>\n ageMs >= 0 && ageMs < ttlMs;\n\n/**\n * Read the cached flags for `key`, or `undefined` when absent/corrupt/timed-out. Returns the\n * value AND its age so a caller can apply a TTL (fresh) or ignore it (stale-while-error). Never\n * throws; never hangs past the read timeout. The stored value is re-parsed through\n * `parseWireFeatures`, so a partially-corrupt entry still degrades fail-open.\n */\nexport const readCachedFeatures = async (\n storage: WireOnboardingStorage,\n key: string,\n): Promise<CachedFeatures | undefined> => {\n let raw: string | null | undefined;\n try {\n raw = await withTimeout(storage.getItem(key), READ_TIMEOUT_MS);\n } catch {\n return undefined;\n }\n if (!raw) return undefined;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && typeof (parsed as { ts?: unknown }).ts === \"number\") {\n const ts = (parsed as { ts: number }).ts;\n return {\n features: parseWireFeatures((parsed as { features?: unknown }).features),\n ageMs: Date.now() - ts,\n };\n }\n } catch {\n // Corrupt entry → treat as absent; the caller falls back to defaults / a fresh fetch.\n }\n return undefined;\n};\n\n/** Persist `{ features, ts }` under `key` — fire-and-forget, all errors swallowed. */\nexport const writeCachedFeatures = (\n storage: WireOnboardingStorage,\n key: string,\n features: WireFeatures,\n): void => {\n try {\n void storage\n .setItem(key, JSON.stringify({ features, ts: Date.now() }))\n .catch(() => {});\n } catch {\n // Best-effort: a failed write just means the next launch has no cache to fall back to.\n }\n};\n","/**\n * fetchWireFeatures — read the per-module kill switches from `GET {serverUrl}/v1/features`.\n *\n * Contract (server: chohra-med/wireai-onboarding-server, routers/onboarding.py):\n * GET {serverUrl}/v1/features\n * Authorization: Bearer {apiKey}\n * 200 → { coachmarks:{enabled}, showcase:{enabled}, onboarding:{mode}, review:{enabled},\n * announcements:{enabled} } (Cache-Control: private, max-age=300)\n *\n * THE CONTRACT — fail-open, never fail-dark. Unreachable, timed-out, unauthorized (401),\n * server-error (5xx), or malformed JSON all resolve to the LAST CACHED value, else the\n * all-on defaults. No throw ever reaches the host: this is timeout-capped and swallows every\n * error, exactly like the session's best-effort reads. A control-plane outage can only ever be\n * MORE permissive than the dashboard intends — it can never dark a tenant's activation.\n */\nimport { readCachedFeatures, featuresCacheKey, writeCachedFeatures } from \"./cache\";\nimport { defaultWireFeatures, parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\nconst DEFAULT_TIMEOUT_MS = 4_000;\n\n/** The fail-open fallback: last cached value (any age — stale-while-error), else defaults. */\nconst failOpen = async (\n storage: WireOnboardingStorage | undefined,\n key: string,\n): Promise<WireFeatures> => {\n if (!storage) return defaultWireFeatures;\n const cached = await readCachedFeatures(storage, key);\n return cached?.features ?? defaultWireFeatures;\n};\n\n/** GET with a hard timeout via AbortController (falls back to no-abort where unsupported). */\nconst fetchWithTimeout = async (\n url: string,\n apiKey: string,\n timeoutMs: number,\n): Promise<Response> => {\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : undefined;\n const timer = setTimeout(() => controller?.abort(), timeoutMs);\n try {\n return await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\", Authorization: `Bearer ${apiKey}` },\n signal: controller?.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n};\n\n/**\n * Resolve the tenant's feature flags. Attempts the network once; on ANY failure returns the\n * cached value (any age), else the all-on defaults. On success, persists the fresh value to the\n * cache (fire-and-forget) and returns it. Never throws.\n *\n * const flags = await fetchWireFeatures({ serverUrl, apiKey, appId, storage });\n * if (!flags.coachmarks.enabled) { /* skip the tour * / }\n */\nexport const fetchWireFeatures = async (\n config?: WireFeaturesConfig,\n): Promise<WireFeatures> => {\n const key = featuresCacheKey(config?.appId);\n const storage = config?.storage;\n\n // Nothing to fetch (no creds) → cache, else defaults. Lets a host mount the provider before\n // its config is ready without ever darking.\n if (!config?.serverUrl || !config?.apiKey) return failOpen(storage, key);\n\n const url = `${config.serverUrl.replace(/\\/$/, \"\")}/v1/features`;\n const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;\n\n try {\n const res = await fetchWithTimeout(url, config.apiKey, timeoutMs);\n // 401 (bad/rotated key), 5xx, any non-2xx → last-known, never dark.\n if (!res || !res.ok) return failOpen(storage, key);\n const json: unknown = await res.json(); // throws on malformed body → caught below\n const features = parseWireFeatures(json);\n if (storage) writeCachedFeatures(storage, key, features);\n return features;\n } catch {\n // Timeout/abort, network error, missing fetch, or malformed JSON — all fail open.\n return failOpen(storage, key);\n }\n};\n","/**\n * useWireFeatures — resolve the tenant's feature flags for a component tree, once per mount.\n *\n * Returns the all-on defaults immediately (fail-open), then swaps to the fetched value when the\n * network resolves. When no `serverUrl`+`apiKey` is supplied it never fetches and just returns\n * defaults, so a host that never adopts flags sees ZERO behavior change and ZERO network calls.\n *\n * frequent_rules #11 (unstable inline props): the config is idiomatically passed inline\n * (`config={{ serverUrl, apiKey }}`), a fresh identity every render. We stabilize the fetch key\n * by VALUE so the effect fires once per real credential change, and we only swap the returned\n * flags object when its VALUES change — so a host that lists the returned flags in an effect dep\n * array settles in a bounded number of commits instead of looping (enforced by the canary suite).\n */\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { defaultWireFeatures, featuresEqual } from \"./defaults\";\nimport { fetchWireFeatures } from \"./fetchWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\n/** Hold a stable reference for a value while its CONTENT is unchanged (see reviews/equality.ts). */\nconst useStableValue = <T,>(value: T, isEqual: (a: T, b: T) => boolean): T => {\n const ref = useRef(value);\n if (!isEqual(ref.current, value)) ref.current = value;\n return ref.current;\n};\n\n/** The credential slice that actually drives a refetch — stabilized by value. */\nconst sameFetchKey = (a: WireFeaturesConfig | undefined, b: WireFeaturesConfig | undefined): boolean =>\n a?.serverUrl === b?.serverUrl && a?.apiKey === b?.apiKey && a?.appId === b?.appId;\n\nexport const useWireFeatures = (config?: WireFeaturesConfig): WireFeatures => {\n const stableConfig = useStableValue(config, sameFetchKey);\n const [flags, setFlags] = useState<WireFeatures>(defaultWireFeatures);\n\n const canFetch = !!stableConfig?.serverUrl && !!stableConfig?.apiKey;\n\n useEffect(() => {\n if (!canFetch) {\n // No creds → stay on the all-on defaults (and reset if creds were removed).\n setFlags((prev) => (featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures));\n return;\n }\n let alive = true;\n // fetchWireFeatures never throws — the .then always runs with a fail-open value.\n void fetchWireFeatures(stableConfig).then((next) => {\n if (!alive) return;\n // Only adopt a NEW reference on a real value change, so a host effect keyed on the\n // returned flags doesn't loop (frequent_rules #11).\n setFlags((prev) => (featuresEqual(prev, next) ? prev : next));\n });\n return () => {\n alive = false;\n };\n }, [canFetch, stableConfig]);\n\n return flags;\n};\n","/**\n * WireFeaturesProvider + useResolvedFeatures — the OPTIONAL one-fetch-serves-all-modules layer.\n *\n * Mount `WireFeaturesProvider` once near your app root with the tenant `config` and it fetches the\n * flags ONCE; every gated surface below it (coachmarks / showcase / reviews) reads the same\n * resolved value from context instead of each fetching its own. It is entirely optional: with no\n * provider, every surface falls back to its own lazy fetch (when given a config) or to the all-on\n * defaults, so modules work with zero setup and a host that never adopts flags is unchanged.\n *\n * NOTE on the built npm subpaths: React context is shared across the kit's subpath entries in the\n * SOURCE-consumption path (the monorepo apps) and in this test suite — one module instance, one\n * context. If you consume the built `@wireai/activation/*` subpaths as separate bundles, pass the\n * resolved flags (or a `featuresConfig`) to each surface explicitly instead of relying on context.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\n\nimport { defaultWireFeatures } from \"./defaults\";\nimport { useWireFeatures } from \"./useWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\nconst CONTEXT_SYMBOL = Symbol.for(\"wireai.features.context\");\nconst globalObj = global as any;\n\nif (!globalObj[CONTEXT_SYMBOL]) {\n globalObj[CONTEXT_SYMBOL] = createContext<WireFeatures | null>(null);\n}\nconst WireFeaturesContext = globalObj[CONTEXT_SYMBOL];\n\nexport interface WireFeaturesProviderProps {\n /** Tenant creds (+ optional storage) to fetch the flags once for the whole tree. */\n config?: WireFeaturesConfig;\n /**\n * Pre-resolved flags to provide directly instead of fetching (e.g. you already have them, or\n * you drive them from your own remote-config). Takes precedence over `config`.\n */\n flags?: WireFeatures;\n children: React.ReactNode;\n}\n\n/**\n * Fetch (or accept) the flags once and broadcast them to descendants. The provider VALUE is\n * memoized (performance rule #6) so a fresh object each render doesn't re-render every consumer.\n */\nexport const WireFeaturesProvider: React.FC<WireFeaturesProviderProps> = ({\n config,\n flags,\n children,\n}) => {\n // Always call the hook (rules of hooks); when `flags` is supplied we pass no config so it\n // never fetches and the explicit flags win below.\n const fetched = useWireFeatures(flags ? undefined : config);\n const value = flags ?? fetched;\n const stable = useMemo(() => value, [value]);\n return <WireFeaturesContext.Provider value={stable}>{children}</WireFeaturesContext.Provider>;\n};\n\nWireFeaturesProvider.displayName = \"WireFeaturesProvider\";\n\n/** Raw context read — `null` when no `WireFeaturesProvider` is mounted above. */\nexport const useWireFeaturesContext = (): WireFeatures | null =>\n useContext(WireFeaturesContext);\n\n/** Options for `useResolvedFeatures`: an explicit override and/or a lazy-fetch config. */\nexport interface ResolveFeaturesOptions {\n /** Explicit flags — win over everything (a surface's own `features` prop). */\n flags?: WireFeatures;\n /** Lazy-fetch config, used ONLY when there is no explicit `flags` and no provider above. */\n config?: WireFeaturesConfig;\n}\n\n/**\n * The resolution every gated surface uses. Precedence:\n * 1. explicit `options.flags` (a surface's own prop) →\n * 2. the nearest `WireFeaturesProvider` (context) →\n * 3. a lazy fetch from `options.config` (serverUrl + apiKey) →\n * 4. the all-on defaults.\n * Always fail-open, always a stable reference for a given value (so it's safe in effect deps).\n */\nexport const useResolvedFeatures = (options?: ResolveFeaturesOptions): WireFeatures => {\n const ctx = useWireFeaturesContext();\n // Only lazily fetch when nothing else provides the flags — otherwise pass no config so the\n // hook stays inert (defaults, no network). The hook is always called (rules of hooks).\n const shouldFetch = !options?.flags && ctx == null;\n const fetched = useWireFeatures(shouldFetch ? options?.config : undefined);\n return options?.flags ?? ctx ?? fetched ?? defaultWireFeatures;\n};\n","/**\n * equality.ts — tiny, dependency-free value-equality helpers used to STABILIZE\n * references across renders.\n *\n * WHY this exists: real integrators pass inline objects — `config={{ id: 'x' }}`,\n * `decision={{ fire: true }}` — whose IDENTITY changes every render even though\n * their VALUES do not. If the review hook let those unstable references flow into\n * a `useMemo`/`useEffect` dependency list (or handed a fresh verdict object back\n * every render), a host that depends on the returned value would re-run its own\n * effect forever → \"Maximum update depth exceeded\". A library must tolerate inline\n * props without looping; these helpers are how the hook holds a stable reference\n * whenever the underlying values are unchanged.\n *\n * Pure (no React import) so it runs under the kit's node:test runner.\n */\nimport type { ReviewDecision } from \"./types\";\n\n/**\n * One-level value-equality of two plain objects (or primitives). Same-reference is\n * equal; two objects are equal when they have the same keys and each value is\n * `Object.is`-equal. Good enough for the flat `config` / `decision` shapes the gate\n * accepts (all leaf values are primitives).\n */\nexport const shallowEqual = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true;\n if (\n a == null ||\n b == null ||\n typeof a !== \"object\" ||\n typeof b !== \"object\"\n ) {\n return false;\n }\n const ak = Object.keys(a as Record<string, unknown>);\n const bk = Object.keys(b as Record<string, unknown>);\n if (ak.length !== bk.length) return false;\n for (const k of ak) {\n if (!Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k])) {\n return false;\n }\n }\n return true;\n};\n\n/**\n * Structural equality of two review verdicts by their contract fields (`fire`,\n * `reason`). A `null`/`undefined` verdict equals only another absent one. Used to\n * decide whether the hook can keep returning the SAME verdict object (so a host\n * that lists `controller.decision` in an effect dep array never loops).\n */\nexport const sameDecision = (a?: ReviewDecision | null, b?: ReviewDecision | null): boolean => {\n if (a == null || b == null) return a == b;\n return a.fire === b.fire && a.reason === b.reason;\n};\n","/**\n * Runtime helpers for the review gate: the `wire_review_*` gate keys and small\n * typed storage accessors. The gate reuses the SAME injected sync storage + global\n * testing flag as the coachmark engine (see coachmarks/runtime), so a host that\n * mounted CoachmarkProvider gets review gating for free — no second storage to wire.\n */\nimport type { CoachmarkStorage } from \"../coachmarks/types\";\nimport { getCoachmarkStorage } from \"../coachmarks/runtime\";\n\n/** Once-gate key. Keyed by app version when `oncePerVersion` is on, so a new release re-enables. */\nexport const reviewSeenKey = (id: string, version?: string): string =>\n version ? `wire_review_${id}_${version}_seen` : `wire_review_${id}_seen`;\n\n/** Last-shown timestamp key (epoch ms), for the cooldown rule. */\nexport const reviewLastShownKey = (id: string): string => `wire_review_${id}_last`;\n\n/** Session-count key, incremented once per gate mount, for the min-sessions rule. */\nexport const reviewSessionsKey = (id: string): string => `wire_review_${id}_sessions`;\n\n/** Resolve the storage to use: an explicit override, else the provider-injected singleton. */\nexport const resolveStorage = (\n override?: CoachmarkStorage | null,\n): CoachmarkStorage | null => override ?? getCoachmarkStorage();\n\n/** Read an integer from sync storage (0 on a missing/unparseable/throwing read). */\nexport const readInt = (storage: CoachmarkStorage | null, key: string): number => {\n if (!storage) return 0;\n try {\n const raw = storage.getItem(key);\n const n = raw == null ? 0 : parseInt(raw, 10);\n return Number.isFinite(n) ? n : 0;\n } catch {\n return 0;\n }\n};\n\n/** Write an integer to sync storage. Best-effort — a throwing adapter never breaks the gate. */\nexport const writeInt = (storage: CoachmarkStorage | null, key: string, value: number): void => {\n if (!storage) return;\n try {\n storage.setItem(key, String(value));\n } catch {\n // Best-effort.\n }\n};\n","/**\n * Runtime helpers for the questionnaire gate: the `wire_questionnaire_*` gate keys. The\n * gate reuses the SAME injected sync storage + global testing flag as the coachmark engine\n * (via `resolveStorage`/`readInt`/`writeInt`, re-exported from the reviews runtime), so a\n * host that mounted CoachmarkProvider gets questionnaire gating for free - no second storage\n * to wire. Once-per-user is keyed on the questionnaire `id`.\n */\nexport { resolveStorage, readInt, writeInt } from \"../reviews/runtime\";\n\n/** Once-gate key. Keyed by app version when `oncePerVersion` is on, so a new release re-enables. */\nexport const questionnaireSeenKey = (id: string, version?: string): string =>\n version ? `wire_questionnaire_${id}_${version}_seen` : `wire_questionnaire_${id}_seen`;\n\n/** Last-shown timestamp key (epoch ms), for the cooldown rule. */\nexport const questionnaireLastShownKey = (id: string): string =>\n `wire_questionnaire_${id}_last`;\n\n/** Session-count key, incremented once per gate mount, for the min-sessions rule. */\nexport const questionnaireSessionsKey = (id: string): string =>\n `wire_questionnaire_${id}_sessions`;\n","/**\n * useQuestionnaireGate - owns WHEN the questionnaire gate shows.\n *\n * v1 decision = local rules from `config` (enabled / minSessions / minEvents / cooldownDays\n * / oncePerVersion), evaluated against the same injected sync storage as the coachmark\n * engine (`wire_questionnaire_*` keys). The AI seam: pass a server-provided `decision` and it\n * OVERRIDES the local rules (see decideQuestionnaire). The whole cost of being AI-ready is\n * passing that object straight through - mirroring `useReviewGate` exactly.\n *\n * Fallback chain (matches the server design): (1) a server `decision` wins immediately;\n * (2) no decision → after `timeoutFallbackMs` the local rules take over; (3) the once-gate\n * (`wire_questionnaire_<id>_seen`) always applies locally, so a server bug can never re-spam\n * the popup. The global `isTestingCoachmark` flag force-shows the gate for QA replay, and the\n * `questionnaire` master switch (a disabled tenant) wins over everything.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { hasSeenGate, isCoachmarkTesting, markSeenGate } from \"../coachmarks/runtime\";\nimport { useResolvedFeatures } from \"../features/WireFeaturesProvider\";\nimport { sameDecision, shallowEqual } from \"../reviews/equality\";\nimport { decideQuestionnaire, evaluateGate, resolveRules } from \"./decision\";\nimport {\n questionnaireLastShownKey,\n questionnaireSeenKey,\n questionnaireSessionsKey,\n readInt,\n resolveStorage,\n writeInt,\n} from \"./runtime\";\nimport type {\n QuestionnaireDecision,\n QuestionnaireGateController,\n UseQuestionnaireGateOptions,\n} from \"./types\";\n\n/**\n * Hold a stable reference for a value while its CONTENT is unchanged. Integrators pass inline\n * `config` / `decision` objects (idiomatic React) whose identity flips every render; feeding\n * those straight into the deps below would recompute the verdict - and mint a fresh verdict\n * object - on every render, which loops any host that lists the returned verdict in its own\n * effect. Comparing by value here keeps the reference (and everything derived from it) stable.\n */\nconst useStableValue = <T,>(value: T, isEqual: (a: T, b: T) => boolean): T => {\n const ref = useRef(value);\n if (!isEqual(ref.current, value)) ref.current = value;\n return ref.current;\n};\n\nexport const useQuestionnaireGate = ({\n config: configProp,\n decision: decisionProp,\n events = 0,\n storage,\n isTesting,\n features,\n featuresConfig,\n}: UseQuestionnaireGateOptions): QuestionnaireGateController => {\n // Tolerate inline-identity props: only adopt a new reference on a real value change.\n const config = useStableValue(configProp, shallowEqual);\n const decision = useStableValue(decisionProp, (a, b) => sameDecision(a, b));\n\n // The questionnaire MASTER switch. Disabled → the gate never fires, composing as an extra\n // AND over the local rules + the server decision seam below (fail-open: defaults to enabled).\n const featureEnabled = useResolvedFeatures({ flags: features, config: featuresConfig })\n .questionnaire.enabled;\n\n const testing = isTesting ?? isCoachmarkTesting();\n const seenKey = questionnaireSeenKey(\n config.id,\n config.oncePerVersion === false ? undefined : config.appVersion,\n );\n const lastKey = questionnaireLastShownKey(config.id);\n const sessionsKey = questionnaireSessionsKey(config.id);\n\n // Read (and bump) the session counter ONCE per mount: this mount is a new session.\n const sessions = useState(() => {\n const store = resolveStorage(storage);\n const next = readInt(store, sessionsKey) + 1;\n writeInt(store, sessionsKey, next);\n return next;\n })[0];\n\n // Gate the local rules behind an optional client-side timeout, so a reachable server gets a\n // window to answer first. A present `decision` bypasses the wait entirely.\n const hasServerDecision = decision != null;\n const timeoutMs = config.timeoutFallbackMs;\n const waits = !hasServerDecision && timeoutMs != null && timeoutMs > 0;\n const [elapsed, setElapsed] = useState(!waits);\n useEffect(() => {\n if (!waits) {\n setElapsed(true);\n return;\n }\n const timer = setTimeout(() => setElapsed(true), timeoutMs as number);\n return () => clearTimeout(timer);\n }, [waits, timeoutMs]);\n\n const { visible, verdict } = useMemo(() => {\n // Master kill switch wins over everything, including QA replay: a tenant that turned the\n // questionnaire OFF must never see it, whatever the rules, the server decision, or testing say.\n if (!featureEnabled)\n return {\n visible: false,\n verdict: { fire: false, reason: \"feature_disabled\" } as QuestionnaireDecision,\n };\n\n // QA replay: force-show, bypassing rules + gates (safe: only via __DEV__ && bool).\n if (testing)\n return {\n visible: true,\n verdict: { fire: true, reason: \"testing\" } as QuestionnaireDecision,\n };\n\n const store = resolveStorage(storage);\n const local = evaluateGate(resolveRules(config), {\n sessions,\n events,\n lastShownAt: readInt(store, lastKey) || null,\n seen: hasSeenGate(seenKey, storage, isTesting),\n now: Date.now(),\n });\n const resolved = decideQuestionnaire(local, decision);\n // (3) the once-gate always wins locally, even over a server \"fire\".\n const alreadySeen = hasSeenGate(seenKey, storage, isTesting);\n const ready = hasServerDecision || elapsed;\n return { visible: ready && resolved.fire && !alreadySeen, verdict: resolved };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n featureEnabled,\n testing,\n config,\n decision,\n events,\n sessions,\n elapsed,\n hasServerDecision,\n seenKey,\n lastKey,\n storage,\n isTesting,\n ]);\n\n // Stable callbacks + a stable controller object, so a host can safely list any of them in its\n // own effect deps without the effect re-firing every render.\n const shownRef = useRef(false);\n const markShown = useCallback(() => {\n if (shownRef.current) return;\n shownRef.current = true;\n writeInt(resolveStorage(storage), lastKey, Date.now());\n }, [storage, lastKey]);\n const markResolved = useCallback(() => {\n markSeenGate(seenKey, storage, isTesting);\n }, [seenKey, storage, isTesting]);\n\n return useMemo<QuestionnaireGateController>(\n () => ({ visible, decision: verdict, markShown, markResolved }),\n [visible, verdict, markShown, markResolved],\n );\n};\n"]}