@wireai/activation 0.9.0 → 0.9.1

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/components/DoneCheck.tsx","../../src/components/CardHandoff.tsx","../../src/components/ModalPaneHost.tsx","../../src/haptics/haptics.ts","../../src/theme/mergeThemeOver.ts","../../src/reviews/decision.ts","../../src/reviews/feedbackForm.ts","../../src/motion/centeredModalMotion.ts","../../src/reviews/presentation.ts","../../src/components/CenteredModal.tsx","../../src/reviews/storeReview.ts","../../src/reviews/transport.ts","../../src/reviews/ReviewGate.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/reviews/useReviewGate.ts"],"names":["createContext","useContext","useState","useEffect","AccessibilityInfo","useRef","Animated","useCallback","jsx","Pressable","Text","React","StyleSheet","styles","Easing","jsxs","Fragment","easeWire","View","forwardRef","useImperativeHandle","BackHandler","Modal","SafeAreaView","Platform","Linking","useMemo","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 * 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 * 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 * 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 * 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 * 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 * presentation.ts — the pure presentation + entrance-animation logic for the review gate.\n *\n * WHY split out: the gate UI (ReviewGate/ReviewModal) is RN and can't run under the kit's\n * node:test runner, but the presentation DEFAULT and the entrance math are pure and worth\n * pinning. Keep the animation spec here so both the component and the tests read one source.\n *\n * The centered popup uses RN's built-in `Animated` (native driver) — the same idiom as\n * CompletionView/CardHandoff — so the reviews module stays dependency-free (no reanimated).\n */\nimport type { ReviewPresentation } from \"./types\";\n\n/** Centered popup by default (Malik's ruling: the bottom-anchored inline card read as wrong). */\nexport const DEFAULT_PRESENTATION: ReviewPresentation = \"modal\";\n\n/** Resolve the presentation prop → the effective mode. Absent → the centered modal. */\nexport const resolvePresentation = (p?: ReviewPresentation): ReviewPresentation =>\n p ?? DEFAULT_PRESENTATION;\n\n/**\n * The centered-popup entrance spec + pure entrance-frame math now live in the neutral\n * `../motion/centeredModalMotion` (the shell was extracted to `components/CenteredModal` so the\n * questionnaire module can reuse it without importing reviews/). Re-exported here under their\n * original names so the reviews public API (reviews/index.ts) and presentation.test.ts stay valid.\n */\nexport {\n CENTERED_MODAL_ANIM as REVIEW_MODAL_ANIM,\n centeredModalFrame as entranceFrame,\n} from \"../motion/centeredModalMotion\";\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 * storeReview.ts — the 5-star route: ask for a native in-app review, or fall back to\n * opening the store listing.\n *\n * `expo-store-review` is an OPTIONAL peer, loaded lazily via a guarded dynamic import so\n * the core kit never depends on it. When present + available, we call\n * `StoreReview.requestReview()` (the OS decides whether to actually show the dialog — it is\n * quota'd, ~3/year on iOS, and NEVER guaranteed). When absent/unavailable, we open the\n * configured store URL as a graceful fallback. Both paths are best-effort and never throw.\n *\n * Store-policy: call this ONLY on the honest 5-star path, from a NEUTRAL prompt — never a\n * button labeled \"rate us 5 stars\". See the README store-policy notes.\n */\nimport { Linking, Platform } from \"react-native\";\n\nimport type { ReviewStoreConfig } from \"./types\";\n\n/** The store deep-link for the current platform, or null if none is configured. */\nexport const storeUrl = (store: ReviewStoreConfig | undefined): string | null => {\n if (!store) return null;\n if (Platform.OS === \"ios\" && store.iosAppId) {\n return `itms-apps://itunes.apple.com/app/id${store.iosAppId}?action=write-review`;\n }\n if (Platform.OS === \"android\" && store.androidPackage) {\n return `market://details?id=${store.androidPackage}`;\n }\n return store.storeUrl ?? null;\n};\n\n/** Open the configured store listing. Best-effort; resolves false if there was nothing to open. */\nexport const openStoreListing = async (\n store: ReviewStoreConfig | undefined,\n): Promise<boolean> => {\n const url = storeUrl(store);\n if (!url) return false;\n try {\n await Linking.openURL(url);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Request the native in-app review when the optional peer is available; otherwise open the\n * store listing. Returns the path taken so the caller can fire the right analytics.\n */\nexport const requestStoreReview = async (\n store?: ReviewStoreConfig,\n): Promise<\"native\" | \"store_url\" | \"none\"> => {\n try {\n const mod = await import(\"expo-store-review\");\n if (mod && (await mod.isAvailableAsync())) {\n await mod.requestReview();\n return \"native\";\n }\n } catch {\n // Peer not installed or the native call failed — fall through to the URL fallback.\n }\n const opened = await openStoreListing(store);\n return opened ? \"store_url\" : \"none\";\n};\n","/**\n * transport.ts — kit → Wire server requests for the review module, all fire-and-forget\n * (analytics/reviews must never break the app). Mirrors analytics/reportClientEvent: a\n * thin fetch wrapper, Bearer tenant key, swallow every error.\n *\n * • submitReview → POST {serverUrl}/v1/reviews (the review row)\n * • fetchReviewDecision → GET {serverUrl}/v1/reviews/decision (best-effort, the AI seam)\n * • reportAppEvent → POST {serverUrl}/v1/events (generic app.* namespace)\n *\n * `reportAppEvent` is the strategic extension: it lets a host report arbitrary in-app\n * events through the SAME transport (stored server-side as event_type='app_event',\n * question_key=<name>), which is what the backend review-firing rules evaluate on — and\n * it seeds the broader app-analytics stream. Keep payloads minimal + non-PII.\n */\nimport type { ReviewDecisionResponse, ReviewSubmission, ReviewTarget } from \"./types\";\n\n/**\n * POST a review (the 1-4 feedback path). Fire-and-forget: a missing target, a build error,\n * a missing `fetch`, or a network failure is swallowed and the call returns immediately.\n */\nexport const submitReview = (\n target: ReviewTarget | undefined,\n review: ReviewSubmission,\n): void => {\n if (!target?.serverUrl) return;\n try {\n const url = `${target.serverUrl.replace(/\\/$/, \"\")}/v1/reviews`;\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(review),\n }).catch(() => {\n /* best-effort, swallow */\n });\n } catch {\n /* URL/JSON/missing-fetch — swallow */\n }\n};\n\n/** Options for the best-effort review decision fetch. */\nexport interface FetchReviewDecisionOptions {\n /**\n * The onboarding session id, when there IS one. OPTIONAL on purpose: the review gate lives on\n * the home feed, where a user legitimately has no onboarding session. `deviceKey` is the real\n * identity for this call. (Today's prod still requires `session_id` and answers 422 without it;\n * the server relaxation is unmerged. A 422 is a non-2xx, so it returns null like any other\n * failure, and the local rules stand. Permissive wire: do NOT make this required here.)\n */\n sessionId?: string;\n /** A stable, non-PII device id. The decision endpoint reads it for cooldown + min-sessions. */\n deviceKey?: string;\n}\n\n/**\n * Best-effort fetch of the SERVER's review firing decision. The mirror of\n * `fetchQuestionnaireDecision`, and the primitive whose absence caused a live incident.\n *\n * ── WHY THIS LIVES IN THE KIT (Malik, 2026-07-16) ────────────────────────────────────────\n *\n * The questionnaire module has always had its decision fetch; reviews never did. So a host\n * hand-rolled one, and got it subtly wrong: its helper collapsed an explicit `{fire:false}`\n * into `undefined`. `decideReview` is `(local, decision) => decision ?? local`, so `undefined`\n * means \"the server has no opinion, use the local rules\" — and the local timer fired. The\n * server could therefore only ever turn review prompts ON, never OFF. A real user was asked to\n * rate the app ~3 minutes into their FIRST session, having seen nothing yet, and left 1 star.\n *\n * The bug was not that the host was careless. It was that the kit made every host invent this.\n * So the primitive moves here and hosts keep a thin call site.\n *\n * ── THE CONTRACT THAT MATTERS ────────────────────────────────────────────────────────────\n *\n * • 2xx → the FULL `{fire, reason, arm}`, INCLUDING `fire:false`. Never collapse a false\n * into null. That collapse IS the bug: a false must reach `decideReview` intact so\n * it can override the local rules and keep the gate shut.\n * • else → null, and ONLY then. Null means \"the server genuinely has no opinion\", which is\n * the one case where falling back to local rules is correct.\n *\n * Never throws: unreachable, non-2xx (incl. today's 422), bad JSON, or a missing `fetch` all\n * resolve to null. The kit does not call this internally; a host awaits it and passes the\n * result straight to `useReviewGate({ decision })`.\n *\n * const decision = await fetchReviewDecision(target, { deviceKey });\n * const gate = useReviewGate({ config, decision: decision ?? undefined, storage });\n */\nexport const fetchReviewDecision = async (\n target: ReviewTarget | undefined,\n options: FetchReviewDecisionOptions = {},\n): Promise<ReviewDecisionResponse | 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/reviews/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 ReviewDecisionResponse | null;\n // A body without a boolean `fire` is not a decision. Guard it explicitly rather than\n // letting `{}` through as a truthy object that `decideReview` would treat as a verdict\n // (`{}.fire === undefined` is falsy, so it would silently read as \"never fire\").\n if (!json || typeof json.fire !== \"boolean\") return null;\n return json;\n } catch {\n /* unreachable / non-2xx / bad JSON / missing-fetch → the server has no opinion */\n return null;\n }\n};\n\n/** Options for a reported app event. `deviceKey` groups a device's sessions server-side. */\nexport interface ReportAppEventOptions {\n /** The onboarding/session id to correlate with, when known. */\n sessionId?: string;\n /** A stable, non-PII device id — the review-decision endpoint reads it for min-sessions. */\n deviceKey?: string;\n /** Small non-PII extras. */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Report a generic in-app event through the existing events transport. Stored server-side\n * as `event_type='app_event'`, `question_key=<name>`. Fire-and-forget. Keep `name` a short\n * stable identifier and `meta` small + non-PII.\n *\n * reportAppEvent(target, \"content_share\", { sessionId, deviceKey });\n */\nexport const reportAppEvent = (\n target: ReviewTarget | undefined,\n name: string,\n options: ReportAppEventOptions = {},\n): void => {\n if (!target?.serverUrl || !name) return;\n try {\n const url = `${target.serverUrl.replace(/\\/$/, \"\")}/v1/events`;\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;\n const event: Record<string, unknown> = {\n event_type: \"app_event\",\n question_key: name,\n };\n if (options.sessionId) event.session_id = options.sessionId;\n // device_key rides in the non-PII user_context bucket the server sanitizes; the\n // review-decision endpoint reads it to group a device's sessions.\n if (options.deviceKey) event.user_context = { device_key: options.deviceKey };\n if (options.meta && Object.keys(options.meta).length > 0) {\n event.meta = JSON.stringify(options.meta);\n }\n void fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ events: [event] }),\n }).catch(() => {\n /* best-effort, swallow */\n });\n } catch {\n /* swallow */\n }\n};\n","/**\n * ReviewGate — the in-app review sentiment gate UI.\n *\n * A NEUTRAL prompt (\"Enjoying <app>?\") over five tappable stars. The honest split:\n * • 5 stars → the native store review (expo-store-review when available, else the\n * configured store URL). Fires `store_review_requested`, and POSTs a text-less\n * `stars=5` row carrying `meta.store_route` so promoters reach the server too\n * (before 2026-07-16 this route posted nothing — see `pickRating`).\n * • 1-4 stars → a feedback form: the \"why this rating\" opinion box (~4 lines, MANDATORY\n * as of Malik's 2026-07-16 ruling) and a smaller optional \"what can you suggest\" box,\n * POSTed to the Wire server (`feedback_text` + `suggestion`). Warm thank-you state,\n * never a dead end.\n *\n * EXACTLY ONE row is POSTed per gate, at the last responsible moment — see `postOnce`. A\n * detractor who abandons instead of typing still has their rating posted (`meta.abandoned`),\n * so forcing the text can never cost us the detractor data it exists to collect.\n *\n * The form NEVER asks for identity (no name / email / contact field): the host already\n * identifies the user via `sessionId` + `meta` (e.g. user_id, device_key), which is all\n * the POST body carries alongside the rating and the free text.\n *\n * Motion (2026-07-16): the three phases used to swap IN PLACE with no transition. They now\n * ride `ModalPaneHost`, the same pane-slide primitive the questionnaire steps use, and the\n * thank-you plays the shared `DoneCheck` payoff before the existing 1500ms auto-close.\n * Picking a star fires a haptic through the lazy, optional `expo-haptics` peer — silently\n * absent when the host has not installed it. The popup's own entrance is unchanged: it is\n * the CenteredModal shell's spring, which already animates.\n *\n * Every visual value comes from the OnboardingTheme (useOnboardingTheme). Analytics are\n * callback-based (mirroring the coachmark convention): the host wires `onEvent` to its own\n * analytics. No PII in events — feedback text goes ONLY in the POST body.\n *\n * Store-policy: `requestReview` is quota'd and never guaranteed to show; it is called ONLY\n * on the 5-star path, never from a \"rate us 5 stars\" button. See the README notes.\n */\nimport React, { useCallback, useMemo, useState } from \"react\";\nimport { Pressable, StyleSheet, Text, TextInput, View } from \"react-native\";\n\nimport { Button } from \"../components/Button\";\nimport { DoneCheck } from \"../components/DoneCheck\";\nimport { ModalPaneHost } from \"../components/ModalPaneHost\";\nimport { playHaptic } from \"../haptics/haptics\";\nimport { mergeThemeOver } from \"../theme/mergeThemeOver\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport { bodyStyle, captionStyle, headingStyle } from \"../theme/typography\";\nimport { buildReviewSubmission, routeRating } from \"./decision\";\nimport { feedbackInputHeights } from \"./feedbackForm\";\nimport { resolvePresentation } from \"./presentation\";\nimport { ReviewModal, type ReviewModalHandle } from \"./ReviewModal\";\nimport { requestStoreReview } from \"./storeReview\";\nimport { submitReview } from \"./transport\";\nimport type { ReviewGateProps, ReviewSubmission } from \"./types\";\n\ntype Phase = \"rating\" | \"feedback\" | \"thanks\";\n\nconst _ReviewGate: React.FC<ReviewGateProps> = ({\n appName,\n store,\n target,\n sessionId,\n meta,\n onEvent,\n onResolved,\n onShown,\n theme: themeOverride,\n dismissible = true,\n presentation,\n id = \"default\",\n}) => {\n const active = useOnboardingTheme();\n const t = useMemo(() => mergeThemeOver(active, themeOverride), [active, themeOverride]);\n const mode = resolvePresentation(presentation);\n const modalRef = React.useRef<ReviewModalHandle>(null);\n\n const [phase, setPhase] = useState<Phase>(\"rating\");\n const [stars, setStars] = useState(0);\n const [hovered, setHovered] = useState(0);\n const [feedback, setFeedback] = useState(\"\");\n const [suggestion, setSuggestion] = useState(\"\");\n\n // Fire review_prompt_shown exactly ONCE per mount. The callbacks are read through\n // refs (not effect deps) so an inline `onShown`/`onEvent` — recreated every render,\n // as real hosts idiomatically pass — never re-runs the effect. Empty deps + the\n // shownRef guard make this a true fire-once, immune to prop-identity churn.\n const shownRef = React.useRef(false);\n const onShownRef = React.useRef(onShown);\n const onEventRef = React.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: \"review_prompt_shown\", id });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const resolveTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n\n React.useEffect(() => {\n return () => {\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n };\n }, []);\n\n const resolve = useCallback(() => {\n onResolved?.();\n }, [onResolved]);\n\n /**\n * EXACTLY ONE review row per gate, ever — the latch that makes \"force feedback\" safe.\n *\n * WHY ONE POST AND NOT TWO: the tempting design is to post the rating at star-tap and then\n * post again with the text, enriching the first row. That needs the server to accept a\n * client-supplied id so the second write UPSERTS. It does not, as deployed today:\n * `create_review` mints its own id unconditionally (`app/reviews.py` `_new_id()`) and\n * `CreateReviewRequest` (`app/schemas.py`) has no id field — so two posts = two rows, which\n * double-counts `count` and corrupts `avg`. That is the SAME class of data corruption this\n * whole change exists to fix. And `submitReview` is fire-and-forget (transport.ts: the\n * response is never read), so the kit CANNOT detect a rejection and repair it: a wrong guess\n * fails silently and permanently. So we post once, at the last responsible moment, and never\n * depend on an unmerged/undeployed server capability.\n */\n const postedRef = React.useRef(false);\n const postOnce = useCallback(\n (body: ReviewSubmission) => {\n if (postedRef.current) return;\n postedRef.current = true;\n submitReview(target, body);\n },\n [target],\n );\n\n /**\n * The abandonment safety net, and the reason forcing feedback does not COST us detractor data.\n *\n * Malik's ruling: a 1-4 rater must leave text. Implemented naively (block Send, remove Skip),\n * that would LOSE the ratings of everyone who bails rather than types — the detractors we most\n * need — because today the 1-4 branch posts only from `sendFeedback`. So: if the gate goes away\n * while a rating is pending and unposted, we post the rating anyway, with whatever text was\n * typed, flagged `meta.abandoned`. The user is pushed to explain; the rating is never the price.\n *\n * Read through a ref and fired from an unmount-only effect, so it always sees the latest\n * state without re-subscribing (the same ref convention `review_prompt_shown` above uses).\n */\n const abandonRef = React.useRef<() => void>(() => {});\n abandonRef.current = () => {\n if (postedRef.current || stars < 1) return;\n postOnce(\n buildReviewSubmission({\n stars,\n feedbackText: feedback,\n suggestion,\n sessionId,\n meta: { ...meta, abandoned: true },\n }),\n );\n };\n React.useEffect(() => () => abandonRef.current(), []);\n\n const resolveWithDelay = useCallback(() => {\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n resolveTimer.current = setTimeout(() => {\n if (mode === \"modal\") {\n modalRef.current?.close();\n } else {\n onResolved?.();\n }\n }, 1500);\n }, [mode, onResolved]);\n\n const pickRating = useCallback(\n async (value: number) => {\n setStars(value);\n // The tap you feel. Fire-and-forget: an absent peer must never delay the route below.\n playHaptic(\"selection\");\n onEvent?.({ name: \"review_rating_selected\", id, stars: value });\n if (routeRating(value) === \"store\") {\n onEvent?.({ name: \"store_review_requested\", id, stars: value });\n const route = await requestStoreReview(store);\n // The 5-star row. Until 2026-07-16 this branch POSTed NOTHING: submitReview was\n // reachable only from the feedback phase, which only the 1-4 route enters. Every\n // promoter was silently dropped, so server-side `by_stars[\"5\"]` and `store_routed`\n // were permanently 0 and `avg` averaged detractors only. The four onEvent moments\n // above go to the HOST's analytics, never to Wire, so nothing else covered this.\n //\n // The body is `stars` + `meta` with NO feedback text — exactly the shape the server\n // already documents as the store route (\"A 5-star tap posts stars=5 with no text\")\n // and the shape its `store_routed` aggregate counts (stars == 5 and not\n // feedback_text). So this is valid against prod as deployed, with no server change.\n //\n // `store_route` records WHICH route we took (native dialog / store URL / neither).\n // Honest ceiling: requestStoreReview is OS-quota'd and reports nothing about whether\n // the user actually left a review — this only ever means we ASKED. Never read it as\n // a review count. We await first so the row carries the route it actually took.\n postOnce(\n buildReviewSubmission({\n stars: value,\n sessionId,\n meta: { ...meta, store_route: route },\n }),\n );\n setPhase(\"thanks\");\n resolveWithDelay();\n } else {\n // 1-4: no post yet. The row lands either from `sendFeedback` (with the forced text) or\n // from the abandonment net above — one row, whichever happens first.\n setPhase(\"feedback\");\n }\n },\n [onEvent, id, store, postOnce, sessionId, meta, resolveWithDelay],\n );\n\n /**\n * Malik's ruling (2026-07-16): a 1-4 rater is FORCED to leave feedback. Enforced HERE, on the\n * client, and deliberately NOT on the wire: `feedback_text` stays optional in\n * `CreateReviewRequest`, because the transport is fire-and-forget and every already-shipped\n * client still posts text-less rows — tightening the server would silently 422 them into\n * oblivion. Permissive wire, strict client.\n *\n * Mirrors the questionnaire contract exactly: the opinion box is the mandatory one, the\n * suggestion box stays optional. Trimmed — whitespace is not feedback.\n */\n const feedbackReady = feedback.trim().length > 0;\n\n const sendFeedback = useCallback(() => {\n // The forced-text gate. Also guarded here, not just on the button's `disabled`, so the\n // rule holds no matter who calls this.\n if (!feedbackReady) return;\n // Identity is NEVER collected here — the host already sends user_id / device /\n // session via `sessionId` + `meta`. We POST only the rating + the free text.\n const body = buildReviewSubmission({\n stars,\n feedbackText: feedback,\n suggestion,\n sessionId,\n meta,\n });\n postOnce(body);\n onEvent?.({ name: \"review_feedback_submitted\", id, stars });\n playHaptic(\"success\");\n setPhase(\"thanks\");\n resolveWithDelay();\n }, [feedbackReady, stars, feedback, suggestion, sessionId, meta, postOnce, onEvent, id, resolveWithDelay]);\n\n const dismiss = useCallback(() => {\n setPhase(\"thanks\");\n resolveWithDelay();\n }, [resolveWithDelay]);\n\n // The in-card \"Not now\"/\"Skip\" link. In modal mode it plays the popup's exit animation\n // (which resolves on completion, the same path a backdrop tap takes); inline keeps the\n // legacy behavior of swapping to the thank-you in place.\n const handleDismissTap = useCallback(() => {\n if (mode === \"modal\") modalRef.current?.close();\n else dismiss();\n }, [mode, dismiss]);\n\n const surface = {\n backgroundColor: t.colors.surface,\n borderRadius: t.radius.lg,\n padding: t.spacing.lg,\n gap: t.spacing.md,\n } as const;\n\n // A multiline box ~4 lines tall (capped at ~5), derived from the theme's body\n // line-height so it scales with the app's font config. The field's own vertical\n // padding is folded in so the requested lines are visible inside the padding.\n const feedbackBox = feedbackInputHeights(t.fonts, t.spacing.md);\n\n const linkStyle = [captionStyle(t.fonts), styles.link, { color: t.colors.textMuted }];\n\n // Each phase is a self-contained PANE, title included, so the heading travels with its\n // content instead of swapping under a static header — one moving surface, not two.\n const ratingPane = (\n <View style={{ gap: t.spacing.md }}>\n <Text style={[headingStyle(t.fonts), { color: t.colors.text }]}>\n {appName ? `Enjoying ${appName}?` : \"How's your experience?\"}\n </Text>\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n Tap a star to let us know.\n </Text>\n <View style={styles.stars}>\n {[1, 2, 3, 4, 5].map((n) => {\n const filled = n <= (hovered || stars);\n return (\n <Pressable\n key={n}\n onPressIn={() => setHovered(n)}\n onPressOut={() => setHovered(0)}\n onPress={() => void pickRating(n)}\n accessibilityRole=\"button\"\n accessibilityLabel={`${n} star${n > 1 ? \"s\" : \"\"}`}\n hitSlop={8}\n >\n <Text style={[styles.star, { color: filled ? t.colors.primary : t.colors.border }]}>\n {filled ? \"★\" : \"☆\"}\n </Text>\n </Pressable>\n );\n })}\n </View>\n {dismissible && (\n <Pressable\n onPress={handleDismissTap}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Dismiss the review prompt\"\n >\n <Text style={linkStyle}>Not now</Text>\n </Pressable>\n )}\n </View>\n );\n\n const feedbackPane = (\n <View style={{ gap: t.spacing.md }}>\n <Text style={[headingStyle(t.fonts), { color: t.colors.text }]}>What should we improve?</Text>\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n A few words is plenty — tell us what went wrong and we'll fix it.\n </Text>\n {/* No name / email / contact field: the host already identifies the user via\n sessionId + meta, so we never ask for identity here. As of Malik's 2026-07-16\n ruling the FIRST box is mandatory (mirroring the questionnaire's `opinion`);\n the suggestion box stays optional. */}\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n Why this rating?\n </Text>\n <TextInput\n value={feedback}\n onChangeText={setFeedback}\n placeholder=\"e.g. too many steps\"\n placeholderTextColor={t.colors.textMuted}\n accessibilityLabel=\"Why this rating?\"\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: feedbackBox.minHeight,\n maxHeight: feedbackBox.maxHeight,\n },\n ]}\n />\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n What can we do better? (optional)\n </Text>\n <TextInput\n value={suggestion}\n onChangeText={setSuggestion}\n placeholder=\"e.g. save my place between steps\"\n placeholderTextColor={t.colors.textMuted}\n accessibilityLabel=\"What can we do better? (optional)\"\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 paddingHorizontal: t.spacing.md,\n paddingVertical: t.spacing.sm,\n minHeight: t.button.height,\n },\n ]}\n />\n <Button\n title=\"Send feedback\"\n onPress={sendFeedback}\n variant=\"primary\"\n fullWidth\n disabled={!feedbackReady}\n />\n {/* No Skip here — this step is mandatory (Malik, 2026-07-16). The rating itself is\n still never held hostage: bailing out of the gate entirely (backdrop / Android\n back / navigation) posts it through the abandonment net above. We do NOT trap the\n user in the modal; forcing the TEXT is the rule, imprisoning them is not. */}\n </View>\n );\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 We appreciate you. This helps us make it better.\n </Text>\n </View>\n );\n\n // The phase content, shared by both presentations. In \"modal\" mode ReviewModal supplies\n // the centered, dimmed, animated card surface; in \"inline\" mode the bare card below does.\n const content = (\n <ModalPaneHost paneKey={phase}>\n {phase === \"rating\" ? ratingPane : phase === \"feedback\" ? feedbackPane : thanksPane}\n </ModalPaneHost>\n );\n\n // Default: a centered popup over a dimmed backdrop with a spring/fade entrance. A backdrop\n // tap (or Android back) resolves via the same path onResolved already tracks.\n if (mode === \"modal\") {\n return (\n <ReviewModal ref={modalRef} theme={t} dismissible={dismissible} onDismiss={resolve}>\n {content}\n </ReviewModal>\n );\n }\n\n // Legacy: the bare card, positioned by wherever the host mounts it.\n return <View style={[styles.card, surface]}>{content}</View>;\n};\n\nexport const ReviewGate = React.memo(_ReviewGate);\nReviewGate.displayName = \"ReviewGate\";\n\nconst styles = StyleSheet.create({\n card: { width: \"100%\" },\n stars: { flexDirection: \"row\", justifyContent: \"center\", gap: 8 },\n star: { fontSize: 40, lineHeight: 46 },\n input: { borderWidth: 1 },\n link: { textAlign: \"center\", textDecorationLine: \"underline\" },\n centerText: { textAlign: \"center\" },\n});\n\nexport default ReviewGate;\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 * useReviewGate — owns WHEN the review 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_review_*` keys). The AI seam: pass a server-provided `decision` and it\n * OVERRIDES the local rules (see decideReview). The whole cost of being AI-ready is passing\n * that object straight through.\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_review_<id>_seen`) always applies locally, so a server bug can never spam the prompt.\n * The global `isTestingCoachmark` flag force-shows the gate for QA replay.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { hasSeenGate, isCoachmarkTesting, markSeenGate } from \"../coachmarks/runtime\";\nimport { useResolvedFeatures } from \"../features/WireFeaturesProvider\";\nimport { decideReview, evaluateGate, resolveRules } from \"./decision\";\nimport { sameDecision, shallowEqual } from \"./equality\";\nimport {\n readInt,\n resolveStorage,\n reviewLastShownKey,\n reviewSeenKey,\n reviewSessionsKey,\n writeInt,\n} from \"./runtime\";\nimport type {\n ReviewDecision,\n ReviewGateController,\n UseReviewGateOptions,\n} from \"./types\";\n\n/**\n * Hold a stable reference for a value while its CONTENT is unchanged. Integrators\n * pass inline `config` / `decision` objects (idiomatic React) whose identity flips\n * every render; feeding those straight into the deps below would recompute the\n * verdict — and mint a fresh verdict object — on every render, which loops any host\n * that lists the returned verdict in its own effect. Comparing by value here keeps\n * the reference (and everything derived from it) stable across identity-only churn.\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 useReviewGate = ({\n config: configProp,\n decision: decisionProp,\n events = 0,\n storage,\n isTesting,\n features,\n featuresConfig,\n}: UseReviewGateOptions): ReviewGateController => {\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(\n decisionProp,\n (a, b) => sameDecision(a, b),\n );\n\n // The review MASTER switch. Disabled → the gate never fires, composing as an extra AND over\n // the local rules + the server decision seam below (fail-open: defaults to enabled).\n const featureEnabled = useResolvedFeatures({ flags: features, config: featuresConfig }).review.enabled;\n\n const testing = isTesting ?? isCoachmarkTesting();\n const seenKey = reviewSeenKey(config.id, config.oncePerVersion === false ? undefined : config.appVersion);\n const lastKey = reviewLastShownKey(config.id);\n const sessionsKey = reviewSessionsKey(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\n // gets a 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 reviews\n // OFF must never see the gate, whatever the rules, the server decision, or testing say.\n if (!featureEnabled) return { visible: false, verdict: { fire: false, reason: \"feature_disabled\" } as ReviewDecision };\n\n // QA replay: force-show, bypassing rules + gates (safe: only via __DEV__ && bool).\n if (testing) return { visible: true, verdict: { fire: true, reason: \"testing\" } as ReviewDecision };\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 = decideReview(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 }, [featureEnabled, testing, config, decision, events, sessions, elapsed, hasServerDecision, seenKey, lastKey, storage, isTesting]);\n\n // Stable callbacks + a stable controller object, so a host can safely list any of\n // them in its 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<ReviewGateController>(\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/components/DoneCheck.tsx","../../src/components/CardHandoff.tsx","../../src/components/ModalPaneHost.tsx","../../src/haptics/haptics.ts","../../src/theme/mergeThemeOver.ts","../../src/reviews/decision.ts","../../src/reviews/feedbackForm.ts","../../src/motion/centeredModalMotion.ts","../../src/reviews/presentation.ts","../../src/components/CenteredModal.tsx","../../src/reviews/storeReview.ts","../../src/reviews/transport.ts","../../src/reviews/ReviewGate.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/reviews/useReviewGate.ts"],"names":["createContext","useContext","useState","useEffect","AccessibilityInfo","useRef","Animated","useCallback","jsx","Pressable","Text","React","StyleSheet","styles","Easing","jsxs","Fragment","easeWire","View","forwardRef","useImperativeHandle","BackHandler","Modal","SafeAreaView","Platform","Linking","useMemo","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 * 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 * 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 * 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 * 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 * 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 * presentation.ts — the pure presentation + entrance-animation logic for the review gate.\n *\n * WHY split out: the gate UI (ReviewGate/ReviewModal) is RN and can't run under the kit's\n * node:test runner, but the presentation DEFAULT and the entrance math are pure and worth\n * pinning. Keep the animation spec here so both the component and the tests read one source.\n *\n * The centered popup uses RN's built-in `Animated` (native driver) — the same idiom as\n * CompletionView/CardHandoff — so the reviews module stays dependency-free (no reanimated).\n */\nimport type { ReviewPresentation } from \"./types\";\n\n/** Centered popup by default (Malik's ruling: the bottom-anchored inline card read as wrong). */\nexport const DEFAULT_PRESENTATION: ReviewPresentation = \"modal\";\n\n/** Resolve the presentation prop → the effective mode. Absent → the centered modal. */\nexport const resolvePresentation = (p?: ReviewPresentation): ReviewPresentation =>\n p ?? DEFAULT_PRESENTATION;\n\n/**\n * The centered-popup entrance spec + pure entrance-frame math now live in the neutral\n * `../motion/centeredModalMotion` (the shell was extracted to `components/CenteredModal` so the\n * questionnaire module can reuse it without importing reviews/). Re-exported here under their\n * original names so the reviews public API (reviews/index.ts) and presentation.test.ts stay valid.\n */\nexport {\n CENTERED_MODAL_ANIM as REVIEW_MODAL_ANIM,\n centeredModalFrame as entranceFrame,\n} from \"../motion/centeredModalMotion\";\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 * storeReview.ts — the 5-star route: ask for a native in-app review, or fall back to\n * opening the store listing.\n *\n * `expo-store-review` is an OPTIONAL peer, loaded lazily via a guarded dynamic import so\n * the core kit never depends on it. When present + available, we call\n * `StoreReview.requestReview()` (the OS decides whether to actually show the dialog — it is\n * quota'd, ~3/year on iOS, and NEVER guaranteed). When absent/unavailable, we open the\n * configured store URL as a graceful fallback. Both paths are best-effort and never throw.\n *\n * Store-policy: call this ONLY on the honest 5-star path, from a NEUTRAL prompt — never a\n * button labeled \"rate us 5 stars\". See the README store-policy notes.\n */\nimport { Linking, Platform } from \"react-native\";\n\nimport type { ReviewStoreConfig } from \"./types\";\n\n/** The store deep-link for the current platform, or null if none is configured. */\nexport const storeUrl = (store: ReviewStoreConfig | undefined): string | null => {\n if (!store) return null;\n if (Platform.OS === \"ios\" && store.iosAppId) {\n return `itms-apps://itunes.apple.com/app/id${store.iosAppId}?action=write-review`;\n }\n if (Platform.OS === \"android\" && store.androidPackage) {\n return `market://details?id=${store.androidPackage}`;\n }\n return store.storeUrl ?? null;\n};\n\n/** Open the configured store listing. Best-effort; resolves false if there was nothing to open. */\nexport const openStoreListing = async (\n store: ReviewStoreConfig | undefined,\n): Promise<boolean> => {\n const url = storeUrl(store);\n if (!url) return false;\n try {\n await Linking.openURL(url);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Request the native in-app review when the optional peer is available; otherwise open the\n * store listing. Returns the path taken so the caller can fire the right analytics.\n */\nexport const requestStoreReview = async (\n store?: ReviewStoreConfig,\n): Promise<\"native\" | \"store_url\" | \"none\"> => {\n try {\n const mod = await import(\"expo-store-review\");\n if (mod && (await mod.isAvailableAsync())) {\n await mod.requestReview();\n return \"native\";\n }\n } catch {\n // Peer not installed or the native call failed — fall through to the URL fallback.\n }\n const opened = await openStoreListing(store);\n return opened ? \"store_url\" : \"none\";\n};\n","/**\n * transport.ts — kit → Wire server requests for the review module, all fire-and-forget\n * (analytics/reviews must never break the app). Mirrors analytics/reportClientEvent: a\n * thin fetch wrapper, Bearer tenant key, swallow every error.\n *\n * • submitReview → POST {serverUrl}/v1/reviews (the review row)\n * • fetchReviewDecision → GET {serverUrl}/v1/reviews/decision (best-effort, the AI seam)\n * • reportAppEvent → POST {serverUrl}/v1/events (generic app.* namespace)\n *\n * `reportAppEvent` is the strategic extension: it lets a host report arbitrary in-app\n * events through the SAME transport (stored server-side as event_type='app_event',\n * question_key=<name>), which is what the backend review-firing rules evaluate on — and\n * it seeds the broader app-analytics stream. Keep payloads minimal + non-PII.\n */\nimport type { ReviewDecisionResponse, ReviewSubmission, ReviewTarget } from \"./types\";\n\n/**\n * POST a review (the 1-4 feedback path). Fire-and-forget: a missing target, a build error,\n * a missing `fetch`, or a network failure is swallowed and the call returns immediately.\n */\nexport const submitReview = (\n target: ReviewTarget | undefined,\n review: ReviewSubmission,\n): void => {\n if (!target?.serverUrl) return;\n try {\n const url = `${target.serverUrl.replace(/\\/$/, \"\")}/v1/reviews`;\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(review),\n }).catch(() => {\n /* best-effort, swallow */\n });\n } catch {\n /* URL/JSON/missing-fetch — swallow */\n }\n};\n\n/**\n * Options for the best-effort review decision fetch.\n *\n * ── WHAT THE DEPLOYED SERVER ACTUALLY READS (verified 2026-07-17) ────────────────────────\n *\n * `GET /v1/reviews/decision` declares exactly two query params — `session_id` and\n * `device_key` — plus the `Authorization` header. That is the whole wire. Verified against\n * the deployed OpenAPI schema, not against intent.\n *\n * This type is CLOSED on purpose. Hosts that hand-rolled this fetch invented `user_id` and\n * `session_count` query params believing \"the server ignores what it doesn't read, so passing\n * it is always safe\". Both are no-ops: the route declares neither. `session_count` is real, but\n * only on the questionnaire POST body — which is precisely how it copy-pasted its way into a\n * reviews call site and sat there doing nothing. They cost a wire lie — a call site that reads as though\n * identity and a session counter reach the firing brain when neither does. So they are not\n * offered here. Pass identity as `deviceKey`; the session count the server reasons about is the\n * one IT derives from the event stream keyed by `deviceKey`, not one the client asserts.\n *\n * The client-side session floor is a LOCAL rule, not a wire param: use `ReviewConfig.minSessions`\n * (evaluated by `useReviewGate` against the kit's own `wire_review_<id>_sessions` counter).\n */\nexport interface FetchReviewDecisionOptions {\n /**\n * The onboarding session id, when there IS one. OPTIONAL on purpose: the review gate lives on\n * the home feed, where a user legitimately has no onboarding session. `deviceKey` is the real\n * identity for this call. (The server relaxed `session_id` to optional on 2026-07-16 and the\n * relaxation IS deployed — the route no longer 422s without it. Permissive wire: do NOT make\n * this required here.)\n */\n sessionId?: string;\n /**\n * A stable, non-PII device id — THE identity for this call. The decision endpoint reads it for\n * cooldown + min-sessions, and it is the key the server groups a device's events under. A host\n * whose own identity is a user id passes that id here rather than reaching for a `user_id`\n * param the route does not declare.\n */\n deviceKey?: string;\n}\n\n/**\n * Best-effort fetch of the SERVER's review firing decision. The mirror of\n * `fetchQuestionnaireDecision`, and the primitive whose absence caused a live incident.\n *\n * ── WHY THIS LIVES IN THE KIT (Malik, 2026-07-16) ────────────────────────────────────────\n *\n * The questionnaire module has always had its decision fetch; reviews never did. So a host\n * hand-rolled one, and got it subtly wrong: its helper collapsed an explicit `{fire:false}`\n * into `undefined`. `decideReview` is `(local, decision) => decision ?? local`, so `undefined`\n * means \"the server has no opinion, use the local rules\" — and the local timer fired. The\n * server could therefore only ever turn review prompts ON, never OFF. A real user was asked to\n * rate the app ~3 minutes into their FIRST session, having seen nothing yet, and left 1 star.\n *\n * The bug was not that the host was careless. It was that the kit made every host invent this.\n * So the primitive moves here and hosts keep a thin call site.\n *\n * ── THE CONTRACT THAT MATTERS ────────────────────────────────────────────────────────────\n *\n * • 2xx → the FULL `{fire, reason, arm}`, INCLUDING `fire:false`. Never collapse a false\n * into null. That collapse IS the bug: a false must reach `decideReview` intact so\n * it can override the local rules and keep the gate shut.\n * • else → null, and ONLY then. Null means \"the server genuinely has no opinion\", which is\n * the one case where falling back to local rules is correct.\n *\n * Never throws: unreachable, non-2xx, bad JSON, or a missing `fetch` all resolve to null. The\n * kit does not call this internally; a host awaits it and passes the result straight to\n * `useReviewGate({ decision })`.\n *\n * ── DON'T RACE THIS AGAINST A LOCAL TIMER ────────────────────────────────────────────────\n *\n * The return type is `ReviewDecisionResponse`, which carries `arm` alongside `{fire, reason}`.\n * Hand the WHOLE object to the gate and echo `arm` into the submission's `meta.firing_arm`;\n * narrowing it to `{fire, reason}` on the way through silently kills per-arm attribution\n * across a reweighting of the experiment.\n *\n * A host that starts its own dwell timer in parallel with this fetch has built a race a slow\n * server loses: the timer fires, the local rules show the prompt, and the `{fire:false}` still\n * in flight arrives too late to stop it. Do not hand-roll that. `useReviewGate` already owns\n * the wait — set `ReviewConfig.timeoutFallbackMs` and the local rules stay parked until either\n * the decision lands or the window expires, whichever comes first.\n *\n * const decision = await fetchReviewDecision(target, { deviceKey });\n * const gate = useReviewGate({\n * config: { id: \"home\", minSessions: 2, timeoutFallbackMs: 3000 },\n * decision: decision ?? undefined, // pass it whole — keep `arm`\n * storage,\n * });\n */\nexport const fetchReviewDecision = async (\n target: ReviewTarget | undefined,\n options: FetchReviewDecisionOptions = {},\n): Promise<ReviewDecisionResponse | 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/reviews/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 ReviewDecisionResponse | null;\n // A body without a boolean `fire` is not a decision. Guard it explicitly rather than\n // letting `{}` through as a truthy object that `decideReview` would treat as a verdict\n // (`{}.fire === undefined` is falsy, so it would silently read as \"never fire\").\n if (!json || typeof json.fire !== \"boolean\") return null;\n return json;\n } catch {\n /* unreachable / non-2xx / bad JSON / missing-fetch → the server has no opinion */\n return null;\n }\n};\n\n/** Options for a reported app event. `deviceKey` groups a device's sessions server-side. */\nexport interface ReportAppEventOptions {\n /** The onboarding/session id to correlate with, when known. */\n sessionId?: string;\n /** A stable, non-PII device id — the review-decision endpoint reads it for min-sessions. */\n deviceKey?: string;\n /** Small non-PII extras. */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Report a generic in-app event through the existing events transport. Stored server-side\n * as `event_type='app_event'`, `question_key=<name>`. Fire-and-forget. Keep `name` a short\n * stable identifier and `meta` small + non-PII.\n *\n * reportAppEvent(target, \"content_share\", { sessionId, deviceKey });\n */\nexport const reportAppEvent = (\n target: ReviewTarget | undefined,\n name: string,\n options: ReportAppEventOptions = {},\n): void => {\n if (!target?.serverUrl || !name) return;\n try {\n const url = `${target.serverUrl.replace(/\\/$/, \"\")}/v1/events`;\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;\n const event: Record<string, unknown> = {\n event_type: \"app_event\",\n question_key: name,\n };\n if (options.sessionId) event.session_id = options.sessionId;\n // device_key rides in the non-PII user_context bucket the server sanitizes; the\n // review-decision endpoint reads it to group a device's sessions.\n if (options.deviceKey) event.user_context = { device_key: options.deviceKey };\n if (options.meta && Object.keys(options.meta).length > 0) {\n event.meta = JSON.stringify(options.meta);\n }\n void fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ events: [event] }),\n }).catch(() => {\n /* best-effort, swallow */\n });\n } catch {\n /* swallow */\n }\n};\n","/**\n * ReviewGate — the in-app review sentiment gate UI.\n *\n * A NEUTRAL prompt (\"Enjoying <app>?\") over five tappable stars. The honest split:\n * • 5 stars → the native store review (expo-store-review when available, else the\n * configured store URL). Fires `store_review_requested`, and POSTs a text-less\n * `stars=5` row carrying `meta.store_route` so promoters reach the server too\n * (before 2026-07-16 this route posted nothing — see `pickRating`).\n * • 1-4 stars → a feedback form: the \"why this rating\" opinion box (~4 lines, MANDATORY\n * as of Malik's 2026-07-16 ruling) and a smaller optional \"what can you suggest\" box,\n * POSTed to the Wire server (`feedback_text` + `suggestion`). Warm thank-you state,\n * never a dead end.\n *\n * EXACTLY ONE row is POSTed per gate, at the last responsible moment — see `postOnce`. A\n * detractor who abandons instead of typing still has their rating posted (`meta.abandoned`),\n * so forcing the text can never cost us the detractor data it exists to collect.\n *\n * The form NEVER asks for identity (no name / email / contact field): the host already\n * identifies the user via `sessionId` + `meta` (e.g. user_id, device_key), which is all\n * the POST body carries alongside the rating and the free text.\n *\n * Motion (2026-07-16): the three phases used to swap IN PLACE with no transition. They now\n * ride `ModalPaneHost`, the same pane-slide primitive the questionnaire steps use, and the\n * thank-you plays the shared `DoneCheck` payoff before the existing 1500ms auto-close.\n * Picking a star fires a haptic through the lazy, optional `expo-haptics` peer — silently\n * absent when the host has not installed it. The popup's own entrance is unchanged: it is\n * the CenteredModal shell's spring, which already animates.\n *\n * Every visual value comes from the OnboardingTheme (useOnboardingTheme). Analytics are\n * callback-based (mirroring the coachmark convention): the host wires `onEvent` to its own\n * analytics. No PII in events — feedback text goes ONLY in the POST body.\n *\n * Store-policy: `requestReview` is quota'd and never guaranteed to show; it is called ONLY\n * on the 5-star path, never from a \"rate us 5 stars\" button. See the README notes.\n */\nimport React, { useCallback, useMemo, useState } from \"react\";\nimport { Pressable, StyleSheet, Text, TextInput, View } from \"react-native\";\n\nimport { Button } from \"../components/Button\";\nimport { DoneCheck } from \"../components/DoneCheck\";\nimport { ModalPaneHost } from \"../components/ModalPaneHost\";\nimport { playHaptic } from \"../haptics/haptics\";\nimport { mergeThemeOver } from \"../theme/mergeThemeOver\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport { bodyStyle, captionStyle, headingStyle } from \"../theme/typography\";\nimport { buildReviewSubmission, routeRating } from \"./decision\";\nimport { feedbackInputHeights } from \"./feedbackForm\";\nimport { resolvePresentation } from \"./presentation\";\nimport { ReviewModal, type ReviewModalHandle } from \"./ReviewModal\";\nimport { requestStoreReview } from \"./storeReview\";\nimport { submitReview } from \"./transport\";\nimport type { ReviewGateProps, ReviewSubmission } from \"./types\";\n\ntype Phase = \"rating\" | \"feedback\" | \"thanks\";\n\nconst _ReviewGate: React.FC<ReviewGateProps> = ({\n appName,\n store,\n target,\n sessionId,\n meta,\n onEvent,\n onResolved,\n onShown,\n theme: themeOverride,\n dismissible = true,\n presentation,\n id = \"default\",\n}) => {\n const active = useOnboardingTheme();\n const t = useMemo(() => mergeThemeOver(active, themeOverride), [active, themeOverride]);\n const mode = resolvePresentation(presentation);\n const modalRef = React.useRef<ReviewModalHandle>(null);\n\n const [phase, setPhase] = useState<Phase>(\"rating\");\n const [stars, setStars] = useState(0);\n const [hovered, setHovered] = useState(0);\n const [feedback, setFeedback] = useState(\"\");\n const [suggestion, setSuggestion] = useState(\"\");\n\n // Fire review_prompt_shown exactly ONCE per mount. The callbacks are read through\n // refs (not effect deps) so an inline `onShown`/`onEvent` — recreated every render,\n // as real hosts idiomatically pass — never re-runs the effect. Empty deps + the\n // shownRef guard make this a true fire-once, immune to prop-identity churn.\n const shownRef = React.useRef(false);\n const onShownRef = React.useRef(onShown);\n const onEventRef = React.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: \"review_prompt_shown\", id });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const resolveTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n\n React.useEffect(() => {\n return () => {\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n };\n }, []);\n\n const resolve = useCallback(() => {\n onResolved?.();\n }, [onResolved]);\n\n /**\n * EXACTLY ONE review row per gate, ever — the latch that makes \"force feedback\" safe.\n *\n * WHY ONE POST AND NOT TWO: the tempting design is to post the rating at star-tap and then\n * post again with the text, enriching the first row. That needs the server to accept a\n * client-supplied id so the second write UPSERTS. It does not, as deployed today:\n * `create_review` mints its own id unconditionally (`app/reviews.py` `_new_id()`) and\n * `CreateReviewRequest` (`app/schemas.py`) has no id field — so two posts = two rows, which\n * double-counts `count` and corrupts `avg`. That is the SAME class of data corruption this\n * whole change exists to fix. And `submitReview` is fire-and-forget (transport.ts: the\n * response is never read), so the kit CANNOT detect a rejection and repair it: a wrong guess\n * fails silently and permanently. So we post once, at the last responsible moment, and never\n * depend on an unmerged/undeployed server capability.\n */\n const postedRef = React.useRef(false);\n const postOnce = useCallback(\n (body: ReviewSubmission) => {\n if (postedRef.current) return;\n postedRef.current = true;\n submitReview(target, body);\n },\n [target],\n );\n\n /**\n * The abandonment safety net, and the reason forcing feedback does not COST us detractor data.\n *\n * Malik's ruling: a 1-4 rater must leave text. Implemented naively (block Send, remove Skip),\n * that would LOSE the ratings of everyone who bails rather than types — the detractors we most\n * need — because today the 1-4 branch posts only from `sendFeedback`. So: if the gate goes away\n * while a rating is pending and unposted, we post the rating anyway, with whatever text was\n * typed, flagged `meta.abandoned`. The user is pushed to explain; the rating is never the price.\n *\n * Read through a ref and fired from an unmount-only effect, so it always sees the latest\n * state without re-subscribing (the same ref convention `review_prompt_shown` above uses).\n */\n const abandonRef = React.useRef<() => void>(() => {});\n abandonRef.current = () => {\n if (postedRef.current || stars < 1) return;\n postOnce(\n buildReviewSubmission({\n stars,\n feedbackText: feedback,\n suggestion,\n sessionId,\n meta: { ...meta, abandoned: true },\n }),\n );\n };\n React.useEffect(() => () => abandonRef.current(), []);\n\n const resolveWithDelay = useCallback(() => {\n if (resolveTimer.current) clearTimeout(resolveTimer.current);\n resolveTimer.current = setTimeout(() => {\n if (mode === \"modal\") {\n modalRef.current?.close();\n } else {\n onResolved?.();\n }\n }, 1500);\n }, [mode, onResolved]);\n\n const pickRating = useCallback(\n async (value: number) => {\n setStars(value);\n // The tap you feel. Fire-and-forget: an absent peer must never delay the route below.\n playHaptic(\"selection\");\n onEvent?.({ name: \"review_rating_selected\", id, stars: value });\n if (routeRating(value) === \"store\") {\n onEvent?.({ name: \"store_review_requested\", id, stars: value });\n const route = await requestStoreReview(store);\n // The 5-star row. Until 2026-07-16 this branch POSTed NOTHING: submitReview was\n // reachable only from the feedback phase, which only the 1-4 route enters. Every\n // promoter was silently dropped, so server-side `by_stars[\"5\"]` and `store_routed`\n // were permanently 0 and `avg` averaged detractors only. The four onEvent moments\n // above go to the HOST's analytics, never to Wire, so nothing else covered this.\n //\n // The body is `stars` + `meta` with NO feedback text — exactly the shape the server\n // already documents as the store route (\"A 5-star tap posts stars=5 with no text\")\n // and the shape its `store_routed` aggregate counts (stars == 5 and not\n // feedback_text). So this is valid against prod as deployed, with no server change.\n //\n // `store_route` records WHICH route we took (native dialog / store URL / neither).\n // Honest ceiling: requestStoreReview is OS-quota'd and reports nothing about whether\n // the user actually left a review — this only ever means we ASKED. Never read it as\n // a review count. We await first so the row carries the route it actually took.\n postOnce(\n buildReviewSubmission({\n stars: value,\n sessionId,\n meta: { ...meta, store_route: route },\n }),\n );\n setPhase(\"thanks\");\n resolveWithDelay();\n } else {\n // 1-4: no post yet. The row lands either from `sendFeedback` (with the forced text) or\n // from the abandonment net above — one row, whichever happens first.\n setPhase(\"feedback\");\n }\n },\n [onEvent, id, store, postOnce, sessionId, meta, resolveWithDelay],\n );\n\n /**\n * Malik's ruling (2026-07-16): a 1-4 rater is FORCED to leave feedback. Enforced HERE, on the\n * client, and deliberately NOT on the wire: `feedback_text` stays optional in\n * `CreateReviewRequest`, because the transport is fire-and-forget and every already-shipped\n * client still posts text-less rows — tightening the server would silently 422 them into\n * oblivion. Permissive wire, strict client.\n *\n * Mirrors the questionnaire contract exactly: the opinion box is the mandatory one, the\n * suggestion box stays optional. Trimmed — whitespace is not feedback.\n */\n const feedbackReady = feedback.trim().length > 0;\n\n const sendFeedback = useCallback(() => {\n // The forced-text gate. Also guarded here, not just on the button's `disabled`, so the\n // rule holds no matter who calls this.\n if (!feedbackReady) return;\n // Identity is NEVER collected here — the host already sends user_id / device /\n // session via `sessionId` + `meta`. We POST only the rating + the free text.\n const body = buildReviewSubmission({\n stars,\n feedbackText: feedback,\n suggestion,\n sessionId,\n meta,\n });\n postOnce(body);\n onEvent?.({ name: \"review_feedback_submitted\", id, stars });\n playHaptic(\"success\");\n setPhase(\"thanks\");\n resolveWithDelay();\n }, [feedbackReady, stars, feedback, suggestion, sessionId, meta, postOnce, onEvent, id, resolveWithDelay]);\n\n const dismiss = useCallback(() => {\n setPhase(\"thanks\");\n resolveWithDelay();\n }, [resolveWithDelay]);\n\n // The in-card \"Not now\"/\"Skip\" link. In modal mode it plays the popup's exit animation\n // (which resolves on completion, the same path a backdrop tap takes); inline keeps the\n // legacy behavior of swapping to the thank-you in place.\n const handleDismissTap = useCallback(() => {\n if (mode === \"modal\") modalRef.current?.close();\n else dismiss();\n }, [mode, dismiss]);\n\n const surface = {\n backgroundColor: t.colors.surface,\n borderRadius: t.radius.lg,\n padding: t.spacing.lg,\n gap: t.spacing.md,\n } as const;\n\n // A multiline box ~4 lines tall (capped at ~5), derived from the theme's body\n // line-height so it scales with the app's font config. The field's own vertical\n // padding is folded in so the requested lines are visible inside the padding.\n const feedbackBox = feedbackInputHeights(t.fonts, t.spacing.md);\n\n const linkStyle = [captionStyle(t.fonts), styles.link, { color: t.colors.textMuted }];\n\n // Each phase is a self-contained PANE, title included, so the heading travels with its\n // content instead of swapping under a static header — one moving surface, not two.\n const ratingPane = (\n <View style={{ gap: t.spacing.md }}>\n <Text style={[headingStyle(t.fonts), { color: t.colors.text }]}>\n {appName ? `Enjoying ${appName}?` : \"How's your experience?\"}\n </Text>\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n Tap a star to let us know.\n </Text>\n <View style={styles.stars}>\n {[1, 2, 3, 4, 5].map((n) => {\n const filled = n <= (hovered || stars);\n return (\n <Pressable\n key={n}\n onPressIn={() => setHovered(n)}\n onPressOut={() => setHovered(0)}\n onPress={() => void pickRating(n)}\n accessibilityRole=\"button\"\n accessibilityLabel={`${n} star${n > 1 ? \"s\" : \"\"}`}\n hitSlop={8}\n >\n <Text style={[styles.star, { color: filled ? t.colors.primary : t.colors.border }]}>\n {filled ? \"★\" : \"☆\"}\n </Text>\n </Pressable>\n );\n })}\n </View>\n {dismissible && (\n <Pressable\n onPress={handleDismissTap}\n hitSlop={8}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Dismiss the review prompt\"\n >\n <Text style={linkStyle}>Not now</Text>\n </Pressable>\n )}\n </View>\n );\n\n const feedbackPane = (\n <View style={{ gap: t.spacing.md }}>\n <Text style={[headingStyle(t.fonts), { color: t.colors.text }]}>What should we improve?</Text>\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n A few words is plenty — tell us what went wrong and we'll fix it.\n </Text>\n {/* No name / email / contact field: the host already identifies the user via\n sessionId + meta, so we never ask for identity here. As of Malik's 2026-07-16\n ruling the FIRST box is mandatory (mirroring the questionnaire's `opinion`);\n the suggestion box stays optional. */}\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n Why this rating?\n </Text>\n <TextInput\n value={feedback}\n onChangeText={setFeedback}\n placeholder=\"e.g. too many steps\"\n placeholderTextColor={t.colors.textMuted}\n accessibilityLabel=\"Why this rating?\"\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: feedbackBox.minHeight,\n maxHeight: feedbackBox.maxHeight,\n },\n ]}\n />\n <Text style={[captionStyle(t.fonts), { color: t.colors.textMuted }]}>\n What can we do better? (optional)\n </Text>\n <TextInput\n value={suggestion}\n onChangeText={setSuggestion}\n placeholder=\"e.g. save my place between steps\"\n placeholderTextColor={t.colors.textMuted}\n accessibilityLabel=\"What can we do better? (optional)\"\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 paddingHorizontal: t.spacing.md,\n paddingVertical: t.spacing.sm,\n minHeight: t.button.height,\n },\n ]}\n />\n <Button\n title=\"Send feedback\"\n onPress={sendFeedback}\n variant=\"primary\"\n fullWidth\n disabled={!feedbackReady}\n />\n {/* No Skip here — this step is mandatory (Malik, 2026-07-16). The rating itself is\n still never held hostage: bailing out of the gate entirely (backdrop / Android\n back / navigation) posts it through the abandonment net above. We do NOT trap the\n user in the modal; forcing the TEXT is the rule, imprisoning them is not. */}\n </View>\n );\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 We appreciate you. This helps us make it better.\n </Text>\n </View>\n );\n\n // The phase content, shared by both presentations. In \"modal\" mode ReviewModal supplies\n // the centered, dimmed, animated card surface; in \"inline\" mode the bare card below does.\n const content = (\n <ModalPaneHost paneKey={phase}>\n {phase === \"rating\" ? ratingPane : phase === \"feedback\" ? feedbackPane : thanksPane}\n </ModalPaneHost>\n );\n\n // Default: a centered popup over a dimmed backdrop with a spring/fade entrance. A backdrop\n // tap (or Android back) resolves via the same path onResolved already tracks.\n if (mode === \"modal\") {\n return (\n <ReviewModal ref={modalRef} theme={t} dismissible={dismissible} onDismiss={resolve}>\n {content}\n </ReviewModal>\n );\n }\n\n // Legacy: the bare card, positioned by wherever the host mounts it.\n return <View style={[styles.card, surface]}>{content}</View>;\n};\n\nexport const ReviewGate = React.memo(_ReviewGate);\nReviewGate.displayName = \"ReviewGate\";\n\nconst styles = StyleSheet.create({\n card: { width: \"100%\" },\n stars: { flexDirection: \"row\", justifyContent: \"center\", gap: 8 },\n star: { fontSize: 40, lineHeight: 46 },\n input: { borderWidth: 1 },\n link: { textAlign: \"center\", textDecorationLine: \"underline\" },\n centerText: { textAlign: \"center\" },\n});\n\nexport default ReviewGate;\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 * useReviewGate — owns WHEN the review 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_review_*` keys). The AI seam: pass a server-provided `decision` and it\n * OVERRIDES the local rules (see decideReview). The whole cost of being AI-ready is passing\n * that object straight through.\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_review_<id>_seen`) always applies locally, so a server bug can never spam the prompt.\n * The global `isTestingCoachmark` flag force-shows the gate for QA replay.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { hasSeenGate, isCoachmarkTesting, markSeenGate } from \"../coachmarks/runtime\";\nimport { useResolvedFeatures } from \"../features/WireFeaturesProvider\";\nimport { decideReview, evaluateGate, resolveRules } from \"./decision\";\nimport { sameDecision, shallowEqual } from \"./equality\";\nimport {\n readInt,\n resolveStorage,\n reviewLastShownKey,\n reviewSeenKey,\n reviewSessionsKey,\n writeInt,\n} from \"./runtime\";\nimport type {\n ReviewDecision,\n ReviewGateController,\n UseReviewGateOptions,\n} from \"./types\";\n\n/**\n * Hold a stable reference for a value while its CONTENT is unchanged. Integrators\n * pass inline `config` / `decision` objects (idiomatic React) whose identity flips\n * every render; feeding those straight into the deps below would recompute the\n * verdict — and mint a fresh verdict object — on every render, which loops any host\n * that lists the returned verdict in its own effect. Comparing by value here keeps\n * the reference (and everything derived from it) stable across identity-only churn.\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 useReviewGate = ({\n config: configProp,\n decision: decisionProp,\n events = 0,\n storage,\n isTesting,\n features,\n featuresConfig,\n}: UseReviewGateOptions): ReviewGateController => {\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(\n decisionProp,\n (a, b) => sameDecision(a, b),\n );\n\n // The review MASTER switch. Disabled → the gate never fires, composing as an extra AND over\n // the local rules + the server decision seam below (fail-open: defaults to enabled).\n const featureEnabled = useResolvedFeatures({ flags: features, config: featuresConfig }).review.enabled;\n\n const testing = isTesting ?? isCoachmarkTesting();\n const seenKey = reviewSeenKey(config.id, config.oncePerVersion === false ? undefined : config.appVersion);\n const lastKey = reviewLastShownKey(config.id);\n const sessionsKey = reviewSessionsKey(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\n // gets a 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 reviews\n // OFF must never see the gate, whatever the rules, the server decision, or testing say.\n if (!featureEnabled) return { visible: false, verdict: { fire: false, reason: \"feature_disabled\" } as ReviewDecision };\n\n // QA replay: force-show, bypassing rules + gates (safe: only via __DEV__ && bool).\n if (testing) return { visible: true, verdict: { fire: true, reason: \"testing\" } as ReviewDecision };\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 = decideReview(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 }, [featureEnabled, testing, config, decision, events, sessions, elapsed, hasServerDecision, seenKey, lastKey, storage, isTesting]);\n\n // Stable callbacks + a stable controller object, so a host can safely list any of\n // them in its 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<ReviewGateController>(\n () => ({ visible, decision: verdict, markShown, markResolved }),\n [visible, verdict, markShown, markResolved],\n );\n};\n"]}