{"version":3,"sources":["../../core/dist/generated/tokens.js","../../core/dist/ports/event-bus.js","../../core/dist/ports/clock.js","../../core/dist/ports/platform.js","../../core/dist/api/client.js","../../core/dist/theme/gradient-utils.js","../../core/dist/theme/theme-engine.js","../../core/dist/rpc/formatter.js","../../core/dist/stores/store.js","../../core/dist/stores/shell-store.js","../../core/dist/stores/session-store.js","../../core/dist/stores/message-store.js","../../core/dist/constants.js","../../core/dist/stores/typing-store.js","../../core/dist/stores/component-store.js","../../core/dist/stores/slash-command-store.js","../../core/dist/controller.js","../../core/dist/react/hooks.js","../src/RinggWidget.tsx","../src/components/action-button.tsx","../src/lib/gradient.tsx","../src/lib/icons.tsx","../src/lib/portable-styles.ts","../src/lib/testing.ts","../src/lib/widget-theme.tsx","../src/components/ui/pressable.tsx","../src/components/call-controls.tsx","../src/components/message-input.tsx","../src/lib/slash-command-types.ts","../src/components/slash-command-menu.tsx","../src/components/feedback-screen.tsx","../src/components/header.tsx","../src/components/interactive-flow.tsx","../src/lib/component-types.ts","../src/lib/theme-utils.ts","../src/components/steps/buttons-step.tsx","../src/components/steps/calendar-step.tsx","../src/components/steps/confirmation-step.tsx","../src/components/steps/form-step.tsx","../src/components/ui/swap.tsx","../src/components/message-item.tsx","../src/lib/markdown.tsx","../src/components/steps/blocks-step.tsx","../src/lib/block-types.ts","../src/components/loading-bar.tsx","../src/components/system-log.tsx","../src/components/typing-indicator.tsx","../src/components/voice-leaves.tsx","../src/transport/agent.ts","../src/components/dot-audio-visualizer.tsx","../src/components/ui/dialog.tsx","../src/components/ui/button.tsx","../src/hooks/use-microphone.ts","../src/hooks/use-presence.ts","../src/lib/text-helpers.tsx","../src/transport/livekit-transport.ts","../src/platform/audio-session.ts","../src/transport/legacy-chat.ts","../src/lib/utf8.ts","../src/platform/mic-permission.ts","../src/platform/app-origin.ts","../src/platform/notification.ts","../src/lib/host-actions.ts"],"sourcesContent":["/**\n * GENERATED FILE — DO NOT EDIT.\n * Source: tokens/tokens.json + tokens/defaults.json\n * Regenerate: node scripts/generate-tokens.mjs\n */\nexport const DEFAULT_WIDGET_THEME = {\n    \"primaryColor\": \"#0a0a0b\",\n    \"primaryTextColor\": \"#ffffff\",\n    \"backgroundColor\": \"#ffffff\",\n    \"surfaceColor\": \"#f3f4f6\",\n    \"agentBubbleColor\": \"\",\n    \"textColor\": \"#0a0a0b\",\n    \"mutedTextColor\": \"#6b7280\",\n    \"borderColor\": \"#e5e7eb\",\n    \"errorColor\": \"#ef4444\",\n    \"successColor\": \"#16a34a\",\n    \"buttonStyle\": \"pill\",\n    \"borderRadius\": \"16px\",\n    \"fontFamily\": \"inherit\"\n};\nexport const WIDGET_PRESET_THEMES = {\n    \"light\": {\n        \"primaryColor\": \"#18181b\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#ffffff\",\n        \"surfaceColor\": \"#f4f4f5\",\n        \"textColor\": \"#18181b\",\n        \"mutedTextColor\": \"#71717a\",\n        \"borderColor\": \"#e4e4e7\"\n    },\n    \"warm\": {\n        \"primaryColor\": \"#57534e\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#fefefe\",\n        \"surfaceColor\": \"#fafaf9\",\n        \"textColor\": \"#1c1917\",\n        \"mutedTextColor\": \"#78716c\",\n        \"borderColor\": \"#e7e5e4\"\n    },\n    \"blue\": {\n        \"primaryColor\": \"#2563eb\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#fafcff\",\n        \"surfaceColor\": \"#f0f7ff\",\n        \"textColor\": \"#1e3a8a\",\n        \"mutedTextColor\": \"#64748b\",\n        \"borderColor\": \"#dbeafe\"\n    },\n    \"indigo\": {\n        \"primaryColor\": \"#6366f1\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#fbfbff\",\n        \"surfaceColor\": \"#f5f5ff\",\n        \"textColor\": \"#312e81\",\n        \"mutedTextColor\": \"#6b7280\",\n        \"borderColor\": \"#e0e7ff\"\n    },\n    \"green\": {\n        \"primaryColor\": \"#16a34a\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#fbfefb\",\n        \"surfaceColor\": \"#f0fdf4\",\n        \"textColor\": \"#14532d\",\n        \"mutedTextColor\": \"#6b7280\",\n        \"borderColor\": \"#dcfce7\"\n    },\n    \"orange\": {\n        \"primaryColor\": \"#ea580c\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#fffdfb\",\n        \"surfaceColor\": \"#fff7ed\",\n        \"textColor\": \"#7c2d12\",\n        \"mutedTextColor\": \"#78716c\",\n        \"borderColor\": \"#ffedd5\"\n    },\n    \"dark\": {\n        \"primaryColor\": \"#fafafa\",\n        \"primaryTextColor\": \"#18181b\",\n        \"backgroundColor\": \"#18181b\",\n        \"surfaceColor\": \"#27272a\",\n        \"textColor\": \"#fafafa\",\n        \"mutedTextColor\": \"#a1a1aa\",\n        \"borderColor\": \"#3f3f46\"\n    },\n    \"sunset\": {\n        \"primaryColor\": \"linear-gradient(135deg, #f97316, #ef4444)\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#fffbf7\",\n        \"surfaceColor\": \"#fff3e8\",\n        \"textColor\": \"#7c2d12\",\n        \"mutedTextColor\": \"#9a3412\",\n        \"borderColor\": \"#fed7aa\"\n    },\n    \"ocean\": {\n        \"primaryColor\": \"linear-gradient(135deg, #667eea, #764ba2)\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#faf9ff\",\n        \"surfaceColor\": \"#f0edff\",\n        \"textColor\": \"#312e81\",\n        \"mutedTextColor\": \"#6366f1\",\n        \"borderColor\": \"#ddd6fe\"\n    },\n    \"emerald\": {\n        \"primaryColor\": \"linear-gradient(135deg, #10b981, #0ea5e9)\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#f7fdfb\",\n        \"surfaceColor\": \"#ecfdf5\",\n        \"textColor\": \"#064e3b\",\n        \"mutedTextColor\": \"#047857\",\n        \"borderColor\": \"#a7f3d0\"\n    },\n    \"midnight\": {\n        \"primaryColor\": \"linear-gradient(135deg, #6366f1, #8b5cf6)\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#18181b\",\n        \"surfaceColor\": \"#27272a\",\n        \"textColor\": \"#fafafa\",\n        \"mutedTextColor\": \"#a1a1aa\",\n        \"borderColor\": \"#3f3f46\"\n    },\n    \"policybazaar\": {\n        \"primaryColor\": \"linear-gradient(88deg, #9403fd, #00adfe)\",\n        \"primaryTextColor\": \"#ffffff\",\n        \"backgroundColor\": \"#ffffff\",\n        \"surfaceColor\": \"#f4f2ff\",\n        \"agentBubbleColor\": \"linear-gradient(107deg, #f0fff9, #f7eeff)\",\n        \"textColor\": \"#18181b\",\n        \"mutedTextColor\": \"#64748b\",\n        \"borderColor\": \"#e6e2ff\"\n    }\n};\nexport const TIMING = {\n    \"chatWidgetGraceMs\": 800,\n    \"chatWidgetAfterTextMs\": 120,\n    \"minTypingIndicatorMs\": 500\n};\nexport const WIDGET_DEFAULTS = {\n    \"mode\": \"prod\",\n    \"title\": \"Ringg AI Support\",\n    \"description\": \"Ringg AI offers 24/7 voice support to handle your business calls efficiently and professionally\",\n    \"defaultTab\": \"audio\",\n    \"hideTabSelector\": false,\n    \"defaultExpanded\": false,\n    \"bypassStartScreen\": false,\n    \"bypassFeedbackScreen\": false,\n    \"voiceCallShowAnimation\": false,\n    \"voiceCallShowTranscript\": true,\n    \"notificationTuneUrl\": \"https://assets.ringg.ai/audios/misc/widget_notification.mp3\"\n};\n","/**\n * Event bus port — abstraction over platform-specific host-event dispatch.\n *\n * Web: DOM CustomEvents on `window` (existing integrations listen for these)\n * React Native: callback props / in-memory listeners\n */\n/** Web implementation — dispatches/listens via DOM CustomEvents on `window`. */\nexport function createDomEventBus() {\n    const listeners = new Map();\n    return {\n        emit(event, payload) {\n            if (typeof window !== \"undefined\") {\n                window.dispatchEvent(new CustomEvent(event, { detail: payload }));\n            }\n        },\n        on(event, handler) {\n            if (typeof window === \"undefined\")\n                return () => { };\n            const wrapped = ((e) => handler(e.detail));\n            let set = listeners.get(event);\n            if (!set) {\n                set = new Set();\n                listeners.set(event, set);\n            }\n            set.add(wrapped);\n            window.addEventListener(event, wrapped);\n            return () => {\n                window.removeEventListener(event, wrapped);\n                listeners.get(event)?.delete(wrapped);\n            };\n        },\n        off(event) {\n            const remove = (name, handlers) => {\n                handlers.forEach((h) => window.removeEventListener(name, h));\n            };\n            if (event) {\n                const handlers = listeners.get(event);\n                if (handlers)\n                    remove(event, handlers);\n                listeners.delete(event);\n            }\n            else {\n                listeners.forEach((handlers, name) => remove(name, handlers));\n                listeners.clear();\n            }\n        },\n    };\n}\n/** In-memory event bus — for React Native or testing. */\nexport function createCallbackEventBus() {\n    const listeners = new Map();\n    return {\n        emit(event, payload) {\n            listeners.get(event)?.forEach((handler) => handler(payload));\n        },\n        on(event, handler) {\n            let set = listeners.get(event);\n            if (!set) {\n                set = new Set();\n                listeners.set(event, set);\n            }\n            const typed = handler;\n            set.add(typed);\n            return () => {\n                listeners.get(event)?.delete(typed);\n            };\n        },\n        off(event) {\n            if (event) {\n                listeners.delete(event);\n            }\n            else {\n                listeners.clear();\n            }\n        },\n    };\n}\n","/**\n * Clock port — injectable time and timers.\n *\n * The widget's UX-critical logic is timing logic (typing-indicator minimum\n * duration, chat-widget grace buffering). Routing all time access through\n * this port makes that logic deterministic under test.\n */\nexport function createSystemClock() {\n    return {\n        now() {\n            return Date.now();\n        },\n        setTimeout(fn, ms) {\n            return setTimeout(fn, ms);\n        },\n        clearTimeout(handle) {\n            clearTimeout(handle);\n        },\n    };\n}\n","/**\n * Small platform ports — capabilities core needs but cannot implement\n * portably. Web and React Native each provide implementations.\n */\n/** No-op defaults for platforms/tests that don't wire these up */\nexport const grantedMicPermission = {\n    isGranted: async () => true,\n    request: async () => true,\n};\nexport const silentNotificationPlayer = {\n    play: () => { },\n};\n","/**\n * API client for the Ringg backend.\n * Pure fetch-based — works in any JS runtime (browser, Node, React Native).\n * URLs are always injected by the platform entry point via a UrlResolver;\n * core embeds no endpoints.\n */\nexport function createStaticUrlResolver(urls) {\n    return {\n        resolve(mode) {\n            return urls[mode];\n        },\n    };\n}\nexport function createRinggApiClient(config) {\n    const { backendUrl, livekitUrl } = config.urlResolver.resolve(config.mode);\n    const authHeaders = config.authorization\n        ? { Authorization: config.authorization }\n        : config.xApiKey\n            ? { \"X-API-KEY\": config.xApiKey }\n            : {};\n    // Only present when the caller supplied one. A browser refuses to let us set\n    // `Origin` at all, so web must leave `clientOrigin` unset and let the\n    // platform attach the real thing.\n    const originHeader = config.clientOrigin ? { Origin: config.clientOrigin } : {};\n    const headers = () => ({ \"Content-Type\": \"application/json\", ...originHeader, ...authHeaders });\n    return {\n        backendUrl,\n        livekitUrl,\n        async startWebcall(params) {\n            const response = await fetch(`${backendUrl}/calling/webcall`, {\n                method: \"POST\",\n                body: JSON.stringify({\n                    agent_id: params.agentId,\n                    custom_args_values: params.variables,\n                    media_type: params.mediaType,\n                    // Marks this call as coming from the v2 embed so the backend can use\n                    // the newer endpoint; absent on older embeds, which fall back.\n                    embed_version: \"v2\",\n                }),\n                headers: headers(),\n            });\n            // Read as text first, then parse — a non-JSON error page shouldn't crash\n            // the widget with a cryptic JSON parse error.\n            const responseText = await response.text();\n            let data;\n            try {\n                data = JSON.parse(responseText);\n            }\n            catch {\n                throw new Error(responseText.slice(0, 200) || `Request failed with status ${response.status}`);\n            }\n            if (!response.ok) {\n                throw new Error(data?.message || \"Failed to make call\");\n            }\n            return {\n                call_id: data.call_id,\n                user_token: data.user_token,\n                enabled_slash_commands: data.enabled_slash_commands,\n            };\n        },\n        async submitFeedback(callId, feedback) {\n            await fetch(`${backendUrl}/calling/${callId}/feedback`, {\n                method: \"POST\",\n                body: JSON.stringify(feedback),\n                headers: headers(),\n            });\n        },\n        async callComponentApi(method, endpoint, payload) {\n            const url = endpoint.startsWith(\"http\") ? endpoint : `${backendUrl}${endpoint}`;\n            const response = await fetch(url, {\n                method,\n                body: method === \"GET\" ? undefined : JSON.stringify(payload),\n                headers: headers(),\n            });\n            // Unchecked parse, same as production — the flow renderer validates shape.\n            return (await response.json());\n        },\n    };\n}\n","/**\n * Gradient-aware style utilities for the widget theme system.\n *\n * CSS `backgroundColor` does not support gradient values — only the\n * `background` shorthand does. These helpers detect whether a color value is\n * a solid hex/rgb or a CSS gradient string, and extract a solid fallback\n * color for surfaces that can't render gradients (borders, React Native).\n *\n * Parsing is deliberately explicit — small named steps instead of regexes —\n * so a bad input can be walked through in a debugger function by function.\n */\nconst GRADIENT_FUNCTIONS = [\"linear-gradient\", \"radial-gradient\", \"conic-gradient\", \"repeating-linear-gradient\", \"repeating-radial-gradient\", \"repeating-conic-gradient\"];\nconst COLOR_FUNCTIONS = [\"rgba\", \"rgb\", \"hsla\", \"hsl\"];\n/** Detect whether a CSS color value is a gradient string. */\nexport function isGradient(color) {\n    const normalized = color.trim().toLowerCase();\n    return GRADIENT_FUNCTIONS.some((fn) => normalized.startsWith(`${fn}(`));\n}\n/**\n * Split a gradient's argument list on top-level commas, respecting nested\n * parentheses: \"135deg, rgb(1, 2, 3), #fff\" → [\"135deg\", \"rgb(1, 2, 3)\", \"#fff\"]\n */\nfunction splitGradientArguments(gradient) {\n    const open = gradient.indexOf(\"(\");\n    const close = gradient.lastIndexOf(\")\");\n    if (open === -1 || close <= open)\n        return [];\n    const body = gradient.slice(open + 1, close);\n    const args = [];\n    let depth = 0;\n    let current = \"\";\n    for (const char of body) {\n        if (char === \"(\")\n            depth++;\n        else if (char === \")\")\n            depth--;\n        if (char === \",\" && depth === 0) {\n            args.push(current.trim());\n            current = \"\";\n        }\n        else {\n            current += char;\n        }\n    }\n    if (current.trim())\n        args.push(current.trim());\n    return args;\n}\nfunction isHexDigit(char) {\n    return (char >= \"0\" && char <= \"9\") || (char >= \"a\" && char <= \"f\") || (char >= \"A\" && char <= \"F\");\n}\n/** \"#f97316 40%\" → \"#f97316\"; rejects malformed hex lengths. */\nfunction takeHexColor(value) {\n    let digits = \"\";\n    for (const char of value.slice(1)) {\n        if (!isHexDigit(char))\n            break;\n        digits += char;\n    }\n    const validLengths = [3, 4, 6, 8];\n    return validLengths.includes(digits.length) ? `#${digits}` : null;\n}\n/** \"rgb(1, 2, 3) 50%\" → \"rgb(1, 2, 3)\" */\nfunction takeColorFunction(value) {\n    const normalized = value.toLowerCase();\n    if (!COLOR_FUNCTIONS.some((fn) => normalized.startsWith(`${fn}(`)))\n        return null;\n    const close = value.indexOf(\")\");\n    return close === -1 ? null : value.slice(0, close + 1);\n}\n/**\n * The color at the start of one gradient argument, or null for non-color\n * arguments like \"135deg\" or \"circle at center\".\n */\nfunction leadingColor(argument) {\n    const value = argument.trim();\n    if (value.startsWith(\"#\"))\n        return takeHexColor(value);\n    return takeColorFunction(value);\n}\n/** Extract all color stops from a gradient string, in order. */\nexport function extractColorsFromGradient(gradient) {\n    if (!isGradient(gradient))\n        return [];\n    return splitGradientArguments(gradient)\n        .map(leadingColor)\n        .filter((color) => color !== null);\n}\n/**\n * Return the dominant (first) color from a gradient, or the color as-is for\n * solid values. Falls back to the original string if no colors can be extracted.\n */\nexport function getDominantColor(color) {\n    if (!isGradient(color))\n        return color;\n    return extractColorsFromGradient(color)[0] ?? color;\n}\n/**\n * Determine the correct CSS properties for a background color.\n * Returns `{ backgroundColor }` for solid colors, `{ background }` for gradients.\n * On React Native, gradients aren't natively supported — use `getDominantColor()`\n * to fall back to a solid color.\n */\nexport function colorToBackground(color) {\n    if (isGradient(color)) {\n        return { background: color };\n    }\n    return { backgroundColor: color };\n}\n/**\n * Always return a solid hex/rgb color string. Use for properties that don't\n * support gradients: border, box-shadow, accent-color.\n */\nexport function colorToSolid(color) {\n    return getDominantColor(color);\n}\n/**\n * Return the correct CSS properties for a border color.\n * Solid colors -> `{ borderColor }`, gradients -> `{ borderImage, borderStyle }`.\n */\nexport function colorToBorder(color) {\n    if (isGradient(color)) {\n        return {\n            borderImage: `${color} 1`,\n            borderStyle: \"solid\",\n        };\n    }\n    return { borderColor: color };\n}\n","/**\n * Theme engine — resolves, merges, and provides theme values.\n * Pure functions with no framework dependency.\n *\n * Default and preset theme VALUES live in tokens/tokens.json (shared across\n * all implementations via codegen) — only merging/contrast LOGIC lives here.\n */\nimport { DEFAULT_WIDGET_THEME, WIDGET_PRESET_THEMES } from \"../generated/tokens.js\";\nimport { getDominantColor } from \"./gradient-utils.js\";\nexport { DEFAULT_WIDGET_THEME, WIDGET_PRESET_THEMES };\n// ─── Theme merging ───────────────────────────────────────────────────────────\n/** Merge a partial user theme with the defaults. Returns a fully resolved theme. */\nexport function mergeWidgetTheme(theme) {\n    return { ...DEFAULT_WIDGET_THEME, ...theme };\n}\n/** Merge a component-level theme with the widget theme as fallback. */\nexport function mergeComponentTheme(componentTheme, widgetTheme) {\n    const base = widgetTheme ?? DEFAULT_WIDGET_THEME;\n    return {\n        primaryColor: base.primaryColor,\n        primaryTextColor: base.primaryTextColor,\n        backgroundColor: base.backgroundColor,\n        surfaceColor: base.surfaceColor,\n        textColor: base.textColor,\n        mutedTextColor: base.mutedTextColor,\n        borderColor: base.borderColor,\n        errorColor: base.errorColor,\n        successColor: base.successColor,\n        fontFamily: base.fontFamily,\n        borderRadius: base.borderRadius,\n        buttonStyle: base.buttonStyle,\n        ...componentTheme,\n    };\n}\n// ─── Button radius ───────────────────────────────────────────────────────────\n/** Get button border radius based on style */\nexport function getButtonRadius(style) {\n    switch (style) {\n        case \"pill\":\n            return \"9999px\";\n        case \"square\":\n            return \"6px\";\n        case \"rounded\":\n        default:\n            return \"12px\";\n    }\n}\n// ─── Color contrast ──────────────────────────────────────────────────────────\n/**\n * Calculate relative luminance of a color.\n * Handles both solid hex colors and gradient strings (uses dominant color).\n */\nfunction getLuminance(hexColor) {\n    const solid = getDominantColor(hexColor);\n    const hex = solid.replace(\"#\", \"\");\n    const r = parseInt(hex.slice(0, 2), 16) / 255;\n    const g = parseInt(hex.slice(2, 4), 16) / 255;\n    const b = parseInt(hex.slice(4, 6), 16) / 255;\n    const toLinear = (c) => (c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));\n    return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\n/** Check if a color is considered \"light\" (for auto-contrast) */\nexport function isLightColor(hexColor) {\n    try {\n        return getLuminance(hexColor) > 0.5;\n    }\n    catch {\n        return true;\n    }\n}\n/** Get a contrasting text color (black or white) for a given background */\nexport function getContrastingTextColor(bgColor) {\n    return isLightColor(bgColor) ? \"#212121\" : \"#ffffff\";\n}\n","/**\n * RPC message formatting — transforms between backend RPC format and internal\n * component format.\n *\n * The backend sends `send_dynamic_data` RPCs like:\n *   { component_type: \"render_component_calendar\", component_config: { ... } }\n * The widget needs them in the internal format:\n *   { component_type: \"calendar_booking\", component_id: \"calendar_1234\", data: { ... } }\n *\n * This module handles both directions.\n */\n// ─── Backend -> widget ───────────────────────────────────────────────────────\n/**\n * Transform a backend RPC payload into the internal component format.\n * Returns null if the component type is unknown.\n */\nexport function transformRpcToComponent(componentName, rpcPayload) {\n    const componentId = `${componentName}_${Date.now()}`;\n    // Legacy senders put the config under component_data — accept both, like production.\n    const config = rpcPayload.component_config ?? rpcPayload.component_data;\n    switch (componentName) {\n        case \"calendar\":\n            return transformCalendar(componentId, config, rpcPayload);\n        case \"form\":\n            return transformForm(componentId, config);\n        case \"buttons\":\n            return transformButtons(componentId, config, rpcPayload);\n        case \"quick_replay\":\n            return transformQuickReplay(componentId, config);\n        case \"confirmation\":\n            return transformConfirmation(componentId, rpcPayload);\n        default:\n            // Already in the internal format — pass through.\n            if (rpcPayload.component_type && rpcPayload.component_id) {\n                return rpcPayload;\n            }\n            return null;\n    }\n}\nfunction transformCalendar(componentId, config, rpcPayload) {\n    const configObj = config;\n    const slots = configObj?.slots || [];\n    const timezone = configObj?.timezone || \"UTC\";\n    return {\n        component_type: \"calendar_booking\",\n        component_id: componentId,\n        data: {\n            available_slots: slots.map((slot) => ({ id: slot.id, datetime: slot.datetime })),\n            timezone,\n            title: rpcPayload.title || \"Select a time slot\",\n        },\n    };\n}\nfunction transformForm(componentId, config) {\n    const configObj = config;\n    const transformedFields = (configObj?.fields || []).map((field) => ({\n        name: field.key || field.name || \"\",\n        type: mapFieldType(field.type),\n        label: field.description || field.label || field.key || field.name || \"\",\n        required: field.required,\n        placeholder: field.placeholder,\n        options: field.options,\n    }));\n    return {\n        component_type: \"form\",\n        component_id: componentId,\n        data: {\n            title: configObj?.title || \"Form\",\n            description: configObj?.description,\n            fields: transformedFields,\n            submit_label: configObj?.cta || configObj?.submit_label || \"Submit\",\n        },\n    };\n}\nfunction transformButtons(componentId, config, rpcPayload) {\n    return {\n        component_type: \"buttons\",\n        component_id: componentId,\n        data: {\n            title: rpcPayload.title,\n            buttons: Array.isArray(config) ? config : [],\n        },\n    };\n}\n/**\n * Quick replies render as free-standing chips (no boxed card) and, once picked,\n * show the selection as a user bubble instead of a confirmation card.\n */\nfunction transformQuickReplay(componentId, config) {\n    const configObj = config;\n    const options = Array.isArray(configObj?.options) ? configObj.options.filter((option) => typeof option === \"string\" && option.trim().length > 0) : [];\n    return {\n        component_type: \"buttons\",\n        component_id: componentId,\n        data: {\n            presentation: \"free\",\n            completionDisplay: \"selected_item\",\n            buttons: options.map((option) => ({\n                id: option,\n                label: option,\n                action: { type: \"trigger_component\" },\n            })),\n        },\n    };\n}\nfunction transformConfirmation(componentId, rpcPayload) {\n    return {\n        component_type: \"confirmation\",\n        component_id: componentId,\n        data: {\n            title: rpcPayload.title || \"Confirmed\",\n            message: rpcPayload.message || \"\",\n            icon: rpcPayload.icon || \"success\",\n            details: rpcPayload.details,\n        },\n    };\n}\n/** Map backend field type strings to internal FormFieldType */\nfunction mapFieldType(backendType) {\n    const typeMap = {\n        text: \"text\",\n        string: \"text\",\n        number: \"number\",\n        email: \"email\",\n        phone_number: \"tel\",\n        single_select: \"select\",\n        multiselect: \"multiselect\",\n        checkbox: \"boolean\",\n        date: \"date\",\n        textarea: \"textarea\",\n    };\n    return typeMap[backendType] || \"text\";\n}\nconst RECEIVE_RPC_METHOD = \"receive_dynamic_data\";\n/**\n * Format a component response payload for sending back to the backend via RPC.\n * Used when the user interacts with a component (selects a slot, submits a\n * form, taps a button).\n */\nexport function formatComponentResponse(componentName, componentId, responseData, originalConfig) {\n    let componentData;\n    const stepData = responseData.step_data;\n    if (componentName === \"calendar\") {\n        const slotId = stepData?.slot_id;\n        const configObj = originalConfig;\n        const slots = configObj?.slots || [];\n        const timezone = configObj?.timezone || \"UTC\";\n        const selectedSlot = slots.find((slot) => slot.id === slotId);\n        componentData = {\n            id: selectedSlot?.id || slotId,\n            datetime: selectedSlot?.datetime || stepData?.slot_datetime,\n            timezone,\n            slot_time: stepData?.slot_time,\n            slot_date: stepData?.slot_date,\n        };\n    }\n    else if (componentName === \"form\") {\n        componentData = responseData.step_data || responseData.all_data;\n    }\n    else if (componentName === \"buttons\") {\n        const buttonId = stepData?.selected_button;\n        const buttons = Array.isArray(originalConfig) ? originalConfig : [];\n        const selectedButton = buttons.find((btn) => btn.id === buttonId);\n        componentData = selectedButton || { id: buttonId };\n    }\n    else if (componentName === \"quick_replay\") {\n        componentData = { text: stepData?.selected_button };\n    }\n    else {\n        componentData = responseData;\n    }\n    // Echo the render payload's tool_id when present.\n    const toolId = originalConfig?.tool_id;\n    return {\n        method: RECEIVE_RPC_METHOD,\n        payload: JSON.stringify({\n            component_type: `receive_component_${componentName}`,\n            component_id: componentId,\n            component_data: componentData,\n            ...(toolId && { tool_id: toolId }),\n        }),\n    };\n}\n/** Format a slash command for sending via RPC. */\nexport function formatSlashCommand(command) {\n    return {\n        method: RECEIVE_RPC_METHOD,\n        payload: JSON.stringify({\n            component_type: \"receive_component_slash_command\",\n            command: command.replace(/^\\//, \"\"),\n        }),\n    };\n}\n/**\n * Format a Block Kit interaction for the agent. Envelope mirrors the dashboard\n * test widget the bot bridge was tested against: `component_id` and `values`\n * are always present; `tool_id` is omitted when falsy and `value` when\n * undefined (never sent as null/empty keys).\n */\nexport function formatBlocksAction(toolId, componentId, action) {\n    return {\n        method: RECEIVE_RPC_METHOD,\n        payload: JSON.stringify({\n            component_type: \"receive_component_blocks\",\n            component_id: componentId,\n            ...(toolId && { tool_id: toolId }),\n            component_data: {\n                action_id: action.action_id,\n                ...(action.value !== undefined && { value: action.value }),\n                values: action.values,\n            },\n        }),\n    };\n}\n/**\n * Format a raw dynamic-data payload (client packs: disease search/submit).\n * The payload already carries its own `component_type` envelope.\n */\nexport function formatDynamicData(payload) {\n    return {\n        method: RECEIVE_RPC_METHOD,\n        payload: JSON.stringify(payload),\n    };\n}\n","/**\n * Base store — the one state-sharing primitive in core.\n *\n * Platform bindings stay thin because they all consume the same shape:\n *   web (Lit):  subscribe(() => this.host.requestUpdate())\n *   RN (React): useSyncExternalStore(store.subscribe, store.getSnapshot)\n *\n * Snapshots must be immutable values — stores rebuild them on change so\n * reference equality is a valid dirty check. `getSnapshot`/`subscribe` are\n * closures, so they stay bound when bindings pass them unbound (React:\n * `useSyncExternalStore(store.subscribe, store.getSnapshot)`).\n */\nexport function createStore(build) {\n    const listeners = new Set();\n    let snapshot = build();\n    return {\n        getSnapshot: () => snapshot,\n        subscribe(listener) {\n            listeners.add(listener);\n            return () => {\n                listeners.delete(listener);\n            };\n        },\n        commit() {\n            snapshot = build();\n            listeners.forEach((listener) => listener(snapshot));\n        },\n        dispose() {\n            listeners.clear();\n        },\n    };\n}\n","/**\n * Shell store — widget open/close/feedback lifecycle and the active call id.\n * Ported from the alpha WidgetStateController; emits `ringg:widget_status`\n * host events on visibility transitions.\n */\nimport { createStore } from \"./store.js\";\nexport function createShellStore(eventBus, initialCallMode = \"audio\", \n// Permanently-expanded (embedded) widget: starts open, and minimize/close\n// keep the panel on screen — there is no trigger to reopen it from.\ndefaultExpanded = false) {\n    // Two independent flags, exactly like the production useWidgetState hook:\n    // minimizing must NOT forget a pending feedback screen — reopening shows it\n    // again until it is submitted or skipped (which go through close()).\n    let isOpen = defaultExpanded;\n    let feedbackPending = false;\n    let currentCallId = null;\n    let callMode = initialCallMode;\n    const buildViewState = () => {\n        if (!isOpen)\n            return \"closed\";\n        return feedbackPending ? \"feedback\" : \"open\";\n    };\n    const build = () => ({ viewState: buildViewState(), currentCallId, callMode });\n    const handle = createStore(build);\n    const store = {\n        getSnapshot: handle.getSnapshot,\n        subscribe: handle.subscribe,\n        dispose: handle.dispose,\n        get isOpen() {\n            return isOpen;\n        },\n        get isShowingFeedback() {\n            return feedbackPending;\n        },\n        open() {\n            // No-op while already visible. A pending feedback flag survives here, so\n            // the controller's endCall sequence (showFeedback() then open()) and a\n            // minimize → reopen both land on the feedback view.\n            if (isOpen)\n                return;\n            isOpen = true;\n            eventBus.emit(\"ringg:widget_status\", { status: \"maximised\", mode: callMode });\n            handle.commit();\n        },\n        minimize() {\n            // A permanently-expanded widget has no trigger to reopen from — hiding\n            // the panel would strand the user, so minimize is a full no-op (no state\n            // change, no \"minimised\" event), matching the production hook.\n            if (defaultExpanded)\n                return;\n            if (!isOpen)\n                return;\n            // Deliberately keeps feedbackPending: reopening restores the feedback view.\n            isOpen = false;\n            eventBus.emit(\"ringg:widget_status\", { status: \"minimised\", mode: callMode });\n            handle.commit();\n        },\n        close() {\n            feedbackPending = false;\n            currentCallId = null;\n            // defaultExpanded: the panel stays visible (and no \"minimised\" event) —\n            // only the feedback/call state resets, as in the production hook where\n            // close() delegates to a no-op minimize().\n            if (!defaultExpanded) {\n                isOpen = false;\n                eventBus.emit(\"ringg:widget_status\", { status: \"minimised\", mode: callMode });\n            }\n            handle.commit();\n        },\n        toggle() {\n            if (isOpen) {\n                store.minimize();\n            }\n            else {\n                store.open();\n            }\n        },\n        showFeedback() {\n            feedbackPending = true;\n            handle.commit();\n        },\n        setCallMode(mode) {\n            if (callMode === mode)\n                return;\n            callMode = mode;\n            handle.commit();\n        },\n        setCurrentCallId(callId) {\n            currentCallId = callId;\n            handle.commit();\n        },\n    };\n    return store;\n}\n","/**\n * Session store — the call lifecycle state machine.\n *\n *   idle → starting → live-optimistic → connected → idle\n *\n * \"live-optimistic\" is load-bearing UX (lifted from production): the flag\n * flips the moment /calling/webcall succeeds — before transport.connect()\n * resolves. The call exists server-side at that point, so the calling layout\n * mounts one HTTP round trip after Start instead of waiting out the LiveKit\n * handshake. A connect failure rolls it back so the start screen (with the\n * error) returns instead of a dead calling layout.\n */\nimport { createStore } from \"./store.js\";\nconst NO_ERROR = { hasError: false, message: \"\" };\n/** Verbatim production copy (use-microphone-permission.ts request() denial). */\nconst MIC_DENIED_MESSAGE = \"Microphone access was denied. Please enable it in your browser settings.\";\n/** Verbatim production copy (RoomEvent.MediaDevicesError handler). */\nconst MEDIA_DEVICES_ERROR_MESSAGE = \"Error acquiring microphone permission. Please make sure you grant the necessary permissions in your browser and reload the tab\";\nexport function createSessionStore(api, transport, mic) {\n    let phase = \"idle\";\n    let isLoading = false;\n    let connectionState = \"disconnected\";\n    let error = NO_ERROR;\n    const computeIsSessionLive = () => phase === \"live-optimistic\" || phase === \"connected\";\n    const build = () => ({\n        phase,\n        isLoading,\n        isSessionLive: computeIsSessionLive(),\n        connectionState,\n        error,\n    });\n    const handle = createStore(build);\n    transport.onConnectionStateChange((state) => {\n        connectionState = state;\n        if (state === \"connected\" && phase !== \"idle\")\n            phase = \"connected\";\n        handle.commit();\n    });\n    // Mic acquisition failing after connect (permission revoked, device gone) —\n    // production surfaces this via RoomEvent.MediaDevicesError → setError.\n    transport.onMediaDevicesError(() => {\n        error = { hasError: true, message: MEDIA_DEVICES_ERROR_MESSAGE };\n        handle.commit();\n    });\n    return {\n        getSnapshot: handle.getSnapshot,\n        subscribe: handle.subscribe,\n        dispose: handle.dispose,\n        get isSessionLive() {\n            return computeIsSessionLive();\n        },\n        prewarm() {\n            void transport.prepareConnection(api.livekitUrl).catch(() => { });\n        },\n        async start(params) {\n            if (params.mediaType === \"audio\" && !(await mic.isGranted())) {\n                if (!(await mic.request())) {\n                    // Denial must not be silent: production's mic.onError puts this\n                    // message on the start screen (use-microphone-permission.ts).\n                    error = { hasError: true, message: MIC_DENIED_MESSAGE };\n                    handle.commit();\n                    return null;\n                }\n            }\n            isLoading = true;\n            phase = \"starting\";\n            handle.commit();\n            try {\n                const response = await api.startWebcall({\n                    agentId: params.agentId,\n                    variables: params.variables,\n                    mediaType: params.mediaType,\n                });\n                // Call exists server-side — mount the calling layout now.\n                phase = \"live-optimistic\";\n                error = NO_ERROR;\n                handle.commit();\n                await transport.connect(api.livekitUrl, response.user_token);\n                if (params.mediaType === \"audio\")\n                    await transport.setMicrophoneEnabled(true);\n                return {\n                    callId: response.call_id,\n                    slashCommands: response.enabled_slash_commands ?? [],\n                };\n            }\n            catch (err) {\n                // Roll the optimistic flip back — see module docs.\n                phase = \"idle\";\n                error = { hasError: true, message: err.message };\n                handle.commit();\n                return null;\n            }\n            finally {\n                isLoading = false;\n                handle.commit();\n            }\n        },\n        async end() {\n            isLoading = true;\n            handle.commit();\n            try {\n                await transport.disconnect();\n            }\n            catch {\n                // Disconnect failures don't block teardown.\n            }\n            finally {\n                phase = \"idle\";\n                isLoading = false;\n                handle.commit();\n            }\n        },\n        clearError() {\n            error = NO_ERROR;\n            handle.commit();\n        },\n    };\n}\n","/**\n * Message store — the single ordered conversation timeline.\n *\n * Three sources feed it and must interleave correctly:\n * - chat messages (text mode, incl. the local optimistic echo)\n * - transcription segments (audio mode; segments UPDATE in place by id as STT\n *   refines, keeping their original position)\n * - component messages (RPC widgets, Block Kit — commit-time stamped so a\n *   buffered widget sorts strictly after the agent message that released it)\n *\n * Ordering: entries sort by timestamp. The store hands out strictly\n * monotonically increasing timestamps (sub-ms bumped when the clock hasn't\n * advanced), replacing the production widget's `Date.now() + Math.random()`\n * collision-avoidance hacks with a deterministic policy.\n */\nimport { createStore } from \"./store.js\";\nconst MONOTONIC_BUMP = 0.001;\nexport function createMessageStore(clock) {\n    /** Committed messages: chat, components, selection bubbles */\n    let entries = [];\n    /** Live transcription segments keyed by segment id */\n    const transcripts = new Map();\n    /** RAG source URL waiting to attach to the next agent reply */\n    let pendingSourceUrl = \"\";\n    let lastTimestamp = 0;\n    const build = () => {\n        const merged = [...transcripts.values(), ...entries].sort((a, b) => a.timestamp - b.timestamp);\n        return { messages: merged };\n    };\n    const handle = createStore(build);\n    const store = {\n        getSnapshot: handle.getSnapshot,\n        subscribe: handle.subscribe,\n        dispose: handle.dispose,\n        nextTimestamp() {\n            const now = clock.now();\n            lastTimestamp = now > lastTimestamp ? now : lastTimestamp + MONOTONIC_BUMP;\n            return lastTimestamp;\n        },\n        addChatMessage(params) {\n            const sourceUrl = !params.isSelf && pendingSourceUrl ? pendingSourceUrl : undefined;\n            if (sourceUrl)\n                pendingSourceUrl = \"\";\n            const msg = {\n                name: params.name ?? (params.isSelf ? \"You\" : \"Agent\"),\n                message: params.message,\n                isSelf: params.isSelf,\n                timestamp: params.timestamp ?? store.nextTimestamp(),\n                ...(sourceUrl && { sourceUrl }),\n            };\n            entries.push(msg);\n            handle.commit();\n            return msg;\n        },\n        addComponent(component) {\n            const msg = {\n                name: \"Agent\",\n                message: \"\",\n                isSelf: false,\n                timestamp: store.nextTimestamp(),\n                componentType: component.component_type,\n                componentData: component,\n            };\n            entries.push(msg);\n            handle.commit();\n            return msg;\n        },\n        addSystemLog(params) {\n            entries.push({\n                name: \"system\",\n                message: params.label,\n                isSelf: false,\n                timestamp: store.nextTimestamp(),\n                kind: \"system\",\n                ...(params.meta && { systemMeta: params.meta }),\n                systemLevel: params.level,\n            });\n            handle.commit();\n        },\n        addLocalSelection(componentId, label) {\n            const prompt = entries.find((m) => m.componentData?.component_id === componentId);\n            const anchor = prompt ? prompt.timestamp + MONOTONIC_BUMP / 2 : store.nextTimestamp();\n            entries.push({ name: \"You\", isSelf: true, message: label, timestamp: anchor });\n            handle.commit();\n        },\n        upsertTranscription(segment) {\n            const existing = transcripts.get(segment.id);\n            transcripts.set(segment.id, {\n                name: segment.participantName ?? (segment.isLocal ? \"You\" : \"Agent\"),\n                message: segment.text,\n                isSelf: segment.isLocal,\n                timestamp: existing?.timestamp ?? store.nextTimestamp(),\n                ...(existing?.sourceUrl && { sourceUrl: existing.sourceUrl }),\n            });\n            // Voice-mode RAG citations (App.tsx:1094-1118): a pending send_source_urls\n            // value appends to the LAST transcription when that is an agent segment\n            // without a URL yet. Whether it appended or not, the pending value is\n            // consumed — production clears the ref on every update that doesn't\n            // append, and the append itself is once-only (index guard + !sourceUrl).\n            if (pendingSourceUrl) {\n                let newestId;\n                let newest;\n                for (const [id, msg] of transcripts) {\n                    if (!newest || msg.timestamp >= newest.timestamp) {\n                        newest = msg;\n                        newestId = id;\n                    }\n                }\n                if (newest && newestId !== undefined && !newest.isSelf && !newest.sourceUrl) {\n                    transcripts.set(newestId, { ...newest, sourceUrl: pendingSourceUrl });\n                }\n                pendingSourceUrl = \"\";\n            }\n            handle.commit();\n        },\n        setPendingSourceUrl(url) {\n            pendingSourceUrl = url;\n        },\n        clearPendingSourceUrl() {\n            pendingSourceUrl = \"\";\n        },\n        reset() {\n            entries = [];\n            transcripts.clear();\n            pendingSourceUrl = \"\";\n            handle.commit();\n        },\n    };\n    return store;\n}\n","/**\n * Timing constants — every value encodes a UX bug that was found and fixed in\n * the production widget. Values live in tokens/defaults.json (shared across\n * all implementations via codegen); change them there, never here.\n */\nimport { TIMING } from \"./generated/tokens.js\";\n/** Chat-widget RPCs land before the agent's text streams in; buffer them this\n * long waiting for the text so the widget sorts below it. */\nexport const CHAT_WIDGET_GRACE_MS = TIMING.chatWidgetGraceMs;\n/** Once the agent text lands, release buffered widgets after this beat so the\n * message paints first. */\nexport const CHAT_WIDGET_AFTER_TEXT_MS = TIMING.chatWidgetAfterTextMs;\n/** Keep the typing dots visible at least this long — instant replies\n * otherwise make the indicator flash. */\nexport const MIN_TYPING_INDICATOR_MS = TIMING.minTypingIndicatorMs;\n","/**\n * Typing store — drives the \"agent is typing\" indicator (text mode).\n *\n * Behavior lifted from the production widget:\n * - Dots appear the moment the user sends (we always expect a reply); the\n *   min-duration timer anchors only when they first appear, so back-to-back\n *   sends keep one continuous indicator instead of resetting it.\n * - Any landed backend response — text or RPC — answers the pending turn and\n *   drops the dots, unconditionally.\n * - Replies that land faster than MIN_TYPING_INDICATOR_MS wait out the\n *   remainder before committing, otherwise the indicator just flashes.\n */\nimport { createStore } from \"./store.js\";\nimport { MIN_TYPING_INDICATOR_MS } from \"../constants.js\";\nexport function createTypingStore(clock) {\n    let shownAt = null;\n    let isTyping = false;\n    const build = () => ({ isTyping });\n    const handle = createStore(build);\n    const set = (next) => {\n        if (isTyping === next)\n            return;\n        isTyping = next;\n        handle.commit();\n    };\n    return {\n        getSnapshot: handle.getSnapshot,\n        subscribe: handle.subscribe,\n        dispose: handle.dispose,\n        showOnUserSend() {\n            if (shownAt === null)\n                shownAt = clock.now();\n            set(true);\n        },\n        clear() {\n            shownAt = null;\n            set(false);\n        },\n        waitMinDuration() {\n            if (shownAt === null)\n                return Promise.resolve();\n            const remaining = MIN_TYPING_INDICATOR_MS - (clock.now() - shownAt);\n            if (remaining <= 0)\n                return Promise.resolve();\n            return new Promise((resolve) => clock.setTimeout(resolve, remaining));\n        },\n    };\n}\n","/**\n * Component store — interactive components pushed by the backend mid-call.\n *\n * Chat-mode anchoring (lifted from production): widget RPCs land instantly\n * while the agent's text streams a beat later. In text mode we buffer the\n * widget until the accompanying message lands, then commit it right after so\n * it sorts below. If no message arrives within CHAT_WIDGET_GRACE_MS, flush\n * anyway. Audio mode commits immediately.\n *\n * Also owns the response side: which components still await a user response\n * (and the original config needed to format it), completed flows, and the\n * extension registry that lets client packs handle domain-specific\n * `send_dynamic_data` component types without polluting core.\n */\nimport { createStore } from \"./store.js\";\nimport { CHAT_WIDGET_GRACE_MS, CHAT_WIDGET_AFTER_TEXT_MS } from \"../constants.js\";\nexport function createComponentStore(clock, \n/** Commits a component to the timeline — wired to MessageStore + host events by the controller */\ncommitComponent) {\n    let pendingChatWidgets = [];\n    let graceTimer = null;\n    const pendingResponses = new Map();\n    const completedFlowIds = new Set();\n    let extensions = [];\n    const build = () => ({ completedFlowIds: new Set(completedFlowIds) });\n    const handle = createStore(build);\n    const store = {\n        getSnapshot: handle.getSnapshot,\n        subscribe: handle.subscribe,\n        dispose: handle.dispose,\n        add(component, mode) {\n            if (mode !== \"text\") {\n                commitComponent(component);\n                return;\n            }\n            pendingChatWidgets.push(component);\n            if (!graceTimer) {\n                graceTimer = clock.setTimeout(() => store.flush(), CHAT_WIDGET_GRACE_MS);\n            }\n        },\n        onAgentTextLanded() {\n            if (pendingChatWidgets.length > 0) {\n                clock.setTimeout(() => store.flush(), CHAT_WIDGET_AFTER_TEXT_MS);\n            }\n        },\n        flush() {\n            if (graceTimer) {\n                clock.clearTimeout(graceTimer);\n                graceTimer = null;\n            }\n            const queued = pendingChatWidgets;\n            pendingChatWidgets = [];\n            queued.forEach((component) => commitComponent(component));\n        },\n        // ─── Response tracking ─────────────────────────────────────────────────────\n        trackPendingResponse(componentId, pending) {\n            pendingResponses.set(componentId, pending);\n        },\n        takePendingResponse(componentId) {\n            const pending = pendingResponses.get(componentId);\n            if (pending)\n                pendingResponses.delete(componentId);\n            return pending;\n        },\n        markFlowComplete(componentId) {\n            completedFlowIds.add(componentId);\n            handle.commit();\n        },\n        // ─── Extensions ────────────────────────────────────────────────────────────\n        registerExtension(extension) {\n            extensions.push(extension);\n            return () => {\n                extensions = extensions.filter((e) => e !== extension);\n            };\n        },\n        runExtensions(componentName, parsed) {\n            return extensions.some((extension) => extension(componentName, parsed));\n        },\n        // ─── Lifecycle ─────────────────────────────────────────────────────────────\n        reset() {\n            if (graceTimer) {\n                clock.clearTimeout(graceTimer);\n                graceTimer = null;\n            }\n            pendingChatWidgets = [];\n            pendingResponses.clear();\n            completedFlowIds.clear();\n            handle.commit();\n        },\n    };\n    return store;\n}\n","/**\n * Slash command store — merges commands declared in config with commands the\n * backend enables at webcall time. Config commands win on collisions.\n */\nimport { createStore } from \"./store.js\";\nexport function createSlashCommandStore(configCommands = []) {\n    let runtimeCommands = [];\n    const build = () => {\n        const seen = new Set(configCommands.map((c) => c.command));\n        const merged = [...configCommands];\n        for (const cmd of runtimeCommands) {\n            if (!seen.has(cmd.command))\n                merged.push(cmd);\n        }\n        return { commands: merged };\n    };\n    const handle = createStore(build);\n    return {\n        getSnapshot: handle.getSnapshot,\n        subscribe: handle.subscribe,\n        dispose: handle.dispose,\n        setRuntimeCommands(commands) {\n            runtimeCommands = commands;\n            handle.commit();\n        },\n        reset() {\n            runtimeCommands = [];\n            handle.commit();\n        },\n    };\n}\n","/**\n * RinggWidgetController — the composition root of the widget brain.\n *\n * Owns every store, wires transport events into them, and exposes the\n * imperative API the platform UIs call. This is the headless replacement for\n * the production widget's App.tsx orchestration: platform bindings render\n * snapshots and forward user intents; ALL behavior lives here or in the\n * stores.\n */\nimport { createRinggApiClient } from \"./api/client.js\";\nimport { createSystemClock } from \"./ports/clock.js\";\nimport { grantedMicPermission, silentNotificationPlayer } from \"./ports/platform.js\";\nimport { createCallbackEventBus } from \"./ports/event-bus.js\";\nimport { createMessageStore } from \"./stores/message-store.js\";\nimport { createTypingStore } from \"./stores/typing-store.js\";\nimport { createComponentStore } from \"./stores/component-store.js\";\nimport { createSlashCommandStore } from \"./stores/slash-command-store.js\";\nimport { createSessionStore } from \"./stores/session-store.js\";\nimport { createShellStore } from \"./stores/shell-store.js\";\nimport { mergeWidgetTheme } from \"./theme/theme-engine.js\";\nimport { transformRpcToComponent, formatComponentResponse, formatSlashCommand, formatBlocksAction, formatDynamicData } from \"./rpc/formatter.js\";\nimport { DEFAULT_CONFIG } from \"./types/config.js\";\nexport function createRinggWidgetController(config, ports) {\n    const theme = mergeWidgetTheme(config.theme);\n    const eventBus = ports.eventBus ?? createCallbackEventBus();\n    const clock = ports.clock ?? createSystemClock();\n    const notification = ports.notification ?? silentNotificationPlayer;\n    const onDomAction = ports.onDomAction;\n    const transport = ports.transport;\n    const api = createRinggApiClient({\n        urlResolver: ports.urlResolver,\n        mode: config.mode ?? DEFAULT_CONFIG.mode,\n        xApiKey: config.xApiKey,\n        authorization: config.authorization,\n        clientOrigin: config.clientOrigin,\n    });\n    const shell = createShellStore(eventBus, config.defaultTab ?? DEFAULT_CONFIG.defaultTab, config.defaultExpanded ?? DEFAULT_CONFIG.defaultExpanded);\n    const session = createSessionStore(api, transport, ports.micPermission ?? grantedMicPermission);\n    const messages = createMessageStore(clock);\n    const typing = createTypingStore(clock);\n    const slashCommands = createSlashCommandStore(config.enabledSlashCommands);\n    const components = createComponentStore(clock, (component) => commitComponent(component));\n    const unsubscribers = [];\n    // ParticipantDisconnected AND Disconnected both funnel into endCall (the\n    // transport's onSessionEnded fires for either, and livekit emits Disconnected\n    // synchronously inside room.disconnect() while endCall is still awaiting), so\n    // the \"ended\" host event needs the same once-per-conversation guard as\n    // production's conversationEndedDispatched ref (App.tsx:259-264).\n    let conversationEndedDispatched = false;\n    // Inline chat pills for DOM-action/system events (App.tsx:945-967). Off by\n    // default; `eventLogs.showIds` surfaces the action id next to the meta.\n    const eventLogsEnabled = config.eventLogs?.enabled === true;\n    const eventLogsShowIds = config.eventLogs?.showIds === true;\n    const pushSystemLog = (entry) => {\n        if (!eventLogsEnabled)\n            return;\n        const meta = eventLogsShowIds && entry.id ? (entry.meta ? `${entry.id} · ${entry.meta}` : entry.id) : entry.meta;\n        messages.addSystemLog({ label: entry.label, meta, level: entry.level });\n    };\n    // ─── Internal wiring ───────────────────────────────────────────────────────\n    function resetConversation() {\n        messages.reset();\n        components.reset();\n    }\n    function commitComponent(component) {\n        messages.addComponent(component);\n        eventBus.emit(\"ringg:calendar_booking\", { status: \"shown\", componentId: component.component_id });\n        // A rendered component *is* the agent's reply — the turn passes to the\n        // user, so drop the dots.\n        typing.clear();\n        if (!shell.isOpen)\n            notification.play();\n        shell.open();\n    }\n    async function handleAgentTextStream(stream) {\n        // Production registers this handler only while callMode === \"text\" &&\n        // isSessionLive (App.tsx:1129). LiveKit Agents backends publish agent/user\n        // utterances on BOTH the legacy transcription packets and this topic, so\n        // committing these streams during an audio call would render every\n        // utterance twice (live upsert + chat bubble).\n        if (shell.getSnapshot().callMode !== \"text\" || !session.isSessionLive)\n            return;\n        try {\n            const message = await stream.readAll();\n            if (!stream.isAgent) {\n                messages.addChatMessage({ message, isSelf: true, name: \"You\" });\n                // Any landed text-stream message consumes the pending RAG URL —\n                // production clears the ref unconditionally (App.tsx:1159).\n                messages.clearPendingSourceUrl();\n                return;\n            }\n            // Hold the dots up for at least the minimum duration even if the reply\n            // came back fast — otherwise the indicator just flashes.\n            await typing.waitMinDuration();\n            if (!shell.isOpen)\n                notification.play();\n            shell.open();\n            messages.addChatMessage({ message, isSelf: false, name: \"Agent\" });\n            // Any landed reply clears the dots, unconditionally.\n            typing.clear();\n            // Release any widget buffered for this turn so it sorts directly below.\n            components.onAgentTextLanded();\n        }\n        catch {\n            if (stream.isAgent)\n                typing.clear();\n        }\n    }\n    async function handleBlocksStream(stream) {\n        try {\n            const raw = await stream.readAll();\n            typing.clear();\n            const parsed = JSON.parse(raw);\n            if (parsed.component_type !== \"render_component_blocks\" || !Array.isArray(parsed.component_config?.blocks))\n                return;\n            components.add({\n                component_type: \"blocks\",\n                component_id: `blocks_${clock.now()}`,\n                data: parsed.component_config,\n            }, shell.getSnapshot().callMode);\n        }\n        catch {\n            // Malformed blocks payloads are dropped; the conversation continues.\n        }\n    }\n    async function handleDynamicData(invocation) {\n        typing.clear();\n        let parsed;\n        try {\n            parsed = JSON.parse(invocation.payload);\n        }\n        catch {\n            throw new Error(\"Invalid send_dynamic_data payload\");\n        }\n        const componentType = parsed.component_type;\n        if (!componentType) {\n            return JSON.stringify({ status: \"error\", message: \"No component_type provided\" });\n        }\n        // Fire-and-forget host-page action — execute and ack immediately.\n        // Backend payload uses { action_id, event_name, detail }; normalize to the\n        // internal shape exactly like production (App.tsx:986-995): kind defaults\n        // to \"trigger_event\" when absent.\n        if (componentType === \"execute_dom_action\") {\n            const cfg = (parsed.component_config ?? parsed.component_data ?? {});\n            const action = {\n                id: cfg.id ?? cfg.action_id ?? \"\",\n                kind: cfg.kind ?? \"trigger_event\",\n                event_name: cfg.event_name,\n                default_payload: cfg.default_payload ?? cfg.detail,\n            };\n            onDomAction?.(action, pushSystemLog);\n            return JSON.stringify({ status: \"received\" });\n        }\n        const componentName = componentType.replace(\"render_component_\", \"\");\n        // Client packs get first refusal (e.g. disease_search_results).\n        if (components.runExtensions(componentName, parsed)) {\n            return JSON.stringify({ status: \"received\" });\n        }\n        const component = transformRpcToComponent(componentName, parsed);\n        if (!component) {\n            return JSON.stringify({ status: \"error\", message: `Unknown component type: ${componentName}` });\n        }\n        components.trackPendingResponse(component.component_id, {\n            name: componentName,\n            originalConfig: parsed.component_config ?? parsed.component_data,\n        });\n        components.add(component, shell.getSnapshot().callMode);\n        return JSON.stringify({ status: \"received\", component_id: component.component_id });\n    }\n    /**\n     * Legacy `render_component` RPC (production's componentRpcHandler,\n     * App.tsx:789-805): the payload is already in the internal component format\n     * — commit it untouched when component_type && component_id are present.\n     * No transform, no pending-response tracking, and a bare {status:\"received\"}\n     * ack (never a component_id).\n     */\n    async function handleRenderComponent(invocation) {\n        typing.clear();\n        let parsed;\n        try {\n            parsed = JSON.parse(invocation.payload);\n        }\n        catch {\n            throw new Error(\"Invalid component payload\");\n        }\n        if (parsed.component_type && parsed.component_id) {\n            components.add(parsed, shell.getSnapshot().callMode);\n        }\n        return JSON.stringify({ status: \"received\" });\n    }\n    function wireTransport() {\n        transport.registerRpcMethod(\"send_dynamic_data\", (invocation) => handleDynamicData(invocation));\n        // Legacy method name — pre-formatted payloads, committed as-is.\n        transport.registerRpcMethod(\"render_component\", (invocation) => handleRenderComponent(invocation));\n        // RAG citations (App.tsx:775-786): `source_urls` array → ALL urls joined\n        // with \", \"; else the singular `source_url` string. Other keys are ignored\n        // (production never sends them) and malformed JSON rejects the RPC.\n        transport.registerRpcMethod(\"send_source_urls\", async (invocation) => {\n            let parsed;\n            try {\n                parsed = JSON.parse(invocation.payload);\n            }\n            catch {\n                throw new Error(\"Invalid payload for send_source_urls\");\n            }\n            if (Array.isArray(parsed.source_urls))\n                messages.setPendingSourceUrl(parsed.source_urls.join(\", \"));\n            else if (parsed.source_url)\n                messages.setPendingSourceUrl(String(parsed.source_url));\n            return JSON.stringify({ status: \"received\" });\n        });\n        // Agent text replies (text mode). Registered up front — text streams\n        // aren't replayed, so registering only after \"connected\" can drop the\n        // agent's greeting.\n        transport.registerTextStreamHandler(\"lk.transcription\", (stream) => {\n            void handleAgentTextStream(stream);\n        });\n        // Block Kit arrives over a text stream (chunked → no RPC size cap).\n        transport.registerTextStreamHandler(\"ringg.blocks\", (stream) => {\n            void handleBlocksStream(stream);\n        });\n        unsubscribers.push(transport.onChatMessage((message) => {\n            // Local sends are committed optimistically in sendMessage() — an\n            // adapter echoing them anyway must not duplicate the bubble.\n            if (message.isSelf)\n                return;\n            // Incoming chat commits only in text mode (production merges\n            // `chatMessages` inside the callMode === \"text\" && isSessionLive\n            // effect only — App.tsx:1129, 1187-1206).\n            if (shell.getSnapshot().callMode !== \"text\" || !session.isSessionLive)\n                return;\n            messages.addChatMessage({ message: message.message, isSelf: false, name: message.senderName });\n            if (message.isAgent)\n                typing.clear();\n        }), transport.onTranscription((segment) => {\n            // Transcription packets merge only during a connected audio call\n            // (App.tsx:1074) — text mode renders the lk.transcription streams\n            // instead, and both channels carry the same utterances.\n            const { callMode } = shell.getSnapshot();\n            if (callMode !== \"audio\" || session.getSnapshot().connectionState !== \"connected\")\n                return;\n            messages.upsertTranscription(segment);\n        }), transport.onSessionEnded(() => {\n            // Remote hangup / room drop — same path as the user ending the call.\n            if (session.isSessionLive)\n                void controller.endCall();\n        }));\n    }\n    const controller = {\n        config,\n        theme,\n        eventBus,\n        shell,\n        session,\n        messages,\n        typing,\n        components,\n        slashCommands,\n        // ─── Widget shell ──────────────────────────────────────────────────────────\n        openWidget() {\n            shell.open();\n            // Opening is a clear intent signal — warm the connection while the user\n            // reads the start screen (never on page views where it's never opened).\n            if (!session.isSessionLive)\n                session.prewarm();\n        },\n        minimizeWidget() {\n            shell.minimize();\n        },\n        handleTriggerClick() {\n            // defaultExpanded renders no trigger at all — a stray click must never\n            // toggle the panel or start a call (the widget is permanently open).\n            if (config.defaultExpanded)\n                return;\n            const { isLoading, connectionState } = session.getSnapshot();\n            if (config.bypassStartScreen && !isLoading && connectionState === \"disconnected\" && !session.isSessionLive) {\n                controller.openWidget();\n                void controller.startCall(shell.getSnapshot().callMode);\n            }\n            else if (shell.isOpen) {\n                shell.minimize();\n            }\n            else {\n                controller.openWidget();\n            }\n        },\n        // ─── Call lifecycle ────────────────────────────────────────────────────────\n        async startCall(mediaType) {\n            shell.setCallMode(mediaType);\n            // Fresh conversation for every new call — old transcript/components never\n            // carry over.\n            resetConversation();\n            const result = await session.start({\n                agentId: config.agentId,\n                variables: config.variables ?? {},\n                mediaType,\n            });\n            if (!result) {\n                typing.clear();\n                return;\n            }\n            shell.setCurrentCallId(result.callId);\n            slashCommands.setRuntimeCommands(result.slashCommands);\n            // In text mode raise the dots immediately: a greeting is always coming,\n            // and they cover both connect and first-reply latency.\n            if (mediaType === \"text\")\n                typing.showOnUserSend();\n            // Re-arm the once-per-conversation \"ended\" guard, then announce the start\n            // (production's dispatchConversationStart, App.tsx:254-257).\n            conversationEndedDispatched = false;\n            eventBus.emit(\"ringg:conversation_status\", { status: \"started\", mode: mediaType, callId: result.callId });\n        },\n        async endCall() {\n            const { currentCallId, callMode } = shell.getSnapshot();\n            // Guarded like production's conversationEndedDispatched ref: endCall\n            // re-enters via onSessionEnded (livekit emits Disconnected synchronously\n            // inside room.disconnect()), and the host must see exactly one \"ended\"\n            // per conversation.\n            if (currentCallId && !conversationEndedDispatched) {\n                conversationEndedDispatched = true;\n                eventBus.emit(\"ringg:conversation_status\", { status: \"ended\", mode: callMode, callId: currentCallId });\n            }\n            slashCommands.reset();\n            typing.clear();\n            components.reset();\n            await session.end();\n            if (config.bypassFeedbackScreen) {\n                resetConversation();\n                shell.close();\n            }\n            else {\n                shell.showFeedback();\n                shell.open();\n            }\n        },\n        // ─── Chat ──────────────────────────────────────────────────────────────────\n        async sendMessage(text) {\n            messages.addChatMessage({ message: text, isSelf: true });\n            typing.showOnUserSend();\n            await transport.sendChatMessage(text);\n        },\n        // ─── Components ────────────────────────────────────────────────────────────\n        async sendComponentResponse(componentId, responseData) {\n            const pending = components.takePendingResponse(componentId);\n            if (!pending)\n                return;\n            const { method, payload } = formatComponentResponse(pending.name, componentId, responseData, pending.originalConfig);\n            await transport.performRpcToAgent(method, payload);\n            eventBus.emit(\"ringg:component_acknowledgement\", {\n                componentName: pending.name,\n                componentId,\n                status: \"responded\",\n            });\n        },\n        async sendBlocksAction(toolId, componentId, action) {\n            const { method, payload } = formatBlocksAction(toolId, componentId, action);\n            try {\n                await transport.performRpcToAgent(method, payload);\n            }\n            catch {\n                // Production console.errors and never surfaces it — resolving anyway\n                // lets the BlocksStep spinner clear.\n            }\n        },\n        callComponentApi(method, endpoint, payload) {\n            return api.callComponentApi(method, endpoint, payload);\n        },\n        async sendDynamicData(payload) {\n            const { method, payload: rpcPayload } = formatDynamicData(payload);\n            await transport.performRpcToAgent(method, rpcPayload);\n        },\n        addLocalComponent(component) {\n            // Direct commit, like production's local widget messages (slash-command\n            // widgets) — NOT the chat buffering path: there's no agent text coming\n            // to anchor under, and no typing/notification/open side effects apply.\n            messages.addComponent(component);\n        },\n        displaySelection(componentId, label) {\n            messages.addLocalSelection(componentId, label);\n        },\n        markFlowComplete(componentId) {\n            components.markFlowComplete(componentId);\n            eventBus.emit(\"ringg:calendar_booking\", { status: \"confirmed\", componentId, message: \"Flow completed\" });\n        },\n        registerDynamicDataExtension(extension) {\n            return components.registerExtension(extension);\n        },\n        // ─── Slash commands ────────────────────────────────────────────────────────\n        async sendSlashCommand(command) {\n            // WIDGET_TOOL commands render locally — extensions (client packs) own\n            // them; nothing goes over the wire from core.\n            if (components.runExtensions(\"slash_command\", { command: command.command, tool_type: command.tool_type }))\n                return;\n            const { method, payload } = formatSlashCommand(command.command);\n            await transport.performRpcToAgent(method, payload);\n        },\n        // ─── Feedback ──────────────────────────────────────────────────────────────\n        async submitFeedback(rating, comment) {\n            const { currentCallId } = shell.getSnapshot();\n            if (currentCallId) {\n                try {\n                    await api.submitFeedback(currentCallId, { rating, comment });\n                    eventBus.emit(\"ringg:feedback_status\", { status: \"submitted\", callId: currentCallId, rating });\n                }\n                catch {\n                    // Feedback is best-effort — closing the widget must never fail on it.\n                }\n            }\n            resetConversation();\n            shell.close();\n        },\n        skipFeedback() {\n            const { currentCallId } = shell.getSnapshot();\n            if (currentCallId) {\n                eventBus.emit(\"ringg:feedback_status\", { status: \"skipped\", callId: currentCallId });\n            }\n            resetConversation();\n            shell.close();\n        },\n        // ─── Teardown ──────────────────────────────────────────────────────────────\n        destroy() {\n            unsubscribers.forEach((unsubscribe) => unsubscribe());\n            transport.unregisterRpcMethod(\"send_dynamic_data\");\n            transport.unregisterRpcMethod(\"render_component\");\n            transport.unregisterRpcMethod(\"send_source_urls\");\n            transport.unregisterTextStreamHandler(\"lk.transcription\");\n            transport.unregisterTextStreamHandler(\"ringg.blocks\");\n            void transport.disconnect();\n            [shell, session, messages, typing, components, slashCommands].forEach((store) => store.dispose());\n            eventBus.off();\n        },\n    };\n    wireTransport();\n    // defaultExpanded seeds the shell store open at creation (no \"maximised\"\n    // event on mount, matching production where isOpen starts true), so no\n    // explicit open() call is needed here.\n    return controller;\n}\n","/**\n * React bindings — shared by @ringg/web (React DOM) and @ringg/react-native.\n *\n * Every hook is a useSyncExternalStore call over a core store; there is no\n * behavior here and there must never be. A fix to typing timing, message\n * ordering, or session lifecycle lands in the stores once and both platforms\n * pick it up.\n *\n * Imported via the \"@ringg/core/react\" subpath so non-React consumers of\n * core never touch the react dependency (it's an optional peer).\n */\nimport { useSyncExternalStore } from \"react\";\nexport function useStoreSnapshot(store) {\n    return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n}\nexport const useRinggMessages = (controller) => useStoreSnapshot(controller.messages);\nexport const useRinggTyping = (controller) => useStoreSnapshot(controller.typing);\nexport const useRinggSession = (controller) => useStoreSnapshot(controller.session);\nexport const useRinggShell = (controller) => useStoreSnapshot(controller.shell);\nexport const useRinggComponents = (controller) => useStoreSnapshot(controller.components);\nexport const useRinggSlashCommands = (controller) => useStoreSnapshot(controller.slashCommands);\n","/**\n * RinggWidget — the assembled React Native widget.\n *\n * The native counterpart of the web assembly: the same tree, the same order,\n * the same branches. It holds NO conversation state — every snapshot comes\n * from `@ringg/core` via the shared hooks and every intent is forwarded to the\n * controller. If a behaviour looks like it belongs here, it belongs in core.\n *\n * Three things genuinely differ from web, all forced by the platform:\n *\n *  1. There is no `position: fixed`. The widget is an absolutely-filled\n *     overlay with `pointerEvents=\"box-none\"`, so taps pass through everywhere\n *     except the trigger and the panel. Mount it as the LAST child of the app\n *     root; `widgetPosition` (a web-only config) is ignored and the panel\n *     sizes itself to the device.\n *  2. The keyboard covers the bottom of the screen. The panel lives inside a\n *     `KeyboardAvoidingView` so the composer stays visible while typing —\n *     without it the input is simply unreachable in text mode.\n *  3. The transcript cannot measure a child's offset the way web does to\n *     anchor the newest turn's first line. It pins to the bottom instead, and\n *     the \"new message\" / \"typing toggled\" distinction is preserved so a long\n *     reply arriving does not yank the view while the user is reading.\n */\n\nimport { Fragment, useEffect, useMemo, useRef, useState, type ComponentRef, type FC } from \"react\";\nimport { Animated, Image, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, Text, View, useWindowDimensions } from \"react-native\";\nimport { Minus, X } from \"lucide-react-native\";\nimport type { Room } from \"livekit-client\";\nimport { DEFAULT_CONFIG, type ChatMessage, type MediaType, type RinggWidgetController, type SlashCommand } from \"@ringg/core\";\nimport { useRinggComponents, useRinggMessages, useRinggSession, useRinggShell, useRinggSlashCommands, useRinggTyping } from \"@ringg/core/react\";\n\nimport ActionButton from \"./components/action-button\";\nimport CallControls from \"./components/call-controls\";\nimport FeedbackScreen from \"./components/feedback-screen\";\nimport Header from \"./components/header\";\nimport InteractiveFlow from \"./components/interactive-flow\";\nimport LoadingBar from \"./components/loading-bar\";\nimport MessageItem from \"./components/message-item\";\nimport SystemLog from \"./components/system-log\";\nimport TypingIndicator from \"./components/typing-indicator\";\nimport { VoiceAnimationLeaf } from \"./components/voice-leaves\";\nimport BlocksStep from \"./components/steps/blocks-step\";\nimport { ConfirmDialog } from \"./components/ui/dialog\";\nimport { Touchable } from \"./components/ui/pressable\";\nimport { useMicrophone } from \"./hooks/use-microphone\";\nimport { usePresence } from \"./hooks/use-presence\";\nimport { GradientFill, solidColor } from \"./lib/gradient\";\nimport { PhoneCallRingIcon } from \"./lib/icons\";\nimport { isBlocks, isButtons, type ComponentPayload as WidgetComponentPayload, type InteractiveFlowPayload, type SimpleComponentPayload } from \"./lib/component-types\";\nimport { toSize, toViewStyle } from \"./lib/portable-styles\";\nimport { renderTextWithLinks } from \"./lib/text-helpers\";\nimport { ringgId } from \"./lib/testing\";\nimport { resolveFontFamily, resolveRadius, WidgetThemeProvider, useWidgetTheme } from \"./lib/widget-theme\";\n\nexport interface RinggWidgetProps {\n  controller: RinggWidgetController;\n  /**\n   * The LiveKit room from `createLiveKitTransport()`. Optional: it only powers\n   * the in-call audio visualizer and the mute button. Without it the widget is\n   * fully functional and the visualizer shows its ambient idle animation.\n   */\n  room?: Room;\n}\n\ninterface WidgetPanelProps extends RinggWidgetProps {\n  width: number;\n  height: number;\n}\n\n/** Web's `md:w-[400px]` / `h-[28.5rem]`, and its 96dvh clamp. */\nconst PANEL_MAX_WIDTH = 400;\nconst PANEL_HEIGHT = 456;\nconst PANEL_HEIGHT_RATIO = 0.9;\n\n/** Web anchors the panel and trigger at 2% of the viewport; dp here. */\nconst EDGE_INSET = 16;\n/**\n * Extra clearance at the bottom so the trigger never sits under the home\n * indicator. The widget deliberately takes no dependency on a safe-area\n * provider — it is mounted as a bare overlay — so this is a fixed inset that\n * clears the indicator on devices that have one and reads as ordinary spacing\n * on those that do not.\n */\nconst BOTTOM_SAFE_INSET = 24;\nconst TRIGGER_SIZE = 52;\nconst TRIGGER_RADIUS = 20;\nconst DEFAULT_TRIGGER_ICON_SIZE = 24;\n\n/**\n * The web widget's own springs, carried over as-is. RN's `Animated.spring`\n * takes the same stiffness/damping units framer-motion uses, so these are the\n * literal values from `web/src/RinggWidget.tsx` rather than an approximation.\n */\nconst PANEL_SPRING = { stiffness: 380, damping: 30 };\nconst TRIGGER_SPRING = { stiffness: 400, damping: 25 };\n\nconst LEGAL_LINKS = { \"Privacy Policy\": \"https://www.ringg.ai/privacy\", \"T&C\": \"https://www.ringg.ai/terms\" };\nconst LEGAL_TEXT = \"By continuing, you agree to our\\nPrivacy Policy and T&C.\";\n\nconst isFreeButtonsMessage = (message: ChatMessage | undefined): boolean => {\n  // Core keeps `presentation` out of its ButtonsData contract — the structured\n  // widget contract lives in lib/component-types, hence the cast.\n  const componentData = message?.componentData as unknown as WidgetComponentPayload | undefined;\n  return !!componentData && isButtons(componentData) && componentData.data.presentation === \"free\";\n};\n\nconst isAttachableAgentMessage = (message: ChatMessage | undefined): boolean => !!message && !message.componentType && !message.isSelf && Boolean(message.message.trim());\n\n\nconst WidgetPanel: FC<WidgetPanelProps> = ({ controller, room, width, height }) => {\n  const theme = useWidgetTheme();\n  const { config } = controller;\n  const {\n    title = DEFAULT_CONFIG.title,\n    description = DEFAULT_CONFIG.description,\n    buttons,\n    defaultExpanded = DEFAULT_CONFIG.defaultExpanded,\n    hideTabSelector = DEFAULT_CONFIG.hideTabSelector,\n    bypassStartScreen = DEFAULT_CONFIG.bypassStartScreen,\n    logoUrl,\n    logoStyles,\n    typingWords,\n    legalDisclaimer,\n    feedbackScreen,\n    voiceCall,\n  } = config;\n\n  // ─── Core snapshots (the ONLY state source) ────────────────────────────────\n  const shell = useRinggShell(controller);\n  const session = useRinggSession(controller);\n  const { messages } = useRinggMessages(controller);\n  const { isTyping: isAgentTyping } = useRinggTyping(controller);\n  const { completedFlowIds } = useRinggComponents(controller);\n  const { commands } = useRinggSlashCommands(controller);\n\n  // The end-call confirm dialog is pure UI state — local, as on web.\n  const [alertEndCall, setAlertEndCall] = useState(false);\n\n  const microphone = useMicrophone(room);\n\n  const callMode = shell.callMode;\n  const showFeedback = shell.viewState === \"feedback\";\n\n  const isLoading = session.isLoading;\n  const error = session.error;\n  const connectionState = session.connectionState;\n  const isCalling = connectionState === \"connected\";\n  // UI gate for the calling layout: optimistic (session created) OR actually\n  // connected — computed by the core session store.\n  const isSessionLive = session.isSessionLive;\n\n  const isAudioMode = callMode === \"audio\";\n  const showVoiceAnimation = isAudioMode && isCalling && (voiceCall?.showAnimation ?? DEFAULT_CONFIG.voiceCallShowAnimation);\n  const showVoiceTranscript = !isAudioMode || (voiceCall?.showTranscript ?? DEFAULT_CONFIG.voiceCallShowTranscript);\n\n  const mergedSlashCommands = useMemo(() => [...commands], [commands]);\n  // Core hands out a readonly snapshot — copy before the (source-verbatim)\n  // sort. Neighbour lookups below use the same sorted array.\n  const sortedMessages = useMemo(() => [...messages].sort((a, b) => a.timestamp - b.timestamp), [messages]);\n\n  // `ComponentRef` reads the instance type off ScrollView itself, so this\n  // compiles on both RN 0.86 (PublicScrollViewInstance) and 0.87\n  // (ScrollViewInstance) — the peer range spans versions that renamed it.\n  const transcriptRef = useRef<ComponentRef<typeof ScrollView>>(null);\n  const previousMessagesCountRef = useRef(0);\n\n  useEffect(() => {\n    const newMessageAdded = messages.length > previousMessagesCountRef.current;\n    previousMessagesCountRef.current = messages.length;\n    // A new turn scrolls; a typing toggle only re-pins. Animating the former\n    // and not the latter keeps the dots from jittering the view every time\n    // they appear and disappear.\n    transcriptRef.current?.scrollToEnd({ animated: newMessageAdded });\n  }, [messages, isAgentTyping]);\n\n  // ─── Intents → controller ──────────────────────────────────────────────────\n  const handleCallStart = (mediaType: MediaType): void => void controller.startCall(mediaType);\n  const handleCallEnd = (): void => {\n    setAlertEndCall(false);\n    void controller.endCall();\n  };\n  const handleFeedbackSubmit = (rating: number, comment: string): void => void controller.submitFeedback(rating, comment);\n  const handleFeedbackSkip = (): void => controller.skipFeedback();\n  const handleUserMessageSent = (): void => controller.typing.showOnUserSend();\n  const handleFlowComplete = (componentId: string): void => controller.markFlowComplete(componentId);\n  const handleSelectionDisplayed = (componentId: string, label: string): void => controller.displaySelection(componentId, label);\n  const sendComponentResponse = (componentId: string, responseData: Record<string, unknown>): Promise<void> => controller.sendComponentResponse(componentId, responseData);\n  const sendSlashCommand = (command: SlashCommand): void => void controller.sendSlashCommand(command);\n  const callComponentApi = controller.callComponentApi;\n\n  const panelRadius = resolveRadius(theme.borderRadius, 16);\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  const chrome = (\n    <>\n      {!defaultExpanded && (isSessionLive || showFeedback) ? (\n        <Touchable testID={ringgId(\"minimize-button\")} accessibilityLabel=\"Minimize widget\" onPress={() => controller.minimizeWidget()} style={[styles.chromeButton, styles.minimizeButton]}>\n          <Minus size={16} color={solidColor(theme.mutedTextColor)} />\n        </Touchable>\n      ) : null}\n      {!defaultExpanded ? (\n        <Touchable\n          testID={ringgId(\"close-button\")}\n          accessibilityLabel={isSessionLive ? \"End call\" : \"Close widget\"}\n          onPress={() => (isSessionLive ? setAlertEndCall(true) : showFeedback ? handleFeedbackSkip() : controller.minimizeWidget())}\n          style={[styles.chromeButton, styles.closeButton]}\n        >\n          <X size={16} color={solidColor(theme.mutedTextColor)} />\n        </Touchable>\n      ) : null}\n    </>\n  );\n\n  const transcript = (\n    <ScrollView\n      testID={ringgId(\"transcript\")}\n      ref={transcriptRef}\n      style={styles.transcript}\n      contentContainerStyle={[styles.transcriptList, !showVoiceAnimation && styles.transcriptTopClearance, !isAudioMode && styles.transcriptBottomClearance]}\n      keyboardShouldPersistTaps=\"handled\"\n      showsVerticalScrollIndicator={false}\n    >\n      {sortedMessages.map((segment, index) => {\n        // System log pill (host action fired, etc.) — before the component branches.\n        if (segment.kind === \"system\") return <SystemLog key={`sys_${segment.timestamp}_${index}`} label={segment.message} meta={segment.systemMeta} level={segment.systemLevel} />;\n\n        const previousSegment = sortedMessages[index - 1];\n        const nextSegment = sortedMessages[index + 1];\n        const attachFreeButtonsToPrevious = isFreeButtonsMessage(segment) && isAttachableAgentMessage(previousSegment);\n        const skipStandaloneRender = isAttachableAgentMessage(segment) && isFreeButtonsMessage(nextSegment);\n\n        if (skipStandaloneRender) return null;\n\n        if (attachFreeButtonsToPrevious && previousSegment && segment.componentData) {\n          // After a selected_item choice the user's pick is shown as a\n          // right-aligned bubble (pushed by handleSelectionDisplayed); render\n          // just the agent's prompt here, without the buttons.\n          const componentData = segment.componentData as unknown as WidgetComponentPayload;\n          const isCompletedSelectedItem = componentData.component_type === \"buttons\" && componentData.data.completionDisplay === \"selected_item\" && completedFlowIds.has(componentData.component_id);\n\n          if (isCompletedSelectedItem) return <MessageItem key={`message_with_buttons_${segment.componentData.component_id}_${index}`} itemIndex={index} message={previousSegment} />;\n\n          // The chips render as a sibling below the message (not inside its\n          // width-capped bubble) so they can align to the panel edge.\n          return (\n            <Fragment key={`message_with_buttons_${segment.componentData.component_id}_${index}`}>\n              <MessageItem itemIndex={index} message={previousSegment} />\n              <View testID={ringgId(\"attached-buttons\")} style={styles.fullWidth}>\n                <InteractiveFlow\n                  initialComponent={segment.componentData as unknown as SimpleComponentPayload | InteractiveFlowPayload}\n                  onApiCall={callComponentApi}\n                  onComplete={() => handleFlowComplete(componentData.component_id)}\n                  onSendResponse={sendComponentResponse}\n                  onSelectionDisplayed={handleSelectionDisplayed}\n                  quickReplyAlign={isAudioMode ? \"center\" : \"end\"}\n                />\n              </View>\n            </Fragment>\n          );\n        }\n\n        // Block Kit tree — standalone, full width; keyed by component_id so a\n        // re-render never wipes half-filled inputs.\n        if (segment.componentType === \"blocks\" && segment.componentData) {\n          const blocksPayload = segment.componentData as unknown as WidgetComponentPayload;\n          if (isBlocks(blocksPayload)) {\n            const blocksConfig = blocksPayload.data;\n            const blockId = blocksPayload.component_id;\n            return (\n              <View key={`blocks_${blockId}`} testID={ringgId(\"blocks-widget\")} style={styles.fullWidth}>\n                <BlocksStep\n                  config={blocksConfig}\n                  // One-shot: a respond is a conversation turn, so the card\n                  // locks once answered.\n                  disabled={completedFlowIds.has(blockId)}\n                  onAction={(action) => {\n                    handleUserMessageSent();\n                    handleFlowComplete(blockId);\n                    // Echo the selection as a right-aligned user bubble, like a\n                    // quick-reply pick. Prefer the button's `value` — it is the\n                    // meaningful choice (identical labels like \"View details\"\n                    // share a value that differs, e.g. the plan name) — and fall\n                    // back to the label only when there is no usable value.\n                    const selection = typeof action.value === \"string\" || typeof action.value === \"number\" ? String(action.value) : action.label;\n                    if (selection) handleSelectionDisplayed(blockId, selection);\n                    // `label` stays UI-only — the wire action carries\n                    // action_id/value/values, exactly like the source.\n                    return controller.sendBlocksAction(blocksConfig.tool_id, blockId, { action_id: action.action_id, value: action.value, values: action.values });\n                  }}\n                />\n              </View>\n            );\n          }\n        }\n\n        if (segment.componentType && segment.componentData) {\n          // Same selected_item case for a standalone (non-attached) button flow\n          // — the pick is the right-aligned bubble below, so unmount the flow.\n          const componentData = segment.componentData as unknown as WidgetComponentPayload;\n          const isCompletedSelectedItem = componentData.component_type === \"buttons\" && componentData.data.completionDisplay === \"selected_item\" && completedFlowIds.has(componentData.component_id);\n          if (isCompletedSelectedItem) return null;\n\n          return (\n            <InteractiveFlow\n              key={`flow_${segment.componentData.component_id}_${index}`}\n              initialComponent={segment.componentData as unknown as SimpleComponentPayload | InteractiveFlowPayload}\n              onApiCall={callComponentApi}\n              onComplete={() => handleFlowComplete(componentData.component_id)}\n              onSendResponse={sendComponentResponse}\n              onSelectionDisplayed={handleSelectionDisplayed}\n              quickReplyAlign={isAudioMode ? \"center\" : \"end\"}\n            />\n          );\n        }\n\n        return <MessageItem key={`${segment.timestamp}__${index}`} itemIndex={index} message={segment} />;\n      })}\n      {isAgentTyping ? <TypingIndicator words={typingWords} /> : null}\n    </ScrollView>\n  );\n\n  const controls = (\n    <CallControls\n      buttonConfig={buttons}\n      callMode={callMode}\n      isCalling={isSessionLive}\n      enabledSlashCommands={mergedSlashCommands}\n      micEnabled={microphone?.enabled ?? true}\n      onToggleMic={microphone?.toggle}\n      onSlashCommand={sendSlashCommand}\n      onUserMessage={handleUserMessageSent}\n      onCallEnd={handleCallEnd}\n      onSendMessage={(message) => controller.sendMessage(message)}\n    />\n  );\n\n  return (\n    <View\n      testID={ringgId(\"widget-root\")}\n      style={[styles.panel, { width, height, borderRadius: panelRadius, backgroundColor: solidColor(theme.backgroundColor), borderColor: solidColor(theme.borderColor) }]}\n    >\n      {chrome}\n\n      <ConfirmDialog\n        open={alertEndCall}\n        title={`Are you sure you want to end ${callMode === \"text\" ? \"chat\" : \"call\"}?`}\n        description=\"Your current conversation will be closed and cannot be accessed later.\"\n        confirmLabel={`End ${callMode === \"text\" ? \"Chat\" : \"Call\"}`}\n        cancelLabel=\"Cancel\"\n        onConfirm={handleCallEnd}\n        onCancel={() => setAlertEndCall(false)}\n      />\n\n      {showFeedback ? (\n        <FeedbackScreen\n          callMode={callMode}\n          isSubmitting={isLoading}\n          feedbackScreenConfig={feedbackScreen}\n          messages={messages}\n          title={title}\n          logoUrl={logoUrl}\n          logoStyles={logoStyles}\n          onSubmit={handleFeedbackSubmit}\n          onSkip={handleFeedbackSkip}\n        />\n      ) : (\n        <View testID={ringgId(\"widget-body\")} style={[styles.body, isSessionLive ? styles.bodyLive : styles.bodyIdle]}>\n          <Header isCalling={isSessionLive} isLoading={isLoading} title={title} description={description} logoUrl={logoUrl} logoStyles={logoStyles} />\n\n          {showVoiceAnimation ? (\n            <View testID={ringgId(\"voice-animation-wrapper\")} style={[styles.voiceWrapper, showVoiceTranscript && messages.length > 0 ? styles.voiceWrapperCompact : styles.voiceWrapperFull]}>\n              <VoiceAnimationLeaf room={room} />\n            </View>\n          ) : null}\n\n          {isSessionLive && !showVoiceAnimation && ((messages.length === 0 && !isAgentTyping) || !showVoiceTranscript) ? <View testID={ringgId(\"body-spacer\")} style={styles.bodySpacer} /> : null}\n\n          {(messages.length > 0 || isAgentTyping) && isSessionLive && showVoiceTranscript ? transcript : null}\n\n          {isSessionLive && callMode === \"text\" ? (\n            // Transparent bottom bar: it only positions the composer over the\n            // transcript, so the gutters stay clear while messages scroll under.\n            <View testID={ringgId(\"controls-bar\")} style={styles.controlsBar}>\n              {error.hasError ? (\n                <Text testID={ringgId(\"error-message\")} style={[styles.error, { color: solidColor(theme.errorColor), fontFamily }]}>\n                  {error.message}\n                </Text>\n              ) : null}\n              {controls}\n            </View>\n          ) : (\n            <>\n              {controls}\n              {error.hasError ? (\n                <Text testID={ringgId(\"error-message\")} style={[styles.error, { color: solidColor(theme.errorColor), fontFamily }]}>\n                  {error.message}\n                </Text>\n              ) : null}\n            </>\n          )}\n\n          {!isSessionLive && isLoading ? (\n            <View testID={ringgId(\"connecting-status\")}>\n              <Text testID={ringgId(\"connecting-label\")} style={[styles.connecting, { color: theme.mutedTextColor, fontFamily }]}>\n                Connecting...\n              </Text>\n              <LoadingBar ariaLabel={callMode === \"text\" ? \"Starting chat\" : \"Connecting\"} />\n            </View>\n          ) : null}\n\n          {!isLoading && connectionState === \"disconnected\" && (!bypassStartScreen || error.hasError) ? (\n            hideTabSelector ? (\n              <ActionButton callMode={callMode} buttonConfig={buttons} isCalling={isCalling} isLoading={isLoading} onCallTrigger={handleCallStart} />\n            ) : (\n              <View testID={ringgId(\"start-actions\")} style={styles.startActions}>\n                <ActionButton dual callMode=\"text\" buttonConfig={buttons} isCalling={isCalling} isLoading={isLoading} onCallTrigger={handleCallStart} />\n                <ActionButton dual callMode=\"audio\" buttonConfig={buttons} isCalling={isCalling} isLoading={isLoading} onCallTrigger={handleCallStart} />\n              </View>\n            )\n          ) : null}\n\n          {!isSessionLive ? (\n            <Text testID={ringgId(\"legal-disclaimer\")} style={[styles.legal, { color: theme.mutedTextColor, fontFamily }]}>\n              {legalDisclaimer ? renderTextWithLinks(legalDisclaimer.text, legalDisclaimer.links) : renderTextWithLinks(LEGAL_TEXT, LEGAL_LINKS, { color: solidColor(theme.primaryColor), textDecorationLine: \"underline\" })}\n            </Text>\n          ) : null}\n        </View>\n      )}\n    </View>\n  );\n};\n\nexport const RinggWidget: FC<RinggWidgetProps> = ({ controller, room }) => {\n  const shell = useRinggShell(controller);\n  const { width: screenWidth, height: screenHeight } = useWindowDimensions();\n  const { buttons, defaultExpanded = DEFAULT_CONFIG.defaultExpanded, widgetPosition } = controller.config;\n\n  const isOpen = shell.viewState === \"open\" || shell.viewState === \"feedback\";\n  const hideTriggerOnExpand = widgetPosition?.hideTriggerOnExpand ?? true;\n  const showTrigger = !defaultExpanded && (!hideTriggerOnExpand || !isOpen);\n\n  // `mounted` outlives `isOpen` for the length of the exit spring — without\n  // that, the panel would unmount in the same commit and its close animation\n  // would drive a value nothing is attached to.\n  const panel = usePresence(isOpen, PANEL_SPRING);\n  const trigger = usePresence(showTrigger, TRIGGER_SPRING);\n  // Derived from the inset, not from a fraction of the viewport. Web sizes the\n  // panel at 95vw and offsets it 2% from the right, which overlaps by design\n  // there; here the anchor asks for a real margin on BOTH sides, so a width\n  // that does not leave room for two of them overflows its own margin box and\n  // the panel drifts left. Phone: fills the width between equal insets.\n  // Tablet: caps at 400 and stays anchored right, as on web.\n  const panelWidth = Math.min(screenWidth - EDGE_INSET * 2, PANEL_MAX_WIDTH);\n  const panelHeight = Math.min(screenHeight * PANEL_HEIGHT_RATIO, PANEL_HEIGHT);\n\n  const triggerIconSize = toSize(buttons?.modalTrigger?.icon?.size, DEFAULT_TRIGGER_ICON_SIZE);\n\n  return (\n    <WidgetThemeProvider theme={controller.theme}>\n      {/* box-none: the overlay itself is transparent to touches, its children\n          are not — so the host app underneath stays fully interactive. */}\n      <View pointerEvents=\"box-none\" style={StyleSheet.absoluteFill}>\n        {panel.mounted ? (\n          <KeyboardAvoidingView pointerEvents=\"box-none\" behavior={Platform.OS === \"ios\" ? \"padding\" : undefined} style={styles.overlay}>\n            <Animated.View\n              // Android redraws an elevation shadow from the view outline on\n              // every frame of a transform. Rasterising the layer hands that to\n              // the GPU instead, which is what makes the open and close smooth\n              // rather than steppy.\n              renderToHardwareTextureAndroid\n              shouldRasterizeIOS\n              style={[\n                styles.panelAnchor,\n                {\n                  opacity: panel.progress,\n                  transform: [{ translateY: panel.progress.interpolate({ inputRange: [0, 1], outputRange: [24, 0] }) }, { scale: panel.progress.interpolate({ inputRange: [0, 1], outputRange: [0.96, 1] }) }],\n                },\n              ]}\n            >\n              <WidgetPanel controller={controller} room={room} width={panelWidth} height={panelHeight} />\n            </Animated.View>\n          </KeyboardAvoidingView>\n        ) : null}\n\n        {trigger.mounted ? <WidgetTrigger controller={controller} iconSize={triggerIconSize} progress={trigger.progress} /> : null}\n      </View>\n    </WidgetThemeProvider>\n  );\n};\n\n/**\n * Split out so it can read the theme context the provider above installs — a\n * component cannot consume a context its own parent creates.\n */\nconst WidgetTrigger: FC<{ controller: RinggWidgetController; iconSize: number; progress: Animated.Value }> = ({ controller, iconSize, progress }) => {\n  const theme = useWidgetTheme();\n  const { buttons } = controller.config;\n\n  return (\n    // Web pops the trigger with a spring and fades it out again when the panel\n    // takes over; both ends of that are visible on every open/close cycle.\n    <Animated.View style={[styles.trigger, { opacity: progress, transform: [{ scale: progress.interpolate({ inputRange: [0, 1], outputRange: [0.8, 1] }) }] }]}>\n      <Touchable testID={ringgId(\"trigger-button\")} accessibilityLabel=\"Open call widget\" onPress={() => controller.handleTriggerClick()}>\n      <GradientFill color={theme.primaryColor} style={[styles.triggerSurface, toViewStyle(buttons?.modalTrigger?.styles)]}>\n        {/* Web's default trigger icon is a remote SVG. RN's <Image> decodes\n            PNG/JPEG/GIF/WebP but NOT SVG, so that URL renders an empty button\n            here — the same glyph ships in this package as a vector instead.\n            An integrator-supplied `icon.url` still goes through <Image>, which\n            is correct for the raster formats they can actually use. */}\n        {buttons?.modalTrigger?.icon?.url ? (\n          <Image\n            testID={ringgId(\"trigger-icon\")}\n            accessibilityLabel=\"Widget trigger\"\n            source={{ uri: buttons.modalTrigger.icon.url }}\n            resizeMode=\"contain\"\n            style={{ width: iconSize, height: iconSize }}\n          />\n        ) : (\n          <PhoneCallRingIcon testID={ringgId(\"trigger-icon\")} size={iconSize} fill={solidColor(theme.primaryTextColor)} />\n        )}\n        </GradientFill>\n      </Touchable>\n    </Animated.View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  overlay: { ...StyleSheet.absoluteFill, justifyContent: \"flex-end\", alignItems: \"flex-end\" },\n  panelAnchor: { marginHorizontal: EDGE_INSET, marginTop: EDGE_INSET, marginBottom: BOTTOM_SAFE_INSET },\n  panel: {\n    borderWidth: StyleSheet.hairlineWidth,\n    // `overflow: hidden` is what keeps the transcript, the header bar and the\n    // rounded corners agreeing with each other.\n    overflow: \"hidden\",\n    // Web stacks three shadows at 1-2% alpha — the panel sits just off the page\n    // rather than floating above it. 12% read as a hard slab, and on Android\n    // `elevation` is the only one of these that applies, so it was the entire\n    // effect instead of a supporting layer.\n    shadowColor: \"#000000\",\n    shadowOpacity: 0.05,\n    shadowRadius: 20,\n    shadowOffset: { width: 0, height: 8 },\n    elevation: 4,\n  },\n\n  trigger: { position: \"absolute\", right: EDGE_INSET, bottom: BOTTOM_SAFE_INSET },\n  triggerSurface: { width: TRIGGER_SIZE, height: TRIGGER_SIZE, borderRadius: TRIGGER_RADIUS, alignItems: \"center\", justifyContent: \"center\" },\n\n  chromeButton: { position: \"absolute\", top: 10, zIndex: 20, width: 28, height: 28, borderRadius: 14, alignItems: \"center\", justifyContent: \"center\" },\n  minimizeButton: { right: 42 },\n  closeButton: { right: 10 },\n\n  body: { flex: 1 },\n  bodyLive: { paddingHorizontal: 20, paddingVertical: 8, gap: 10 },\n  bodyIdle: { padding: 24, gap: 12 },\n  bodySpacer: { flex: 1, marginTop: 56 },\n\n  voiceWrapper: { width: \"100%\", alignItems: \"stretch\", justifyContent: \"center\", marginTop: 56 },\n  voiceWrapperCompact: { height: 56, flexShrink: 0 },\n  voiceWrapperFull: { flex: 1, minHeight: 0 },\n\n  transcript: { flex: 1 },\n  // `justifyContent: flex-end` is web's `mt-auto`: a short conversation sits at\n  // the bottom of the panel rather than floating at the top.\n  transcriptList: { flexGrow: 1, justifyContent: \"flex-end\", gap: 12 },\n  transcriptTopClearance: { paddingTop: 64 },\n  transcriptBottomClearance: { paddingBottom: 80 },\n  fullWidth: { width: \"100%\" },\n\n  controlsBar: { position: \"absolute\", zIndex: 10, bottom: 0, left: 0, right: 0, paddingHorizontal: 20, paddingVertical: 12 },\n  error: { textAlign: \"center\", fontSize: 14, marginBottom: 8 },\n  connecting: { fontSize: 14, textAlign: \"center\" },\n  startActions: { flexDirection: \"row\", alignItems: \"center\", gap: 8, width: \"100%\" },\n  legal: { fontSize: 12, lineHeight: 20, textAlign: \"center\" },\n});\n","/**\n * Start-call / start-chat button — RN port of the web widget's\n * `components/action-button.tsx`.\n *\n * The label rules are what has to survive the crossing intact: the built-in\n * label depends on whether this is one of the paired start-screen buttons or\n * the single full-width one, and the integrator's `textBeforeCall` for this\n * button's own mode overrides it. An empty configured string falls back to the\n * built-in label rather than rendering a nameless button.\n */\n\nimport type { FC } from \"react\";\nimport { ActivityIndicator, StyleSheet, Text } from \"react-native\";\nimport type { RinggWidgetConfig } from \"@ringg/core\";\n\nimport { GradientFill } from \"../lib/gradient\";\nimport { ChatIcon, PhoneCallRingIcon } from \"../lib/icons\";\nimport { toViewStyle } from \"../lib/portable-styles\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveButtonRadius, resolveFontFamily, useWidgetTheme } from \"../lib/widget-theme\";\nimport { Touchable } from \"./ui/pressable\";\n\ninterface ActionButtonProps {\n  isLoading?: boolean;\n  isCalling?: boolean;\n  callMode: \"audio\" | \"text\";\n  buttonConfig?: RinggWidgetConfig[\"buttons\"];\n  // Renders as one of the paired start-screen buttons (Chat | Call)\n  dual?: boolean;\n\n  onCallTrigger: (callMode: ActionButtonProps[\"callMode\"]) => void;\n}\n\n/** `h-4 w-4` on the leading icon. */\nconst ICON_SIZE = 16;\n\nconst CONNECTING_LABEL = \"Connecting...\";\n\nconst ActionButton: FC<ActionButtonProps> = ({ callMode, isLoading, buttonConfig, isCalling, dual = false, onCallTrigger }) => {\n  const theme = useWidgetTheme();\n  // `resolveButtonRadius` already maps \"pill\" onto the finite 9999 radius RN\n  // needs, so web's separate pill branch has nothing left to decide here.\n  const buttonRadius = resolveButtonRadius(theme.buttonStyle);\n\n  // Dual: one of the side-by-side Chat/Call pair on the start screen — short\n  // labels, each half the row. Single: the full-width fallback when the\n  // integrator pins the widget to one mode (hideTabSelector).\n  const defaultLabel = callMode === \"audio\" ? (dual ? \"Call\" : \"Start Call\") : dual ? \"Chat\" : \"Start Chat\";\n  const label = (callMode === \"audio\" ? buttonConfig?.call?.textBeforeCall : buttonConfig?.text?.textBeforeCall) || defaultLabel;\n\n  // Only the voice button reports progress; starting a chat is instant.\n  const isConnecting = isLoading === true && callMode === \"audio\";\n\n  // Web: `flex-1 h-10` when dual, otherwise `h-11` plus `w-full` before a call\n  // and `w-fit px-6` during one. RN splits that in two — the touch target owns\n  // the width, the painted surface owns the height and padding.\n  const widthStyle = dual ? styles.dual : isCalling ? styles.compact : styles.full;\n  const surfaceStyle = dual ? styles.dualSurface : isCalling ? styles.compactSurface : styles.singleSurface;\n  const labelStyle = [styles.label, dual ? styles.dualLabel : styles.singleLabel, { color: theme.primaryTextColor, fontFamily: resolveFontFamily(theme.fontFamily) }];\n\n  return (\n    <Touchable testID={ringgId(callMode === \"audio\" ? \"start-call-button\" : \"start-chat-button\")} disabled={isLoading} onPress={() => onCallTrigger(callMode)} style={widthStyle}>\n      <GradientFill color={theme.primaryColor} style={[styles.surface, surfaceStyle, { borderRadius: buttonRadius }, toViewStyle(buttonConfig?.call?.styles)]}>\n        {isConnecting ? (\n          <>\n            {/* Web spins a LoaderCircle. The platform spinner says the same\n                thing in the idiom users already know, and costs no animation\n                loop of our own. */}\n            <ActivityIndicator size=\"small\" color={theme.primaryTextColor} />\n            <Text style={labelStyle}>{CONNECTING_LABEL}</Text>\n          </>\n        ) : (\n          <>\n            {callMode === \"audio\" ? <PhoneCallRingIcon size={ICON_SIZE} fill={theme.primaryTextColor} /> : <ChatIcon size={ICON_SIZE} fill={theme.primaryTextColor} />}\n            <Text style={labelStyle}>{label}</Text>\n          </>\n        )}\n      </GradientFill>\n    </Touchable>\n  );\n};\n\nexport default ActionButton;\n\nconst styles = StyleSheet.create({\n  dual: { flex: 1 },\n  full: { alignSelf: \"stretch\" },\n  compact: { alignSelf: \"flex-start\" },\n\n  // The layer <GradientFill> paints is absolutely positioned, so it sits out of\n  // this row and the gap only ever spaces the icon from the label.\n  surface: { flexDirection: \"row\", alignItems: \"center\", justifyContent: \"center\", gap: 8 },\n  dualSurface: { height: 40 },\n  singleSurface: { height: 44 },\n  compactSurface: { height: 44, paddingHorizontal: 24 },\n\n  label: { fontWeight: \"500\" },\n  dualLabel: { fontSize: 15 },\n  // No text-size utility on the web button — it inherits the widget container's\n  // 16px.\n  singleLabel: { fontSize: 16 },\n});\n","/**\n * Gradient fills for React Native.\n *\n * The theme surface is CSS-shaped — `primaryColor` may be a solid hex OR a\n * `linear-gradient(...)` string (see core `types/theme.ts`, and the gradient\n * presets in `widget-theme`). The DOM renders those for free; RN has no\n * gradient primitive at all, so every themed surface goes through here.\n *\n * Colour PARSING is not duplicated — `isGradient` / `extractColorsFromGradient`\n * / `getDominantColor` come from `@ringg/core`, the same functions the web\n * widget uses (AGENTS.md rule 2: shared values come from core, never a local\n * re-implementation). Only the two things core cannot know about — the angle in\n * SVG coordinates, and how to paint it — live in this file.\n *\n * Non-linear gradients (radial/conic) degrade to their dominant colour rather\n * than approximating badly; the theme presets are all linear.\n */\n\nimport { Children, type FC, type ReactNode } from \"react\";\nimport { StyleSheet, View, type StyleProp, type ViewStyle } from \"react-native\";\nimport Svg, { Defs, LinearGradient as SvgLinearGradient, Rect, Stop } from \"react-native-svg\";\nimport { extractColorsFromGradient, getDominantColor, isGradient } from \"@ringg/core\";\n\ninterface GradientFillProps {\n  /** A theme colour: solid (`#0a0a0b`, `rgb(...)`) or a CSS gradient string. */\n  color: string;\n  /** Applied to the wrapper — size, padding, radius, alignment. */\n  style?: StyleProp<ViewStyle>;\n  children?: ReactNode;\n}\n\n/** Direction of the gradient line in SVG space (y grows downward). */\ninterface GradientLine {\n  x1: string;\n  y1: string;\n  x2: string;\n  y2: string;\n}\n\n/** CSS `linear-gradient` default when no angle/side is given. */\nconst DEFAULT_ANGLE_DEG = 180;\n\nconst SIDE_ANGLES: Record<string, number> = {\n  \"to top\": 0,\n  \"to right\": 90,\n  \"to bottom\": 180,\n  \"to left\": 270,\n  \"to top right\": 45,\n  \"to right top\": 45,\n  \"to bottom right\": 135,\n  \"to right bottom\": 135,\n  \"to bottom left\": 225,\n  \"to left bottom\": 225,\n  \"to top left\": 315,\n  \"to left top\": 315,\n};\n\n/** `turn` / `rad` / `grad` / `deg` → degrees. Unknown units fall back. */\nconst angleToDegrees = (value: string): number | undefined => {\n  const match = /^(-?\\d+(?:\\.\\d+)?)(deg|rad|grad|turn)$/.exec(value.trim().toLowerCase());\n  if (!match) return undefined;\n  const amount = Number(match[1]);\n  switch (match[2]) {\n    case \"deg\":\n      return amount;\n    case \"rad\":\n      return (amount * 180) / Math.PI;\n    case \"grad\":\n      return amount * 0.9;\n    case \"turn\":\n      return amount * 360;\n    default:\n      return undefined;\n  }\n};\n\n/**\n * The first argument of a `linear-gradient` is the direction — an angle\n * (`135deg`) or a side (`to bottom right`) — and is optional. Anything else\n * means the gradient starts straight at a colour stop, so the CSS default\n * applies.\n */\nconst readAngle = (gradient: string): number => {\n  const open = gradient.indexOf(\"(\");\n  const close = gradient.lastIndexOf(\")\");\n  if (open === -1 || close <= open) return DEFAULT_ANGLE_DEG;\n  const first = gradient.slice(open + 1, close).split(\",\")[0]?.trim().toLowerCase() ?? \"\";\n  if (first.startsWith(\"to \")) return SIDE_ANGLES[first.replace(/\\s+/g, \" \")] ?? DEFAULT_ANGLE_DEG;\n  return angleToDegrees(first) ?? DEFAULT_ANGLE_DEG;\n};\n\n/**\n * CSS angles are measured clockwise from \"to top\"; the gradient line runs\n * through the centre of the box. In screen coordinates (y down) the end\n * direction is `(sin A, -cos A)`, so the line spans centre ± half the vector.\n * Expressed in objectBoundingBox units, which is the same square-box\n * approximation the RN gradient libraries make.\n */\nconst angleToLine = (degrees: number): GradientLine => {\n  const radians = (degrees * Math.PI) / 180;\n  const dx = Math.sin(radians);\n  const dy = -Math.cos(radians);\n  return {\n    x1: `${0.5 - dx / 2}`,\n    y1: `${0.5 - dy / 2}`,\n    x2: `${0.5 + dx / 2}`,\n    y2: `${0.5 + dy / 2}`,\n  };\n};\n\n/** Even distribution — the theme presets carry no explicit stop positions. */\nconst stopOffset = (index: number, total: number): string => (total <= 1 ? \"0\" : `${index / (total - 1)}`);\n\nlet gradientId = 0;\nconst nextGradientId = (): string => `ringg-gradient-${++gradientId}`;\n\n/**\n * Paints `color` behind `children`. Solid colours take the cheap path\n * (`backgroundColor`); gradients get an absolutely-filled SVG layer that\n * inherits the wrapper's rounding through `overflow: hidden`.\n */\nexport const GradientFill: FC<GradientFillProps> = ({ color, style, children }) => {\n  if (!isGradient(color)) return <View style={[{ backgroundColor: color }, style]}>{children}</View>;\n\n  const colors = extractColorsFromGradient(color);\n  // A gradient we can name but not read (`radial-gradient(...)`, unparsed\n  // stops) still has to paint something — the dominant colour, same fallback\n  // core documents for RN in `colorToBackground`.\n  if (colors.length < 2) return <View style={[{ backgroundColor: getDominantColor(color) }, style]}>{children}</View>;\n\n  const id = nextGradientId();\n  const line = angleToLine(readAngle(color));\n\n  return (\n    <View style={[styles.clipped, style]}>\n      <Svg style={StyleSheet.absoluteFill} pointerEvents=\"none\">\n        <Defs>\n          <SvgLinearGradient id={id} x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2}>\n            {colors.map((stop, index) => (\n              <Stop key={`${stop}-${index}`} offset={stopOffset(index, colors.length)} stopColor={stop} />\n            ))}\n          </SvgLinearGradient>\n        </Defs>\n        <Rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" fill={`url(#${id})`} />\n      </Svg>\n      {Children.count(children) > 0 ? children : null}\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  clipped: { overflow: \"hidden\" },\n});\n\n/**\n * A guaranteed-solid colour, for the properties RN can only paint flat —\n * borders, shadows, icon tints, status dots.\n */\nexport const solidColor = (color: string): string => getDominantColor(color);\n","/**\n * Icon set — react-native-svg port of the web widget's `lib/icons.tsx`.\n *\n * Same viewBoxes, same path data: these are the brand marks the production\n * widget ships, so they are lifted verbatim rather than redrawn. Only the host\n * elements differ (`<svg>/<path>` → `<Svg>/<Path>`) and `className` is gone —\n * RN sizes and tints through props.\n *\n * `currentColor` has no meaning without a cascade, so `fill` defaults to the\n * caller's colour explicitly; every call site passes one.\n */\n\nimport type { FC } from \"react\";\nimport type { StyleProp, ViewStyle } from \"react-native\";\nimport Svg, { Path } from \"react-native-svg\";\n\nexport interface IconProps {\n  /** Square size in dp. Overridden by an explicit width/height. */\n  size?: number;\n  width?: number;\n  height?: number;\n  fill?: string;\n  style?: StyleProp<ViewStyle>;\n  /** `data-ringg` equivalent — pass the value `ringgId` returned. */\n  testID?: string;\n}\n\nexport type IconComponent = FC<IconProps>;\n\nconst DEFAULT_SIZE = 18;\nconst DEFAULT_FILL = \"#000000\";\n\nconst PhoneCallRingIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, fill = DEFAULT_FILL, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 19 19\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M11.5253 1.30593C11.5508 1.21075 11.5947 1.12151 11.6547 1.04333C11.7147 0.965143 11.7894 0.899537 11.8748 0.85026C11.9601 0.800983 12.0543 0.769 12.152 0.756139C12.2496 0.743278 12.3489 0.749791 12.4441 0.775306C13.8344 1.13807 15.103 1.86491 16.119 2.88096C17.1351 3.89702 17.8619 5.16556 18.2247 6.55593C18.2502 6.6511 18.2567 6.75036 18.2439 6.84805C18.231 6.94573 18.199 7.03993 18.1497 7.12525C18.1005 7.21057 18.0349 7.28534 17.9567 7.3453C17.8785 7.40526 17.7893 7.44922 17.6941 7.47468C17.6307 7.49132 17.5655 7.49983 17.5 7.49999C17.3347 7.49999 17.1741 7.44539 17.043 7.34469C16.912 7.24399 16.8179 7.10282 16.7753 6.94312C16.4795 5.80811 15.8863 4.77253 15.0569 3.94314C14.2275 3.11375 13.1919 2.52054 12.0569 2.22468C11.9616 2.19932 11.8723 2.15543 11.794 2.09552C11.7157 2.0356 11.65 1.96084 11.6006 1.87551C11.5513 1.79018 11.5192 1.69595 11.5063 1.59822C11.4933 1.50048 11.4998 1.40116 11.5253 1.30593ZM11.3069 5.22468C12.5997 5.56968 13.4303 6.40031 13.7753 7.69312C13.8179 7.85282 13.912 7.99399 14.043 8.09469C14.1741 8.19539 14.3347 8.24999 14.5 8.24999C14.5655 8.24983 14.6307 8.24132 14.6941 8.22468C14.7893 8.19922 14.8785 8.15526 14.9567 8.0953C15.0349 8.03534 15.1005 7.96057 15.1497 7.87525C15.199 7.78993 15.231 7.69573 15.2439 7.59805C15.2567 7.50036 15.2502 7.4011 15.2247 7.30593C14.7447 5.50968 13.4903 4.25531 11.6941 3.77531C11.5019 3.72396 11.2971 3.75107 11.1249 3.85067C10.9527 3.95027 10.8271 4.1142 10.7758 4.3064C10.7244 4.4986 10.7516 4.70332 10.8512 4.87553C10.9508 5.04774 11.1147 5.17334 11.3069 5.22468ZM18.9888 14.1637C18.8216 15.4341 18.1977 16.6001 17.2337 17.4441C16.2696 18.2881 15.0313 18.7523 13.75 18.75C6.30626 18.75 0.250008 12.6937 0.250008 5.24999C0.247712 3.9687 0.711903 2.73039 1.55588 1.76633C2.39986 0.802276 3.56592 0.178406 4.83626 0.0112434C5.1575 -0.0279808 5.4828 0.0377391 5.76362 0.198592C6.04444 0.359445 6.2657 0.606804 6.39438 0.903743L8.37438 5.32406V5.33531C8.4729 5.56261 8.51359 5.81077 8.49282 6.05763C8.47204 6.30449 8.39044 6.54236 8.25532 6.74999C8.23845 6.77531 8.22063 6.79874 8.20188 6.82218L6.25001 9.13593C6.9522 10.5628 8.4447 12.0422 9.89032 12.7462L12.1722 10.8047C12.1946 10.7858 12.2181 10.7683 12.2425 10.7522C12.45 10.6138 12.6887 10.5293 12.937 10.5064C13.1853 10.4835 13.4354 10.5229 13.6647 10.6209L13.6769 10.6266L18.0934 12.6056C18.3909 12.7338 18.6389 12.9549 18.8003 13.2358C18.9616 13.5166 19.0278 13.8422 18.9888 14.1637ZM17.5 13.9762C17.5 13.9762 17.4934 13.9762 17.4897 13.9762L13.0834 12.0028L10.8006 13.9444C10.7785 13.9631 10.7553 13.9807 10.7313 13.9969C10.5154 14.1409 10.2659 14.2264 10.0071 14.2452C9.74828 14.2639 9.48904 14.2152 9.2547 14.1037C7.49876 13.2553 5.74845 11.5181 4.89907 9.78093C4.7866 9.5483 4.73613 9.29055 4.75255 9.03267C4.76898 8.7748 4.85174 8.52554 4.99282 8.30906C5.00872 8.28364 5.02659 8.2595 5.04626 8.23687L7.00001 5.92031L5.03126 1.51406C5.03089 1.51032 5.03089 1.50655 5.03126 1.50281C4.12212 1.6214 3.28739 2.06733 2.68339 2.7571C2.0794 3.44687 1.74755 4.33316 1.75001 5.24999C1.75348 8.43153 3.01888 11.4818 5.26856 13.7314C7.51825 15.9811 10.5685 17.2465 13.75 17.25C14.6663 17.2531 15.5523 16.9225 16.2425 16.3198C16.9327 15.7171 17.3797 14.8837 17.5 13.9753V13.9762Z\" fill={fill} />\n  </Svg>\n);\n\nconst PhoneCallIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, fill = DEFAULT_FILL, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 17 17\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M15.3727 11.3798L11.6922 9.73056L11.682 9.72587C11.491 9.64415 11.2825 9.61135 11.0756 9.63045C10.8687 9.64954 10.6698 9.71993 10.4969 9.83524C10.4765 9.84869 10.457 9.86329 10.4383 9.87899L8.53673 11.5001C7.33204 10.9149 6.08829 9.68055 5.50313 8.49149L7.12657 6.56102C7.14219 6.54149 7.15704 6.52196 7.1711 6.50087C7.28394 6.32845 7.35239 6.13081 7.37039 5.92553C7.38838 5.72026 7.35534 5.51372 7.27423 5.3243V5.31493L5.62032 1.62821C5.51309 1.38076 5.3287 1.17463 5.09468 1.04058C4.86067 0.906541 4.58958 0.851774 4.32188 0.884461C3.26326 1.02376 2.29155 1.54366 1.58824 2.34704C0.884919 3.15042 0.498093 4.18234 0.500007 5.25009C0.500007 11.4532 5.54688 16.5001 11.75 16.5001C12.8177 16.502 13.8497 16.1152 14.6531 15.4119C15.4564 14.7085 15.9763 13.7368 16.1156 12.6782C16.1484 12.4106 16.0937 12.1396 15.9598 11.9056C15.8259 11.6716 15.62 11.4871 15.3727 11.3798ZM11.75 15.2501C9.09873 15.2472 6.55687 14.1927 4.68214 12.318C2.8074 10.4432 1.7529 7.90136 1.75001 5.25009C1.74707 4.48719 2.02192 3.7493 2.52324 3.17423C3.02456 2.59916 3.71806 2.22623 4.47423 2.12509C4.47392 2.1282 4.47392 2.13134 4.47423 2.13446L6.11485 5.80634L4.50001 7.73915C4.48362 7.75801 4.46873 7.77812 4.45548 7.7993C4.33791 7.97971 4.26894 8.18743 4.25525 8.40232C4.24157 8.61722 4.28362 8.83201 4.37735 9.02587C5.08516 10.4735 6.54376 11.9212 8.00704 12.6282C8.20232 12.7211 8.41835 12.7617 8.63403 12.7461C8.8497 12.7304 9.05763 12.6592 9.23751 12.5391C9.25757 12.5256 9.27687 12.511 9.29532 12.4954L11.1945 10.8751L14.8664 12.5196C14.8664 12.5196 14.8727 12.5196 14.875 12.5196C14.7751 13.2769 14.4027 13.9718 13.8275 14.4743C13.2524 14.9769 12.5138 15.2527 11.75 15.2501Z\" fill={fill} />\n  </Svg>\n);\n\nconst PhoneEndCallIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, fill = DEFAULT_FILL, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 20 16\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M4.21328 0.704679C4.15839 0.642809 4.09177 0.592448 4.01728 0.556515C3.94278 0.520582 3.8619 0.499791 3.77931 0.495348C3.69672 0.490905 3.61408 0.502898 3.53616 0.530632C3.45824 0.558365 3.3866 0.601288 3.32539 0.656913C3.26419 0.712537 3.21463 0.779756 3.17959 0.854675C3.14455 0.929593 3.12473 1.01072 3.12128 1.09336C3.11783 1.17599 3.13081 1.25849 3.15948 1.33607C3.18814 1.41365 3.23192 1.48477 3.28828 1.5453L5.44375 3.91718C4.12152 4.47256 2.92021 5.28033 1.90703 6.2953C0.344526 7.8578 0.194526 10.1594 1.54062 11.8945C1.70579 12.1059 1.93457 12.2585 2.19315 12.3298C2.45172 12.4011 2.72639 12.3874 2.97656 12.2906L6.80468 10.9336L6.82734 10.925C7.02045 10.8478 7.19125 10.7236 7.32426 10.5637C7.45727 10.4039 7.54829 10.2133 7.58906 10.0094L8.05 7.7039C8.26906 7.62838 8.49236 7.56578 8.71875 7.5164L15.7898 15.2953C15.8447 15.3572 15.9113 15.4075 15.9858 15.4435C16.0603 15.4794 16.1412 15.5002 16.2238 15.5046C16.3064 15.5091 16.389 15.4971 16.467 15.4694C16.5449 15.4416 16.6165 15.3987 16.6777 15.3431C16.7389 15.2874 16.7885 15.2202 16.8235 15.1453C16.8586 15.0704 16.8784 14.9893 16.8818 14.9066C16.8853 14.824 16.8723 14.7415 16.8436 14.6639C16.815 14.5863 16.7712 14.5152 16.7148 14.4547L4.21328 0.704679ZM7.62734 6.52655C7.42378 6.59909 7.24251 6.72315 7.1012 6.88664C6.9599 7.05013 6.86339 7.24745 6.82109 7.45937L6.36015 9.76405L2.54921 11.1156C2.5414 11.1156 2.53593 11.1258 2.52812 11.1289C1.56484 9.88671 1.66874 8.29921 2.79062 7.1789C3.79625 6.17293 5.00827 5.39726 6.34296 4.90546L7.77265 6.4789C7.72421 6.49452 7.67578 6.50937 7.62734 6.52655ZM18.4594 11.8945C18.2942 12.1059 18.0654 12.2585 17.8068 12.3298C17.5483 12.4011 17.2736 12.3874 17.0234 12.2906L16.3008 12.0344C16.2234 12.0069 16.1522 11.9645 16.0913 11.9096C16.0303 11.8546 15.9808 11.7882 15.9455 11.7141C15.8742 11.5644 15.8653 11.3925 15.9207 11.2363C15.9481 11.159 15.9906 11.0878 16.0455 11.0268C16.1005 10.9658 16.1669 10.9163 16.241 10.881C16.3907 10.8097 16.5625 10.8008 16.7187 10.8562L17.4508 11.1156L17.4742 11.125C18.4352 9.88671 18.3336 8.29921 17.2094 7.1789C15.2047 5.17421 12.375 4.11093 9.44765 4.26405C9.36558 4.26831 9.28346 4.25636 9.20601 4.22889C9.12855 4.20141 9.05726 4.15895 8.99621 4.10392C8.93517 4.0489 8.88556 3.98238 8.85021 3.90819C8.81487 3.83399 8.79449 3.75355 8.79023 3.67148C8.78597 3.5894 8.79792 3.50729 8.8254 3.42983C8.85287 3.35237 8.89534 3.28109 8.95036 3.22004C9.00539 3.15899 9.0719 3.10938 9.1461 3.07404C9.2203 3.03869 9.30073 3.01831 9.38281 3.01405C12.6641 2.84296 15.8383 4.03749 18.093 6.2953C19.6547 7.85702 19.8055 10.1594 18.4594 11.8945Z\" fill={fill} />\n  </Svg>\n);\n\nconst MicrophoneIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, fill = DEFAULT_FILL, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 14 19\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M7 12.75C7.99424 12.749 8.94747 12.3535 9.65051 11.6505C10.3535 10.9475 10.749 9.99424 10.75 9V4C10.75 3.00544 10.3549 2.05161 9.65165 1.34835C8.94839 0.645088 7.99456 0.25 7 0.25C6.00544 0.25 5.05161 0.645088 4.34835 1.34835C3.64509 2.05161 3.25 3.00544 3.25 4V9C3.25103 9.99424 3.64645 10.9475 4.34949 11.6505C5.05253 12.3535 6.00576 12.749 7 12.75ZM4.5 4C4.5 3.33696 4.76339 2.70107 5.23223 2.23223C5.70107 1.76339 6.33696 1.5 7 1.5C7.66304 1.5 8.29893 1.76339 8.76777 2.23223C9.23661 2.70107 9.5 3.33696 9.5 4V9C9.5 9.66304 9.23661 10.2989 8.76777 10.7678C8.29893 11.2366 7.66304 11.5 7 11.5C6.33696 11.5 5.70107 11.2366 5.23223 10.7678C4.76339 10.2989 4.5 9.66304 4.5 9V4ZM7.625 15.2188V17.75C7.625 17.9158 7.55915 18.0747 7.44194 18.1919C7.32473 18.3092 7.16576 18.375 7 18.375C6.83424 18.375 6.67527 18.3092 6.55806 18.1919C6.44085 18.0747 6.375 17.9158 6.375 17.75V15.2188C4.8341 15.062 3.40607 14.3393 2.36707 13.1907C1.32806 12.042 0.751903 10.5489 0.75 9C0.75 8.83424 0.815848 8.67527 0.933058 8.55806C1.05027 8.44085 1.20924 8.375 1.375 8.375C1.54076 8.375 1.69973 8.44085 1.81694 8.55806C1.93415 8.67527 2 8.83424 2 9C2 10.3261 2.52678 11.5979 3.46447 12.5355C4.40215 13.4732 5.67392 14 7 14C8.32608 14 9.59785 13.4732 10.5355 12.5355C11.4732 11.5979 12 10.3261 12 9C12 8.83424 12.0658 8.67527 12.1831 8.55806C12.3003 8.44085 12.4592 8.375 12.625 8.375C12.7908 8.375 12.9497 8.44085 13.0669 8.55806C13.1842 8.67527 13.25 8.83424 13.25 9C13.2481 10.5489 12.6719 12.042 11.6329 13.1907C10.5939 14.3393 9.1659 15.062 7.625 15.2188Z\" fill={fill} />\n  </Svg>\n);\n\nconst ChatIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, fill = DEFAULT_FILL, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 18 18\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M17.1305 13.5905C17.5623 12.6948 17.7742 11.709 17.7486 10.7149C17.7229 9.72084 17.4604 8.74725 16.983 7.87501C16.5055 7.00276 15.8267 6.25704 15.0032 5.69978C14.1796 5.14253 13.2349 4.78982 12.2477 4.67097C11.9192 3.9072 11.4416 3.21664 10.8429 2.63974C10.2442 2.06284 9.53637 1.6112 8.76093 1.31126C7.98549 1.01131 7.158 0.869103 6.32692 0.892953C5.49584 0.916802 4.67787 1.10623 3.9209 1.45015C3.16394 1.79407 2.48321 2.28556 1.91857 2.89584C1.35393 3.50612 0.916724 4.22293 0.632564 5.00429C0.348404 5.78565 0.222999 6.61585 0.263692 7.44628C0.304386 8.27671 0.510359 9.09067 0.869551 9.8405L0.301582 11.771C0.238079 11.9865 0.233833 12.2151 0.289291 12.4328C0.344749 12.6506 0.457861 12.8493 0.616727 13.0082C0.775593 13.167 0.97434 13.2801 1.19206 13.3356C1.40978 13.3911 1.63842 13.3868 1.85393 13.3233L3.7844 12.7553C4.40426 13.0532 5.06884 13.2472 5.75158 13.3296C6.08328 14.1068 6.56914 14.8086 7.17979 15.3927C7.79043 15.9768 8.51318 16.431 9.30434 16.7279C10.0955 17.0247 10.9386 17.158 11.7828 17.1198C12.6269 17.0815 13.4546 16.8725 14.2156 16.5053L16.1461 17.0733C16.3615 17.1367 16.5901 17.141 16.8077 17.0855C17.0253 17.0301 17.224 16.9171 17.3828 16.7583C17.5417 16.5996 17.6548 16.4009 17.7103 16.1834C17.7659 15.9658 17.7618 15.7372 17.6985 15.5218L17.1305 13.5905ZM3.84377 11.4608C3.78404 11.461 3.72463 11.4694 3.66721 11.4858L1.50002 12.1249L2.1383 9.95613C2.1837 9.79944 2.16603 9.63122 2.08908 9.48738C1.5237 8.43002 1.35711 7.2047 1.61968 6.03477C1.88225 4.86485 2.5565 3.82824 3.51951 3.1139C4.48252 2.39957 5.67017 2.05508 6.86595 2.14324C8.06173 2.2314 9.18601 2.74633 10.0339 3.59417C10.8817 4.44201 11.3966 5.5663 11.4848 6.76208C11.5729 7.95786 11.2285 9.1455 10.5141 10.1085C9.79979 11.0715 8.76318 11.7458 7.59325 12.0083C6.42333 12.2709 5.198 12.1043 4.14065 11.5389C4.04972 11.4886 3.94768 11.4618 3.84377 11.4608ZM15.8586 13.7053L16.5 15.8749L14.3313 15.2366C14.1746 15.1912 14.0064 15.2089 13.8625 15.2858C12.7116 15.9004 11.3662 16.0411 10.113 15.678C8.85983 15.3149 7.79803 14.4767 7.15393 13.3421C8.00969 13.2527 8.83776 12.9875 9.58619 12.5631C10.3346 12.1386 10.9873 11.5641 11.5032 10.8755C12.0191 10.1869 12.3871 9.39916 12.5842 8.56163C12.7813 7.72409 12.8032 6.85486 12.6485 6.00847C13.3941 6.18423 14.0893 6.52896 14.6806 7.01605C15.2718 7.50315 15.7432 8.11959 16.0584 8.81779C16.3736 9.51599 16.5242 10.2773 16.4985 11.0429C16.4728 11.8085 16.2715 12.558 15.9102 13.2335C15.8324 13.3782 15.8147 13.5477 15.861 13.7053H15.8586Z\" fill={fill} />\n  </Svg>\n);\n\nconst HistoryIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, fill = DEFAULT_FILL, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 17 16\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M9.625 4.25002V7.64612L12.4469 9.33909C12.589 9.42445 12.6914 9.56279 12.7316 9.72366C12.7717 9.88453 12.7463 10.0548 12.6609 10.1969C12.5756 10.339 12.4372 10.4414 12.2764 10.4816C12.1155 10.5217 11.9453 10.4963 11.8031 10.411L8.67812 8.53596C8.58563 8.48039 8.50911 8.40183 8.45599 8.30791C8.40287 8.21399 8.37497 8.10792 8.375 8.00002V4.25002C8.375 4.08426 8.44085 3.92529 8.55806 3.80808C8.67527 3.69087 8.83424 3.62502 9 3.62502C9.16576 3.62502 9.32473 3.69087 9.44194 3.80808C9.55915 3.92529 9.625 4.08426 9.625 4.25002ZM9 0.500023C8.01406 0.497567 7.03742 0.690675 6.12661 1.06817C5.21579 1.44566 4.38889 2.00005 3.69375 2.69924C3.12578 3.27424 2.62109 3.82737 2.125 4.40627V3.00002C2.125 2.83426 2.05915 2.67529 1.94194 2.55808C1.82473 2.44087 1.66576 2.37502 1.5 2.37502C1.33424 2.37502 1.17527 2.44087 1.05806 2.55808C0.940848 2.67529 0.875 2.83426 0.875 3.00002V6.12502C0.875 6.29078 0.940848 6.44975 1.05806 6.56697C1.17527 6.68418 1.33424 6.75002 1.5 6.75002H4.625C4.79076 6.75002 4.94973 6.68418 5.06694 6.56697C5.18415 6.44975 5.25 6.29078 5.25 6.12502C5.25 5.95926 5.18415 5.80029 5.06694 5.68308C4.94973 5.56587 4.79076 5.50002 4.625 5.50002H2.82812C3.38672 4.84221 3.94297 4.22268 4.57734 3.58049C5.44598 2.71186 6.55133 2.11847 7.75529 1.87446C8.95924 1.63045 10.2084 1.74665 11.3467 2.20853C12.485 2.67041 13.4619 3.45749 14.1555 4.47144C14.849 5.48538 15.2283 6.68121 15.2461 7.90952C15.2639 9.13782 14.9193 10.3441 14.2554 11.3777C13.5915 12.4113 12.6377 13.2263 11.5132 13.7209C10.3888 14.2155 9.1435 14.3678 7.93299 14.1587C6.72249 13.9496 5.60043 13.3885 4.70703 12.5453C4.64732 12.4889 4.57708 12.4448 4.50032 12.4155C4.42356 12.3862 4.34179 12.3724 4.25967 12.3747C4.17754 12.377 4.09668 12.3955 4.0217 12.429C3.94672 12.4626 3.87908 12.5106 3.82266 12.5703C3.76623 12.63 3.72212 12.7003 3.69283 12.777C3.66355 12.8538 3.64967 12.9356 3.652 13.0177C3.65432 13.0998 3.67279 13.1807 3.70636 13.2557C3.73993 13.3306 3.78795 13.3983 3.84766 13.4547C4.73785 14.2948 5.82012 14.9042 7 15.2298C8.17989 15.5554 9.42153 15.5873 10.6166 15.3226C11.8116 15.058 12.9237 14.505 13.8559 13.7117C14.788 12.9184 15.5118 11.9091 15.9642 10.7718C16.4165 9.63442 16.5836 8.40366 16.4509 7.18689C16.3182 5.97011 15.8897 4.80431 15.2029 3.79122C14.516 2.77813 13.5916 1.94854 12.5104 1.37485C11.4292 0.801167 10.224 0.50082 9 0.500023Z\" fill={fill} />\n  </Svg>\n);\n\nconst ArrowRightIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, fill = DEFAULT_FILL, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 256 256\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M227.32,28.68a16,16,0,0,0-15.66-4.08l-.15,0L19.57,82.84a16,16,0,0,0-2.49,29.8L102,154l41.3,84.87A15.86,15.86,0,0,0,157.74,248q.69,0,1.38-.06a15.88,15.88,0,0,0,14-11.51l58.2-191.94c0-.05,0-.1,0-.15A16,16,0,0,0,227.32,28.68ZM157.83,231.85l-.05.14,0-.07-40.06-82.3,48-48a8,8,0,0,0-11.31-11.31l-48,48L24.08,98.25l-.07,0,.14,0L216,40Z\" fill={fill} />\n  </Svg>\n);\n\n// The brand mark paints its own strokes and fills — `fill` is ignored, as on web.\nconst RinggAiIcon: IconComponent = ({ size = DEFAULT_SIZE, width, height, style, testID }) => (\n  <Svg testID={testID} viewBox=\"0 0 30 31\" width={width ?? size} height={height ?? size} style={style}>\n    <Path d=\"M2.33836 25.8591C2.32963 26.2022 2.58051 26.4188 2.90888 26.3661C3.15878 26.3258 3.34088 26.1572 3.53558 26.0172C5.34692 24.712 7.32487 23.7335 9.43263 22.9812C11.49 22.2462 13.6568 22.1312 15.7791 21.7671C18.5242 21.2975 21.2954 20.9563 23.9408 20.0257C25.5875 19.4508 27.2002 18.8135 28.687 17.9059C29.0154 17.7056 29.3263 17.444 29.0861 17.0147C28.8459 16.5854 28.5001 16.8498 28.2096 16.9878C26.5697 17.7734 24.87 18.4303 23.1261 18.9525C19.8987 19.9041 16.5637 20.2941 13.2461 20.7685C9.35416 21.3243 5.88451 22.8135 2.77812 25.1768C2.54758 25.355 2.36644 25.5735 2.33836 25.8591Z\" fill=\"white\" stroke=\"white\" strokeWidth=\"0.789474\" />\n    <Path d=\"M29.3604 13.1643C29.3779 12.74 29.0807 12.5106 28.7124 12.6469C28.4429 12.7602 28.1795 12.8874 27.9231 13.028C25.8484 14.0541 23.7055 14.89 21.4164 15.2869C18.4297 15.8082 15.44 16.3139 12.4513 16.8342C8.42668 17.534 4.81134 19.1862 1.53711 21.6097C0.945592 22.0467 0.797471 22.4387 1.04987 22.769C1.30225 23.0992 1.54295 23.0434 2.1861 22.5897C4.52484 20.9364 7.03997 19.6302 9.79484 18.8383C12.5146 18.0544 15.326 17.7437 18.1022 17.2537C20.3523 16.8558 22.6277 16.5903 24.7813 15.7573C26.1914 15.2115 27.5742 14.6117 28.8468 13.7836C29.0914 13.6239 29.337 13.4544 29.3604 13.1643Z\" fill=\"white\" stroke=\"white\" strokeWidth=\"0.789474\" />\n    <Path d=\"M0.837274 18.3214C0.845042 18.7597 1.21893 18.9989 1.61418 18.7901C1.91329 18.6309 2.18423 18.42 2.46975 18.2365C5.45114 16.312 8.6355 14.8964 12.1423 14.2549C15.4966 13.6417 18.8848 13.2171 22.2071 12.435C24.5505 11.8834 26.7773 11.0173 28.8273 9.73247C29.1643 9.5206 29.5401 9.27944 29.2663 8.80787C28.9817 8.31969 28.6089 8.64384 28.2951 8.80299C26.0956 9.93946 23.7939 10.7898 21.3651 11.2565C19.1908 11.6744 17.0115 12.0767 14.8217 12.4057C11.6557 12.8822 8.56555 13.5871 5.67061 15.0145C4.12845 15.7751 2.6397 16.6216 1.26166 17.6565C1.04218 17.8234 0.823671 17.9992 0.837274 18.3214Z\" fill=\"white\" stroke=\"white\" strokeWidth=\"0.789474\" />\n    <Path d=\"M29.1706 5.18743C29.1706 4.74357 28.8611 4.59203 28.3805 4.83058C25.4943 6.26384 22.4515 7.16329 19.2705 7.65507C16.3902 8.0999 13.4972 8.50466 10.6577 9.17338C7.26364 9.97213 4.12157 11.3702 1.29671 13.4487C1.11021 13.5771 0.941662 13.7299 0.795578 13.9033C0.625291 14.1214 0.573716 14.3834 0.784874 14.618C0.996033 14.8527 1.2393 14.8536 1.49133 14.7089C1.68595 14.5955 1.87473 14.4655 2.06155 14.3355C4.21952 12.8555 6.58876 11.7136 9.08819 10.9488C11.6542 10.1452 14.3253 9.90663 16.9487 9.41389C19.3347 8.96611 21.7557 8.70214 24.0717 7.91023C25.6851 7.35785 27.2751 6.7605 28.7181 5.82878C28.9555 5.67627 29.1803 5.51495 29.1706 5.18743Z\" fill=\"white\" stroke=\"white\" strokeWidth=\"0.789474\" />\n  </Svg>\n);\n\nexport { ArrowRightIcon, ChatIcon, HistoryIcon, MicrophoneIcon, PhoneCallIcon, PhoneCallRingIcon, PhoneEndCallIcon, RinggAiIcon };\n","/**\n * `PortableStyles` → React Native styles.\n *\n * `PortableStyles` (core `types/config.ts`) is the deliberately small subset of\n * CSS the config surface accepts precisely so it can cross platforms. Web hands\n * the values straight to the DOM; RN cannot — it has no CSS parser, so a\n * `\"16px\"` string silently breaks layout instead of throwing.\n *\n * This is the one place that converts. Rules, matching the Dart port\n * (`flutter/lib/src/ui/widgets/portable_styles.dart`):\n *  - numbers pass through as density-independent pixels;\n *  - `\"16px\"` / `\"16\"` → `16`;\n *  - `\"50%\"` survives only where RN accepts percentages (width/height);\n *  - anything else (`calc()`, `em`, `auto`, gradients in `backgroundColor`) is\n *    dropped rather than guessed at — a dropped style degrades, a wrong one\n *    corrupts the layout.\n */\n\nimport type { ViewStyle } from \"react-native\";\nimport type { PortableStyles } from \"@ringg/core\";\n\n/** RN accepts percentage strings only for these dimensions. */\ntype Dimension = number | `${number}%` | undefined;\n\nconst PERCENT = /^-?\\d+(\\.\\d+)?%$/;\n\nconst isPercent = (value: string): value is `${number}%` => PERCENT.test(value.trim());\n\n/** `\"16px\"`, `\"16\"`, `16` → `16`. Returns undefined for anything unparseable. */\nconst toNumber = (value: string | number | undefined): number | undefined => {\n  if (value === undefined) return undefined;\n  if (typeof value === \"number\") return Number.isFinite(value) ? value : undefined;\n  const trimmed = value.trim();\n  const numeric = trimmed.endsWith(\"px\") ? trimmed.slice(0, -2) : trimmed;\n  const parsed = Number(numeric);\n  return Number.isFinite(parsed) && numeric.trim() !== \"\" ? parsed : undefined;\n};\n\n/** Width/height: numbers and percentages both survive. */\nconst toDimension = (value: string | number | undefined): Dimension => {\n  if (typeof value === \"string\" && isPercent(value)) return value.trim() as `${number}%`;\n  return toNumber(value);\n};\n\n/**\n * Drop `undefined` entries so the result can be spread over a base style\n * without punching holes in it (`{...base, ...portable}` with an explicit\n * `undefined` would erase the base value).\n */\nconst compact = (style: ViewStyle): ViewStyle => {\n  const result: Record<string, unknown> = {};\n  for (const [key, value] of Object.entries(style)) {\n    if (value !== undefined) result[key] = value;\n  }\n  return result as ViewStyle;\n};\n\n/** Convert a config `PortableStyles` bag into an RN `ViewStyle`. */\nexport const toViewStyle = (styles: PortableStyles | undefined): ViewStyle => {\n  if (!styles) return {};\n  return compact({\n    width: toDimension(styles.width),\n    height: toDimension(styles.height),\n    // Gradient strings are not valid RN colors — the gradient-aware surfaces\n    // read `theme.primaryColor` through <GradientFill> instead.\n    backgroundColor: typeof styles.backgroundColor === \"string\" && !styles.backgroundColor.includes(\"(\") ? styles.backgroundColor : undefined,\n    padding: toNumber(styles.padding),\n    borderRadius: toNumber(styles.borderRadius),\n  });\n};\n\n/** Icon sizing from `ButtonIconConfig.size` (same parsing, single value). */\nexport const toSize = (value: string | number | undefined, fallback: number): number => toNumber(value) ?? fallback;\n","/**\n * Node identifiers for integrators and end-to-end tests.\n *\n * The web widget tags every meaningful node with `data-ringg=\"...\"` and treats\n * those names as a contract — integrators select on them, so renaming one is a\n * breaking change. RN has no attribute namespace, but it has `testID`, which\n * surfaces to the same audiences (Detox, Maestro, Appium, the native view\n * hierarchy).\n *\n * So the mapping is mechanical and total: `data-ringg=\"header-title\"` becomes\n * `testID=\"ringg-header-title\"`. The prefix keeps widget nodes from colliding\n * with the host app's own testIDs, and the suffix stays byte-identical to web\n * so one selector list documents both platforms.\n */\n\n/** `\"header-title\"` → `\"ringg-header-title\"`. */\nexport const ringgId = (name: string): string => `ringg-${name}`;\n","/**\n * Widget theme for React Native.\n *\n * Deliberately thin: the theme VALUES (defaults, presets) and the merge/\n * contrast LOGIC both come from `@ringg/core` — `mergeWidgetTheme` here is\n * core's function, not a copy. The web package still carries its own copy of\n * that table for byte-fidelity with agents-cdn; RN has no such legacy to match\n * and takes the shared one, so a token change reaches this platform through\n * codegen (AGENTS.md rule 2).\n *\n * What IS local is unit translation. The theme surface is CSS-shaped\n * (`\"16px\"`, `\"9999px\"`, `fontFamily: \"inherit\"`) because that's the contract\n * integrators already write against on web; RN needs numbers and a real family\n * name, so the `resolve*` helpers below are the single conversion point.\n */\n\nimport { createContext, useContext, useMemo, type FC, type ReactNode } from \"react\";\nimport { DEFAULT_WIDGET_THEME, getButtonRadius, mergeWidgetTheme, type ButtonStyle, type ResolvedWidgetTheme, type WidgetTheme } from \"@ringg/core\";\n\ninterface WidgetThemeProviderProps {\n  theme?: WidgetTheme;\n  children: ReactNode;\n}\n\n/** CSS's \"no explicit family — use whatever the platform gives you\". */\nconst INHERIT = \"inherit\";\n\n/**\n * `borderRadius: \"9999px\"` is the web idiom for a pill. RN clamps the radius\n * to half the shorter side anyway, so any large number reads as a pill — but\n * it must be finite: `Infinity` crashes the shadow-node layout pass.\n */\nconst PILL_RADIUS = 9999;\n\nconst WidgetThemeContext = createContext<ResolvedWidgetTheme>(DEFAULT_WIDGET_THEME);\n\n/** `\"16px\"` → `16`. Unparseable values fall back rather than laying out as NaN. */\nexport const resolveRadius = (value: string | undefined, fallback = 0): number => {\n  if (value === undefined) return fallback;\n  const numeric = Number(value.trim().endsWith(\"px\") ? value.trim().slice(0, -2) : value.trim());\n  if (!Number.isFinite(numeric)) return fallback;\n  return Math.min(numeric, PILL_RADIUS);\n};\n\n/** Button corner radius as an RN number, from core's shared style → CSS mapping. */\nexport const resolveButtonRadius = (style: ButtonStyle | undefined): number => resolveRadius(getButtonRadius(style));\n\n/**\n * `\"inherit\"` has no meaning in RN — there is no cascade. Returning undefined\n * lets `<Text>` fall through to the platform system font, which is what\n * \"inherit\" resolves to on web for an unstyled host page.\n */\nexport const resolveFontFamily = (fontFamily: string | undefined): string | undefined => (!fontFamily || fontFamily === INHERIT ? undefined : fontFamily);\n\nexport const WidgetThemeProvider: FC<WidgetThemeProviderProps> = ({ theme, children }) => {\n  const merged = useMemo(() => mergeWidgetTheme(theme), [theme]);\n  return <WidgetThemeContext.Provider value={merged}>{children}</WidgetThemeContext.Provider>;\n};\n\nexport const useWidgetTheme = (): ResolvedWidgetTheme => useContext(WidgetThemeContext);\n","/**\n * The widget's one touch target.\n *\n * Web gets `:hover` and `:disabled` from CSS for free. RN has neither, so the\n * feedback the whole widget relies on — dim on press, dim harder when disabled,\n * never fire while disabled — has to be written once and reused, or every\n * component invents a slightly different one.\n *\n * `hitSlop` is not a nicety here: several of these are 18–28dp icon buttons\n * (mute, minimize, close) that sit below the 44dp touch target both platforms'\n * accessibility guidelines ask for. Expanding the touch area keeps the visual\n * design identical to web while making the buttons reachable.\n */\n\nimport type { FC, ReactNode } from \"react\";\nimport { Pressable, StyleSheet, type StyleProp, type ViewStyle } from \"react-native\";\n\nexport interface TouchableProps {\n  onPress?: () => void;\n  /** For press-driven animation; the opacity feedback is handled internally. */\n  onPressIn?: () => void;\n  onPressOut?: () => void;\n  disabled?: boolean;\n  style?: StyleProp<ViewStyle>;\n  /** `data-ringg` equivalent — pass the bare name, `ringgId` adds the prefix. */\n  testID?: string;\n  accessibilityLabel?: string;\n  /** Extra touch area beyond the visual bounds, in dp. Defaults to 8. */\n  hitSlop?: number;\n  children?: ReactNode;\n}\n\n/** Matches the web widget's `hover:opacity-90` / `disabled:opacity-50`. */\nconst PRESSED_OPACITY = 0.9;\nconst DISABLED_OPACITY = 0.5;\n\nconst DEFAULT_HIT_SLOP = 8;\n\nexport const Touchable: FC<TouchableProps> = ({ onPress, onPressIn, onPressOut, disabled = false, style, testID, accessibilityLabel, hitSlop = DEFAULT_HIT_SLOP, children }) => (\n  <Pressable\n    testID={testID}\n    accessibilityRole=\"button\"\n    accessibilityLabel={accessibilityLabel}\n    accessibilityState={{ disabled }}\n    // `disabled` alone stops the press; the opacity below states it visually.\n    disabled={disabled}\n    onPress={onPress}\n    onPressIn={onPressIn}\n    onPressOut={onPressOut}\n    hitSlop={hitSlop}\n    style={({ pressed }) => [style, disabled ? styles.disabled : pressed ? styles.pressed : null]}\n  >\n    {children}\n  </Pressable>\n);\n\nconst styles = StyleSheet.create({\n  pressed: { opacity: PRESSED_OPACITY },\n  disabled: { opacity: DISABLED_OPACITY },\n});\n","/**\n * Call controls — what the widget shows while a session is live.\n *\n * Two shapes, same as web: a text call gets the message input pill, an audio\n * call gets the mute + end-call pair. Nothing else lives here; sending goes\n * through `onSendMessage` (the core controller) and hanging up through\n * `onCallEnd`.\n *\n * The one deliberate divergence from web is where mic state comes from. Web\n * reads `localParticipant.isMicrophoneEnabled` through LiveKit's React context,\n * which costs a `RoomContext.Provider` wrapped around the whole tree. On RN the\n * widget already holds the Room — the transport hands it back — so the current\n * state and the toggle arrive as props instead: one provider fewer, and this\n * component keeps knowing nothing about transports. A caller that cannot offer\n * a toggle (no room yet) simply omits `onToggleMic` and gets no mute button\n * rather than a dead one.\n */\n\nimport { useState, type FC } from \"react\";\nimport { StyleSheet, View } from \"react-native\";\nimport { MicOff } from \"lucide-react-native\";\nimport type { RinggWidgetConfig, SlashCommand } from \"@ringg/core\";\n\nimport { solidColor } from \"../lib/gradient\";\nimport { MicrophoneIcon, PhoneEndCallIcon } from \"../lib/icons\";\nimport { toViewStyle } from \"../lib/portable-styles\";\nimport { ringgId } from \"../lib/testing\";\nimport { useWidgetTheme } from \"../lib/widget-theme\";\nimport MessageInput from \"./message-input\";\nimport { Touchable } from \"./ui/pressable\";\n\ninterface CallControlProps {\n  isCalling: boolean;\n  callMode: \"text\" | \"audio\";\n  buttonConfig?: RinggWidgetConfig[\"buttons\"];\n  enabledSlashCommands?: SlashCommand[];\n  onSlashCommand?: (command: SlashCommand) => void;\n  onCallEnd?: () => void;\n  // Fired the instant the user submits a text message (before the agent reply\n  // arrives) so the transcript can show the typing indicator right away.\n  onUserMessage?: () => void;\n  /** Sends the message through the core controller (replaces useChat().send). */\n  onSendMessage?: (message: string) => Promise<void>;\n  /** Live mic state, owned by whoever owns the Room. Defaults to on. */\n  micEnabled?: boolean;\n  /** Flips the mic. Absent (no room yet) leaves the button inert, not hidden. */\n  onToggleMic?: () => void;\n}\n\ninterface AudioCallControlsProps {\n  micEnabled: boolean;\n  onToggleMic?: () => void;\n  buttonConfig?: RinggWidgetConfig[\"buttons\"];\n  onCallEnd?: () => void;\n}\n\n/** Web's `h-5 w-5` on both control icons. */\nconst ICON_SIZE = 20;\n\n/** Web's `text-white` on the end-call glyph — fixed, not themed. */\nconst END_CALL_ICON_COLOR = \"#ffffff\";\n\n/**\n * Markup parity with web's AudioControlsView: a centred pair of 48dp circles,\n * no labels. Theme colours go through `solidColor` because RN rejects a\n * gradient string outright where the DOM would merely ignore it, and neither\n * `backgroundColor` nor `errorColor` is a gradient-bearing theme field.\n */\nconst AudioControlsView: FC<AudioCallControlsProps> = ({ micEnabled, onToggleMic, buttonConfig, onCallEnd }) => {\n  const theme = useWidgetTheme();\n  const handleCallEndTrigger = () => onCallEnd?.();\n  const micStyles = toViewStyle(buttonConfig?.mic?.styles);\n\n  return (\n    <View testID={ringgId(\"call-controls\")} style={styles.row}>\n      {/* Always rendered, even with no room to toggle — web does the same with a\n          no-op handler. A voice call that shows one control where the user\n          expects two reads as a broken call, not as a degraded one. */}\n      <Touchable\n        testID={ringgId(\"mute-button\")}\n        // The muted flag has no attribute namespace to live in on RN; the\n        // accessibility label carries the state, exactly as web's aria-label does.\n        accessibilityLabel={micEnabled ? \"Mute\" : \"Unmute\"}\n        onPress={onToggleMic ?? (() => {})}\n        style={[styles.circle, styles.muteButton, { backgroundColor: solidColor(theme.backgroundColor), borderColor: solidColor(theme.borderColor) }, micStyles]}\n      >\n        {micEnabled ? <MicrophoneIcon size={ICON_SIZE} fill={solidColor(theme.textColor)} /> : <MicOff size={ICON_SIZE} color={solidColor(theme.textColor)} />}\n      </Touchable>\n      <Touchable\n        testID={ringgId(\"end-call-button\")}\n        accessibilityLabel=\"End call\"\n        onPress={handleCallEndTrigger}\n        // Source quirk kept: the mic style override spreads on BOTH buttons.\n        style={[styles.circle, { backgroundColor: solidColor(theme.errorColor) }, micStyles]}\n      >\n        <PhoneEndCallIcon size={ICON_SIZE} fill={END_CALL_ICON_COLOR} />\n      </Touchable>\n    </View>\n  );\n};\n\nconst CallControls: FC<CallControlProps> = ({ isCalling, callMode, buttonConfig, enabledSlashCommands, onSlashCommand, onUserMessage, onCallEnd, onSendMessage, micEnabled = true, onToggleMic }) => {\n  // Mirrors LiveKit useChat().isSending — true while a send is in flight.\n  const [isSending, setIsSending] = useState(false);\n\n  const handleSendMessage = async (message: string) => {\n    // Surface the typing indicator immediately — a reply is always expected, so\n    // we don't wait for the agent's stream to open.\n    onUserMessage?.();\n    setIsSending(true);\n    try {\n      await onSendMessage?.(message);\n    } finally {\n      setIsSending(false);\n    }\n  };\n\n  if (!isCalling) return null;\n\n  switch (callMode) {\n    case \"text\":\n      return <MessageInput isSending={isSending} enabledSlashCommands={enabledSlashCommands} onMessageSubmit={handleSendMessage} onSlashCommand={onSlashCommand} />;\n    case \"audio\":\n      return <AudioControlsView micEnabled={micEnabled} onToggleMic={onToggleMic} buttonConfig={buttonConfig} onCallEnd={onCallEnd} />;\n    default:\n      return null;\n  }\n};\n\nexport default CallControls;\n\nconst styles = StyleSheet.create({\n  row: { flexDirection: \"row\", width: \"100%\", justifyContent: \"center\", alignItems: \"center\", gap: 24 },\n  circle: { height: 48, width: 48, borderRadius: 9999, alignItems: \"center\", justifyContent: \"center\" },\n  muteButton: { borderWidth: 1 },\n});\n","/**\n * The chat composer — RN counterpart of the web widget's `message-input.tsx`.\n *\n * Web drives the field with react-hook-form + zod. Neither survives the\n * crossing and neither is missed: there is no form element to submit and no\n * browser validation to suppress, so the draft is one piece of local UI state\n * and the whole of the schema (`z.string().min(1)`) is the length check in\n * `submitDraft`.\n *\n * The web pill is frosted glass — 60% background plus `backdrop-filter: blur`\n * over the scrolling transcript. RN has no backdrop filter on either platform,\n * so the pill is painted solid in `theme.backgroundColor`: the exact colour web\n * itself falls back to whenever the command menu is open.\n *\n * The field is multiline here because a phone keyboard has no horizontal\n * scroll worth typing into; it grows with the text up to a cap and only then\n * scrolls internally.\n */\n\nimport { type FC, useCallback, useMemo, useState } from \"react\";\nimport { StyleSheet, TextInput, View, type TextInputContentSizeChangeEvent } from \"react-native\";\nimport { ArrowUp } from \"lucide-react-native\";\n\nimport { GradientFill, solidColor } from \"../lib/gradient\";\nimport { filterSlashCommands, type SlashCommand } from \"../lib/slash-command-types\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveFontFamily, useWidgetTheme } from \"../lib/widget-theme\";\nimport SlashCommandMenu from \"./slash-command-menu\";\nimport { Touchable } from \"./ui/pressable\";\n\ninterface MessageInputProps {\n  isSending?: boolean;\n  enabledSlashCommands?: SlashCommand[];\n  onMessageSubmit?: (message: string) => void;\n  onSlashCommand?: (command: SlashCommand) => void;\n}\n\n/** `text-[15px]`. */\nconst INPUT_FONT_SIZE = 15;\n\n/**\n * Web pairs `text-[15px]` with no leading class, so the line box is whatever\n * the platform renders. 20 is the working figure for this size and is used\n * only to place the single line and to size the growth cap.\n */\nconst INPUT_LINE_HEIGHT = 20;\n\n/** `h-12` — the collapsed pill: one line plus its padding. */\nconst MIN_INPUT_HEIGHT = 48;\n\n/** Beyond four lines the field keeps its height and scrolls its own content. */\nconst MAX_INPUT_LINES = 4;\nconst MAX_INPUT_HEIGHT = MIN_INPUT_HEIGHT + (MAX_INPUT_LINES - 1) * INPUT_LINE_HEIGHT;\n\n/** Centres the single line inside the collapsed pill. */\nconst INPUT_VERTICAL_PADDING = (MIN_INPUT_HEIGHT - INPUT_LINE_HEIGHT) / 2;\n\n/** The container's two shapes: `rounded-full` closed, `rounded-xl` with the menu open. */\nconst PILL_RADIUS = 9999;\nconst MENU_OPEN_RADIUS = 12;\n\nconst SEND_BUTTON_SIZE = 32;\n\n/**\n * Both platforms report the measured text height with the field's own padding\n * included, so the number is directly comparable to the pill height and the\n * clamp needs no per-platform correction.\n */\nconst clampInputHeight = (height: number): number => Math.min(Math.max(height, MIN_INPUT_HEIGHT), MAX_INPUT_HEIGHT);\n\nconst MessageInput: FC<MessageInputProps> = ({ isSending, enabledSlashCommands, onMessageSubmit, onSlashCommand }) => {\n  const theme = useWidgetTheme();\n  const [message, setMessage] = useState(\"\");\n  const [activeCommandIndex, setActiveCommandIndex] = useState(0);\n  const [inputHeight, setInputHeight] = useState(MIN_INPUT_HEIGHT);\n\n  const isSlashQuery = message.startsWith(\"/\");\n  const availableCommands = enabledSlashCommands ?? [];\n\n  const filteredCommands = useMemo(() => {\n    if (!isSlashQuery || availableCommands.length === 0) return [];\n    return filterSlashCommands(availableCommands, message);\n  }, [isSlashQuery, availableCommands, message]);\n\n  const showMenu = isSlashQuery && filteredCommands.length > 0;\n\n  const clearDraft = useCallback(() => {\n    setMessage(\"\");\n    setActiveCommandIndex(0);\n    // Clearing the value does re-measure the field, but not before the next\n    // frame; resetting the height here keeps the pill from staying tall.\n    setInputHeight(MIN_INPUT_HEIGHT);\n  }, []);\n\n  const handleSelectCommand = useCallback(\n    (command: SlashCommand) => {\n      // Web writes the command into the field and resets the form on the next\n      // line, so an empty draft is the only observable end state.\n      if (onSlashCommand) {\n        onSlashCommand(command);\n      } else {\n        onMessageSubmit?.(command.command);\n      }\n      clearDraft();\n    },\n    [clearDraft, onMessageSubmit, onSlashCommand],\n  );\n\n  const submitDraft = useCallback(() => {\n    // Web's zod schema is `min(1)` and nothing else: whitespace is a message\n    // there, an empty string is silently dropped with no error under the pill.\n    if (message.length === 0) return;\n    onMessageSubmit?.(message);\n    clearDraft();\n  }, [clearDraft, message, onMessageSubmit]);\n\n  const handleSubmitEditing = useCallback(() => {\n    // Return carries the same intent as web's Enter: take the highlighted\n    // command while the menu is open, otherwise send the draft. The rest of\n    // web's key handling (ArrowUp/ArrowDown to move, Tab to accept, Escape to\n    // clear) has no counterpart on a soft keyboard and is dropped — the list\n    // is navigated by tapping it.\n    if (!showMenu) {\n      submitDraft();\n      return;\n    }\n    // noUncheckedIndexedAccess guard — showMenu guarantees a non-empty list\n    // and the index is reset on every keystroke, so this always hits.\n    const command = filteredCommands[activeCommandIndex];\n    if (command) handleSelectCommand(command);\n  }, [activeCommandIndex, filteredCommands, handleSelectCommand, showMenu, submitDraft]);\n\n  const handleChangeText = useCallback((value: string) => {\n    setMessage(value);\n    setActiveCommandIndex(0);\n  }, []);\n\n  const handleContentSizeChange = useCallback((event: TextInputContentSizeChangeEvent) => {\n    setInputHeight(clampInputHeight(event.nativeEvent.contentSize.height));\n  }, []);\n\n  const borderColor = solidColor(theme.borderColor);\n\n  return (\n    <View testID={ringgId(\"message-input-form\")}>\n      {/* Single unified container: command list on top, input on bottom. */}\n      <View\n        testID={ringgId(\"message-input\")}\n        style={[styles.container, { backgroundColor: theme.backgroundColor, borderColor, borderRadius: showMenu ? MENU_OPEN_RADIUS : PILL_RADIUS }]}\n      >\n        {showMenu ? <SlashCommandMenu commands={filteredCommands} activeIndex={activeCommandIndex} theme={theme} onSelect={handleSelectCommand} onActiveIndexChange={setActiveCommandIndex} /> : null}\n        {/* Web floats the send button over a full-width field; a flex row lands\n            it in the same place without absolute positioning, and keeps it on\n            the last line rather than mid-pill once the field has grown. */}\n        <View testID={ringgId(\"message-input-row\")} style={[styles.row, showMenu ? { borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: borderColor } : null]}>\n          <TextInput\n            testID={ringgId(\"message-input-field\")}\n            value={message}\n            onChangeText={handleChangeText}\n            onContentSizeChange={handleContentSizeChange}\n            onSubmitEditing={handleSubmitEditing}\n            placeholder={availableCommands.length > 0 ? \"Type /command...\" : \"Type here...\"}\n            // Web leaves the placeholder to the browser's own grey; RN draws\n            // nothing unless it is given a colour.\n            placeholderTextColor={theme.mutedTextColor}\n            autoComplete=\"off\"\n            multiline\n            returnKeyType=\"send\"\n            // A multiline field treats Return as a newline unless told\n            // otherwise, and the deprecated `blurOnSubmit={false}` suppresses\n            // the submit event entirely. \"submit\" is the one setting that both\n            // fires onSubmitEditing and leaves the keyboard up between messages.\n            submitBehavior=\"submit\"\n            // Android decorates a bare input with an underline; the pill's own\n            // border is the only edge this design has.\n            underlineColorAndroid=\"transparent\"\n            style={[styles.input, { height: inputHeight, color: theme.textColor, fontFamily: resolveFontFamily(theme.fontFamily) }]}\n          />\n          <Touchable onPress={submitDraft} disabled={isSending} testID={ringgId(\"message-send-button\")} accessibilityLabel=\"Send message\" style={styles.sendButton}>\n            <GradientFill color={theme.primaryColor} style={styles.sendButtonSurface}>\n              <ArrowUp size={16} color={theme.primaryTextColor} />\n            </GradientFill>\n          </Touchable>\n        </View>\n      </View>\n    </View>\n  );\n};\n\nexport default MessageInput;\n\nconst styles = StyleSheet.create({\n  container: { borderWidth: StyleSheet.hairlineWidth, overflow: \"hidden\" },\n  row: { flexDirection: \"row\", alignItems: \"flex-end\" },\n  input: {\n    flex: 1,\n    fontSize: INPUT_FONT_SIZE,\n    paddingLeft: 20,\n    // 12 here plus the button's 32 and its 4 of margin reproduce web's `pr-12`.\n    paddingRight: 12,\n    paddingVertical: INPUT_VERTICAL_PADDING,\n    // Text grows downward from the top edge instead of re-centring on Android.\n    textAlignVertical: \"top\",\n  },\n  sendButton: { marginRight: 4, marginBottom: (MIN_INPUT_HEIGHT - SEND_BUTTON_SIZE) / 2 },\n  sendButtonSurface: { width: SEND_BUTTON_SIZE, height: SEND_BUTTON_SIZE, borderRadius: PILL_RADIUS, alignItems: \"center\", justifyContent: \"center\" },\n});\n","// Used in: src/components/slash-command-menu.tsx, src/components/message-input.tsx\n//\n// The `SlashCommand` type is owned by @ringg/core — re-exported here so the\n// ported components keep their original import path; only the pure\n// `filterSlashCommands` helper lives locally (verbatim from agents-cdn).\n\nimport type { SlashCommand } from \"@ringg/core\";\n\nexport type { SlashCommand, SlashCommandToolType } from \"@ringg/core\";\n\nexport function filterSlashCommands(commands: SlashCommand[], query: string): SlashCommand[] {\n  if (!query.startsWith(\"/\")) return [];\n  const search = query.slice(1).toLowerCase();\n  if (!search) return commands;\n  return commands.filter(\n    (cmd) => cmd.command.slice(1).toLowerCase().includes(search) || cmd.display_name.toLowerCase().includes(search),\n  );\n}\n","/**\n * The slash-command palette — RN counterpart of the web widget's\n * `slash-command-menu.tsx`. It sits inside the composer pill, above the field,\n * in the same single container web uses.\n *\n * Two web affordances are gone rather than faked. Arrow-key navigation has no\n * equivalent on a soft keyboard, which also removes the reason for web's\n * scroll-the-active-row-into-view effect: `activeIndex` can now only move to a\n * row the user can already see and touch. And hover, the other thing that moved\n * it, becomes the tap that selects the row.\n *\n * A tap has to land while the keyboard is up — that is the only state this menu\n * is ever visible in — so `keyboardShouldPersistTaps` is load-bearing: without\n * it the first tap is spent dismissing the keyboard.\n */\n\nimport type { FC } from \"react\";\nimport { ScrollView, StyleSheet, Text, View } from \"react-native\";\nimport { Command } from \"lucide-react-native\";\n\nimport { solidColor } from \"../lib/gradient\";\nimport type { SlashCommand } from \"../lib/slash-command-types\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveFontFamily } from \"../lib/widget-theme\";\nimport { Touchable } from \"./ui/pressable\";\n\n/** Web's inline palette plus the family: RN text inherits nothing from above. */\ninterface SlashCommandMenuTheme {\n  backgroundColor: string;\n  surfaceColor: string;\n  borderColor: string;\n  textColor: string;\n  mutedTextColor: string;\n  primaryColor: string;\n  fontFamily: string;\n}\n\ninterface SlashCommandMenuProps {\n  commands: SlashCommand[];\n  activeIndex: number;\n  theme: SlashCommandMenuTheme;\n  onSelect: (command: SlashCommand) => void;\n  onActiveIndexChange: (index: number) => void;\n}\n\n/** `max-h-[180px]` — roughly four rows before the list scrolls. */\nconst LIST_MAX_HEIGHT = 180;\n\n/** Hex alpha on the active row's icon tile, web's `+ \"18\"` (~9%). */\nconst ACTIVE_ICON_ALPHA = \"18\";\n\nconst SIX_DIGIT_HEX = /^#[0-9a-f]{6}$/i;\n\n/**\n * The active tile is the primary colour at a whisper of opacity, which web\n * expresses by suffixing hex alpha. RN rejects a colour string it cannot parse\n * instead of ignoring it, so a primary that is not six-digit hex (`rgb(...)`, a\n * named colour, a gradient reduced to either) keeps the flat surface.\n */\nconst iconBackground = (theme: SlashCommandMenuTheme, isActive: boolean): string => {\n  if (!isActive) return theme.surfaceColor;\n  const primary = solidColor(theme.primaryColor);\n  return SIX_DIGIT_HEX.test(primary) ? `${primary}${ACTIVE_ICON_ALPHA}` : theme.surfaceColor;\n};\n\nconst SlashCommandMenu: FC<SlashCommandMenuProps> = ({ commands, activeIndex, theme, onSelect, onActiveIndexChange }) => {\n  if (commands.length === 0) return null;\n\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n  const primaryColor = solidColor(theme.primaryColor);\n\n  return (\n    <View testID={ringgId(\"slash-command-menu\")}>\n      <View testID={ringgId(\"slash-command-header\")} style={[styles.header, { borderBottomColor: solidColor(theme.borderColor) }]}>\n        <Text testID={ringgId(\"slash-command-heading\")} style={[styles.heading, { color: theme.mutedTextColor, fontFamily }]}>\n          Commands\n        </Text>\n      </View>\n      <ScrollView testID={ringgId(\"slash-command-list\")} style={styles.list} contentContainerStyle={styles.listContent} keyboardShouldPersistTaps=\"handled\">\n        {commands.map((cmd, index) => {\n          const isActive = index === activeIndex;\n          return (\n            <Touchable\n              key={cmd.command}\n              testID={ringgId(\"slash-command-item\")}\n              // Web also marks the row active on hover; here the tap that\n              // selects it is the only pointer event there is. The fill is the\n              // whole of that signal — a testID carries one value, so web's\n              // `data-ringg-active` has nowhere to go.\n              onPress={() => {\n                onActiveIndexChange(index);\n                onSelect(cmd);\n              }}\n              // Rows are stacked and already tall enough to hit; the default\n              // touch expansion would only overlap their neighbours.\n              hitSlop={0}\n              style={[styles.item, { backgroundColor: isActive ? theme.surfaceColor : \"transparent\" }]}\n            >\n              <View testID={ringgId(\"slash-command-icon\")} style={[styles.icon, { backgroundColor: iconBackground(theme, isActive) }]}>\n                <Command size={12} color={primaryColor} />\n              </View>\n              <View testID={ringgId(\"slash-command-text\")} style={styles.text}>\n                <Text testID={ringgId(\"slash-command-name\")} style={[styles.name, { color: theme.textColor, fontFamily }]}>\n                  {cmd.display_name}\n                </Text>\n                {/* Web hangs the untruncated description off `title`; the\n                    accessibility label is where text the eye cannot finish\n                    reading lives on this platform. */}\n                <Text testID={ringgId(\"slash-command-description\")} style={[styles.description, { color: theme.mutedTextColor, fontFamily }]} numberOfLines={1} accessibilityLabel={cmd.description}>\n                  {cmd.description}\n                </Text>\n              </View>\n            </Touchable>\n          );\n        })}\n      </ScrollView>\n    </View>\n  );\n};\n\nexport default SlashCommandMenu;\n\nconst styles = StyleSheet.create({\n  header: { paddingHorizontal: 12, paddingVertical: 8, borderBottomWidth: StyleSheet.hairlineWidth },\n  heading: { fontSize: 10, fontWeight: \"500\", textTransform: \"uppercase\", letterSpacing: 0.5 },\n  list: { maxHeight: LIST_MAX_HEIGHT },\n  listContent: { paddingVertical: 4 },\n  item: { flexDirection: \"row\", alignItems: \"flex-start\", gap: 10, paddingHorizontal: 12, paddingVertical: 8 },\n  icon: { marginTop: 2, flexShrink: 0, width: 24, height: 24, borderRadius: 6, alignItems: \"center\", justifyContent: \"center\" },\n  text: { flex: 1 },\n  name: { fontSize: 12, lineHeight: 16, fontWeight: \"500\" },\n  description: { fontSize: 10 },\n});\n","/**\n * Post-call rating screen — RN counterpart of the web widget's\n * `feedback-screen.tsx`.\n *\n * Two variants, the same two web has, chosen the same way. With messages worth\n * showing, the ended conversation stays readable and the rating hangs off the\n * bottom of it — tapping a star submits straight away, since there is no\n * comment box in that layout. With nothing to replay it falls back to the\n * centred card: title, star row, comment box, submit and skip.\n *\n * The replay is READ-ONLY. Components that were interactive during the call\n * render disabled, and their actions go nowhere: the session is over, so an\n * enabled control would be a promise the widget cannot keep.\n *\n * No conversation state lives here — the rating and the comment are the same\n * two pieces of draft UI state the web source keeps locally, and both leave\n * through `onSubmit` / `onSkip`.\n */\n\nimport { useMemo, useRef, useState, type ComponentRef, type FC } from \"react\";\nimport { Animated, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, Text, TextInput, View } from \"react-native\";\nimport Svg, { Path } from \"react-native-svg\";\nimport type { ChatMessage, MediaType, PortableStyles, RinggWidgetConfig } from \"@ringg/core\";\n\nimport { GradientFill, solidColor } from \"../lib/gradient\";\nimport { toViewStyle } from \"../lib/portable-styles\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveButtonRadius, resolveFontFamily, resolveRadius, useWidgetTheme } from \"../lib/widget-theme\";\nimport { Touchable } from \"./ui/pressable\";\nimport Header from \"./header\";\nimport InteractiveFlow from \"./interactive-flow\";\nimport MessageItem from \"./message-item\";\nimport BlocksStep from \"./steps/blocks-step\";\nimport { isBlocks, type ComponentActionResponse, type InteractiveFlowPayload, type SimpleComponentPayload } from \"../lib/component-types\";\n\ninterface FeedbackScreenProps {\n  callMode: MediaType;\n  isSubmitting: boolean;\n  feedbackScreenConfig?: RinggWidgetConfig[\"feedbackScreen\"];\n  /** The ended conversation, replayed above the rating when it has content. */\n  messages?: readonly ChatMessage[];\n  title?: string;\n  logoUrl?: string;\n  logoStyles?: PortableStyles;\n  onSubmit: (rating: number, comment: string) => void;\n  onSkip: () => void;\n}\n\ninterface StarIconProps {\n  filled: boolean;\n  filledColor: string;\n  emptyColor: string;\n  size?: number;\n  accessibilityLabel: string;\n  onPress: () => void;\n}\n\n/**\n * Hardcoded on web too: conventional amber and gray-300, NOT the theme primary\n * — a black brand primary made the stars read as ink blots.\n */\nconst DEFAULT_STAR_FILLED_COLOR = \"#F5A623\";\nconst DEFAULT_STAR_EMPTY_COLOR = \"#D1D5DB\";\n\n/** Tailwind preflight's `::placeholder` colour (gray-400), which web inherits. */\nconst PLACEHOLDER_COLOR = \"#9CA3AF\";\n\nconst DEFAULT_STARS_COUNT = 5;\n\n/** `w-8 h-8` on the card variant. */\nconst STAR_SIZE = 32;\n\nconst COMMENT_MAX_LENGTH = 500;\n\n/** Card radius, not button radius — a pill-shaped comment box reads badly. */\nconst COMMENT_RADIUS_FALLBACK = 16;\n\nconst SUBMIT_HEIGHT = 44;\n\n/**\n * The web screen's own star, path data verbatim — a rounded 24-viewBox glyph\n * that is NOT lucide's `Star`. Using lucide here looked close enough in\n * isolation and visibly wrong beside the web and Flutter widgets, which both\n * draw this outline.\n */\nconst STAR_PATH = \"M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z\";\nconst STAR_VIEW_BOX = 24;\nconst STAR_STROKE_WIDTH = 1.5;\n\n/** `hover:scale-110` on web; the same growth, driven by press on touch. */\nconst STAR_PRESS_SCALE = 1.1;\nconst STAR_PRESS_SPRING = { stiffness: 400, damping: 22, mass: 1 };\n\nconst StarIcon: FC<StarIconProps> = ({ filled, filledColor, emptyColor, size = STAR_SIZE, accessibilityLabel, onPress }) => {\n  const scale = useRef(new Animated.Value(1)).current;\n\n  const springTo = (toValue: number): void => {\n    Animated.spring(scale, { toValue, ...STAR_PRESS_SPRING, useNativeDriver: true }).start();\n  };\n\n  return (\n    <Touchable\n      onPress={onPress}\n      onPressIn={() => springTo(STAR_PRESS_SCALE)}\n      onPressOut={() => springTo(1)}\n      testID={ringgId(\"feedback-star\")}\n      accessibilityLabel={accessibilityLabel}\n      style={styles.star}\n    >\n      <Animated.View style={{ transform: [{ scale }] }}>\n        <Svg width={size} height={size} viewBox={`0 0 ${STAR_VIEW_BOX} ${STAR_VIEW_BOX}`}>\n          <Path\n            d={STAR_PATH}\n            fill={filled ? filledColor : \"none\"}\n            stroke={filled ? filledColor : emptyColor}\n            strokeWidth={STAR_STROKE_WIDTH}\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n          />\n        </Svg>\n      </Animated.View>\n    </Touchable>\n  );\n};\n\n/** The replayed flow still needs an api prop; nothing may actually call out. */\nconst noopApi = async (): Promise<ComponentActionResponse> => ({ success: true, message: \"\" });\n\n/** Web's `w-7 h-7` on the transcript variant, against `w-8 h-8` on the card. */\nconst TRANSCRIPT_STAR_SIZE = 28;\n\nconst FeedbackScreen: FC<FeedbackScreenProps> = ({ callMode, isSubmitting, feedbackScreenConfig, messages, title, logoUrl, logoStyles, onSubmit, onSkip }) => {\n  const theme = useWidgetTheme();\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  const [rating, setRating] = useState(0);\n  const [comment, setComment] = useState(\"\");\n  // CSS draws `focus:ring-2` for free; RN has no state selectors, so the field\n  // has to know it is focused to tint its border.\n  const [isCommentFocused, setIsCommentFocused] = useState(false);\n\n  const starsCount = feedbackScreenConfig?.starsCount ?? DEFAULT_STARS_COUNT;\n  const stars = Array.from({ length: starsCount }, (_, index) => index + 1);\n  const starFilledColor = feedbackScreenConfig?.starsStyles?.filledColor ?? DEFAULT_STAR_FILLED_COLOR;\n  const starEmptyColor = feedbackScreenConfig?.starsStyles?.emptyColor ?? DEFAULT_STAR_EMPTY_COLOR;\n\n  const isSubmitDisabled = rating === 0 || isSubmitting;\n  const submitOverrides = toViewStyle(feedbackScreenConfig?.submitBtnStyles);\n  // Web spreads `submitBtnStyles` over the themed background, so a configured\n  // colour wins. Here it has to win as the FILL as well: a gradient primary\n  // paints above `backgroundColor`, and would bury the override.\n  const submitFill = typeof submitOverrides.backgroundColor === \"string\" ? submitOverrides.backgroundColor : isSubmitDisabled ? theme.surfaceColor : theme.primaryColor;\n\n  const handleSubmit = () => {\n    if (rating > 0) onSubmit(rating, comment);\n  };\n\n  // Same filter web applies: system pills are chrome, a component without data\n  // and a message without text have nothing to replay.\n  const transcript = useMemo(\n    () => (messages ?? []).filter((message) => message.kind !== \"system\" && (message.componentType ? Boolean(message.componentData) : Boolean(message.message.trim()))),\n    [messages],\n  );\n\n  const scroller = useRef<ComponentRef<typeof ScrollView>>(null);\n\n  if (transcript.length > 0) {\n    return (\n      <View testID={ringgId(\"feedback-screen\")} style={styles.transcriptScreen}>\n        <Header isCalling isLoading={false} title={title ?? \"\"} description=\"\" logoUrl={logoUrl} logoStyles={logoStyles} />\n        <ScrollView\n          testID={ringgId(\"transcript\")}\n          ref={scroller}\n          style={styles.transcript}\n          contentContainerStyle={styles.transcriptList}\n          onContentSizeChange={() => scroller.current?.scrollToEnd({ animated: false })}\n          showsVerticalScrollIndicator={false}\n        >\n          {transcript.map((message, index) => {\n            if (message.componentType && message.componentData) {\n              // Core keeps blocks opaque; the structured contract lives in\n              // lib/component-types, hence the cast.\n              const componentData = message.componentData as unknown as SimpleComponentPayload | InteractiveFlowPayload;\n              if (isBlocks(componentData)) {\n                return (\n                  <View key={`c_${message.timestamp}__${index}`} testID={ringgId(\"blocks-widget\")} style={styles.replayed}>\n                    <BlocksStep config={componentData.data} disabled onAction={async () => {}} />\n                  </View>\n                );\n              }\n              return (\n                // pointerEvents none is what makes the replay read-only — the\n                // flow renders exactly as it did, and answers nothing.\n                <View key={`c_${message.timestamp}__${index}`} pointerEvents=\"none\" style={styles.replayed}>\n                  <InteractiveFlow initialComponent={componentData} onApiCall={noopApi} />\n                </View>\n              );\n            }\n            return <MessageItem key={`${message.timestamp}__${index}`} itemIndex={index} message={message} />;\n          })}\n\n          {/* The rating is the transcript's last entry, so it scrolls with it. */}\n          <View testID={ringgId(\"feedback-footer\")} style={styles.feedbackFooter}>\n            <View testID={ringgId(\"conversation-ended\")} style={styles.endedRow}>\n              <View style={[styles.endedRule, { backgroundColor: solidColor(theme.borderColor) }]} />\n              <Text style={[styles.endedLabel, { color: theme.mutedTextColor, fontFamily }]}>Conversation ended</Text>\n              <View style={[styles.endedRule, { backgroundColor: solidColor(theme.borderColor) }]} />\n            </View>\n            <Text testID={ringgId(\"feedback-prompt\")} style={[styles.description, { color: theme.mutedTextColor, fontFamily }]}>\n              {feedbackScreenConfig?.title ?? \"Please rate your experience\"}\n            </Text>\n            <View testID={ringgId(\"feedback-stars\")} style={styles.stars}>\n              {stars.map((star) => (\n                <StarIcon\n                  key={star}\n                  filled={star <= rating}\n                  filledColor={starFilledColor}\n                  emptyColor={starEmptyColor}\n                  size={TRANSCRIPT_STAR_SIZE}\n                  accessibilityLabel={`Rate ${star} of ${starsCount}`}\n                  onPress={() => {\n                    if (isSubmitting) return;\n                    setRating(star);\n                    // No comment box in this variant — the tap IS the rating.\n                    onSubmit(star, \"\");\n                  }}\n                />\n              ))}\n            </View>\n          </View>\n        </ScrollView>\n      </View>\n    );\n  }\n\n  return (\n    // iOS keeps the keyboard over the content; Android resizes the window\n    // itself, and padding on top of that double-counts the inset.\n    <KeyboardAvoidingView testID={ringgId(\"feedback-screen\")} behavior={Platform.OS === \"ios\" ? \"padding\" : undefined} style={styles.screen}>\n      <View testID={ringgId(\"feedback-header\")} style={styles.header}>\n        <Text testID={ringgId(\"feedback-title\")} style={[styles.title, { color: theme.textColor, fontFamily }]}>\n          {feedbackScreenConfig?.title ?? `How was your ${callMode === \"text\" ? \"chat\" : \"call\"}?`}\n        </Text>\n        <Text testID={ringgId(\"feedback-description\")} style={[styles.description, { color: theme.mutedTextColor, fontFamily }]}>\n          {feedbackScreenConfig?.description ?? \"Your feedback helps us improve!\"}\n        </Text>\n      </View>\n\n      <View testID={ringgId(\"feedback-stars\")} style={styles.stars}>\n        {stars.map((star) => (\n          <StarIcon\n            key={star}\n            // Web previews the hovered star; the selection is all touch has.\n            filled={star <= rating}\n            filledColor={starFilledColor}\n            emptyColor={starEmptyColor}\n            accessibilityLabel={`Rate ${star} of ${starsCount}`}\n            onPress={() => setRating(star)}\n          />\n        ))}\n      </View>\n\n      <TextInput\n        testID={ringgId(\"feedback-comment\")}\n        value={comment}\n        onChangeText={setComment}\n        placeholder={feedbackScreenConfig?.placeholder ?? \"We'd love to hear more...\"}\n        placeholderTextColor={PLACEHOLDER_COLOR}\n        multiline\n        // Android centres multiline text vertically; a textarea starts at the top.\n        textAlignVertical=\"top\"\n        maxLength={COMMENT_MAX_LENGTH}\n        onFocus={() => setIsCommentFocused(true)}\n        onBlur={() => setIsCommentFocused(false)}\n        style={[\n          styles.comment,\n          {\n            backgroundColor: solidColor(theme.backgroundColor),\n            color: theme.textColor,\n            // Web's focus ring sits OUTSIDE the border; growing a border here\n            // would reflow the box, so the border itself takes the accent.\n            borderColor: isCommentFocused ? solidColor(theme.primaryColor) : solidColor(theme.borderColor),\n            borderRadius: resolveRadius(theme.borderRadius, COMMENT_RADIUS_FALLBACK),\n            fontFamily,\n          },\n        ]}\n      />\n\n      <View testID={ringgId(\"feedback-actions\")} style={styles.actions}>\n        {/* Not the shared <Button>: this one is full-width, 44dp, and states\n            disabled as an inert surface chip rather than a faded primary. */}\n        <Touchable onPress={handleSubmit} disabled={isSubmitDisabled} testID={ringgId(\"feedback-submit\")}>\n          <GradientFill color={submitFill} style={[styles.submit, { borderRadius: resolveButtonRadius(theme.buttonStyle) }, submitOverrides]}>\n            <Text style={[styles.submitLabel, { color: isSubmitDisabled ? theme.mutedTextColor : theme.primaryTextColor, fontFamily }]} numberOfLines={1}>\n              {feedbackScreenConfig?.submitBtnCTA ?? \"Submit Feedback\"}\n            </Text>\n          </GradientFill>\n        </Touchable>\n        <Touchable onPress={onSkip} disabled={isSubmitting} testID={ringgId(\"feedback-skip\")} style={styles.skip}>\n          <Text style={[styles.skipLabel, { color: theme.mutedTextColor, fontFamily }]}>Skip</Text>\n        </Touchable>\n      </View>\n    </KeyboardAvoidingView>\n  );\n};\n\nexport default FeedbackScreen;\n\nconst styles = StyleSheet.create({\n  screen: { flex: 1, alignItems: \"center\", justifyContent: \"center\", padding: 24, gap: 16 },\n\n  // Transcript variant. The header floats over the list the same way it does\n  // during a live call, so the list clears it with padding rather than layout.\n  transcriptScreen: { flex: 1, padding: 8, gap: 8 },\n  transcript: { flex: 1 },\n  transcriptList: { flexGrow: 1, justifyContent: \"flex-end\", gap: 12, paddingTop: 48 },\n  replayed: { width: \"100%\" },\n  feedbackFooter: { gap: 10, paddingHorizontal: 8, paddingVertical: 8 },\n  endedRow: { flexDirection: \"row\", alignItems: \"center\", gap: 12 },\n  endedRule: { flex: 1, height: StyleSheet.hairlineWidth },\n  endedLabel: { fontSize: 13 },\n  header: { alignItems: \"center\" },\n  title: { fontSize: 18, lineHeight: 28, fontWeight: \"500\", textAlign: \"center\", marginBottom: 4 },\n  description: { fontSize: 15, lineHeight: 22, textAlign: \"center\" },\n  stars: { flexDirection: \"row\", gap: 4, marginVertical: 8 },\n  star: { padding: 4 },\n  comment: { alignSelf: \"stretch\", minHeight: 80, padding: 12, fontSize: 15, borderWidth: 1 },\n  actions: { alignSelf: \"stretch\", gap: 4, marginTop: 8 },\n  submit: { height: SUBMIT_HEIGHT, alignItems: \"center\", justifyContent: \"center\" },\n  submitLabel: { fontSize: 15, fontWeight: \"500\" },\n  skip: { paddingVertical: 8, alignItems: \"center\" },\n  skipLabel: { fontSize: 15 },\n});\n","/**\n * Widget header — RN port of the web widget's `components/header.tsx`.\n *\n * Two mutually exclusive layouts, kept as two separate trees exactly as on web:\n * the centred intro block that floats in the panel before a call, and the\n * compact bar pinned over the transcript during one. They are not one\n * parameterised layout because `ringg-header` is contractually calling-only —\n * integrators treat its presence as \"a call is live\" — while the intro block\n * answers to `ringg-intro`.\n */\n\nimport { useEffect, useRef, type FC } from \"react\";\nimport { Animated, Easing, Image, StyleSheet, Text, View, type StyleProp, type ViewStyle } from \"react-native\";\nimport type { PortableStyles } from \"@ringg/core\";\n\nimport { GradientFill, solidColor } from \"../lib/gradient\";\nimport { RinggAiIcon } from \"../lib/icons\";\nimport { toViewStyle } from \"../lib/portable-styles\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveFontFamily, useWidgetTheme } from \"../lib/widget-theme\";\n\ninterface HeaderProps {\n  isCalling: boolean;\n  isLoading: boolean;\n  title: string;\n  description: string;\n  logoUrl?: string;\n  logoStyles?: PortableStyles;\n}\n\ninterface HeaderLogoProps {\n  logoUrl: string | undefined;\n  logoStyles: PortableStyles | undefined;\n  /** Tile size and rounding — the only thing the two layouts disagree on. */\n  style: StyleProp<ViewStyle>;\n  /** Size of the fallback brand mark, inset inside the tile. */\n  markSize: number;\n}\n\ninterface StatusDotProps {\n  isLoading: boolean;\n  color: string;\n}\n\n/** Brand-mark sizes for the 64dp intro tile and the 36dp calling tile. */\nconst INTRO_MARK_SIZE = 32;\nconst CALLING_MARK_SIZE = 18;\n\n/** Tailwind's `animate-pulse`: opacity 1 → .5 → 1 over 2s, ease-in-out. */\nconst PULSE_MIN_OPACITY = 0.5;\nconst PULSE_HALF_CYCLE_MS = 1000;\nconst PULSE_EASING = Easing.bezier(0.4, 0, 0.6, 1);\n\n/**\n * Web frosts the calling bar — 60% transparent with `backdrop-filter: blur` —\n * so the transcript blurs through it. RN has no backdrop filter without a\n * native blur module, and 60% of a flat colour just leaves the transcript\n * legible *through* the title, so the bar is near-opaque instead: content\n * still scrolls underneath, only without the blur.\n */\nconst SCRIM_OPACITY = 0.96;\n\nconst HeaderLogo: FC<HeaderLogoProps> = ({ logoUrl, logoStyles, style, markSize }) => {\n  const theme = useWidgetTheme();\n\n  return (\n    // <GradientFill> owns the painted node, so the contract testID rides on a\n    // wrapper that shrink-wraps the tile and centres it on the cross axis (the\n    // intro's `mx-auto`; a no-op inside the already-centred calling row).\n    <View testID={ringgId(\"header-logo\")} style={styles.logoSlot}>\n      {/* Config styles land after the theme fill, matching web's spread order:\n          a flat override replaces a solid primaryColor, a gradient one still\n          paints over it (CSS `background` behaves the same way). */}\n      <GradientFill color={theme.primaryColor} style={[styles.logo, style, toViewStyle(logoStyles)]}>\n        {logoUrl ? (\n          <Image testID={ringgId(\"header-logo-image\")} accessibilityLabel=\"Logo\" source={{ uri: logoUrl }} resizeMode=\"contain\" style={styles.logoImage} />\n        ) : (\n          // Nothing is bundled here (web inlines its default logo as a data URI\n          // at build time), so the brand mark stands in until an integrator\n          // supplies logoUrl.\n          <View testID={ringgId(\"header-logo-image\")} style={styles.logoMark}>\n            <RinggAiIcon size={markSize} />\n          </View>\n        )}\n      </GradientFill>\n    </View>\n  );\n};\n\nconst StatusDot: FC<StatusDotProps> = ({ isLoading, color }) => {\n  const pulse = useRef(new Animated.Value(1)).current;\n\n  useEffect(() => {\n    if (!isLoading) {\n      pulse.setValue(1);\n      return;\n    }\n\n    const loop = Animated.loop(\n      Animated.sequence([\n        Animated.timing(pulse, { toValue: PULSE_MIN_OPACITY, duration: PULSE_HALF_CYCLE_MS, easing: PULSE_EASING, useNativeDriver: true }),\n        Animated.timing(pulse, { toValue: 1, duration: PULSE_HALF_CYCLE_MS, easing: PULSE_EASING, useNativeDriver: true }),\n      ]),\n    );\n    loop.start();\n\n    // Leaving the loop running would keep the animation driver awake for the\n    // rest of the call, long after the dot has settled on \"connected\".\n    return () => loop.stop();\n  }, [isLoading, pulse]);\n\n  return (\n    // Web carries the connecting flag as a second `data-ringg-connecting`\n    // attribute; RN has no attribute namespace, so the machine-readable half\n    // becomes `busy` and the colour carries the visual half.\n    <Animated.View testID={ringgId(\"header-status-dot\")} accessibilityState={{ busy: isLoading }} style={[styles.statusDot, { backgroundColor: color, opacity: pulse }]} />\n  );\n};\n\nconst Header: FC<HeaderProps> = ({ isCalling, isLoading, title, description, logoUrl, logoStyles }) => {\n  const theme = useWidgetTheme();\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  if (!isCalling)\n    return (\n      // flex-1 + centring: the logo/title/description block floats in the\n      // panel's free space so the start buttons and legal text sit low.\n      <View testID={ringgId(\"intro\")} style={styles.intro}>\n        <HeaderLogo logoUrl={logoUrl} logoStyles={logoStyles} style={styles.introLogo} markSize={INTRO_MARK_SIZE} />\n        <View testID={ringgId(\"header-text\")} style={styles.introText}>\n          <Text testID={ringgId(\"header-title\")} accessibilityRole=\"header\" style={[styles.introTitle, { color: theme.textColor, fontFamily }]}>\n            {title}\n          </Text>\n          {/* Stays up while connecting — the \"Connecting...\" status renders next to the loading bar instead */}\n          {description ? (\n            <Text testID={ringgId(\"header-description\")} style={[styles.introDescription, { color: theme.mutedTextColor, fontFamily }]}>\n              {description}\n            </Text>\n          ) : null}\n        </View>\n      </View>\n    );\n\n  return (\n    <View\n      testID={ringgId(\"header\")}\n      // Web puts the call status in an `sr-only` node; RN has no equivalent of\n      // visually-hidden text, so the announcement rides on the bar itself and\n      // the live region is what re-announces it once the call connects.\n      accessibilityLabel={isLoading ? \"Calling...\" : \"Call in Progress\"}\n      accessibilityLiveRegion=\"polite\"\n      style={styles.header}\n    >\n      <View pointerEvents=\"none\" style={[StyleSheet.absoluteFill, styles.scrim, { backgroundColor: solidColor(theme.backgroundColor) }]} />\n      <HeaderLogo logoUrl={logoUrl} logoStyles={logoStyles} style={styles.callingLogo} markSize={CALLING_MARK_SIZE} />\n      <View testID={ringgId(\"header-text\")} style={styles.headerText}>\n        <View style={styles.headerTitleRow}>\n          <Text testID={ringgId(\"header-title\")} accessibilityRole=\"header\" numberOfLines={1} style={[styles.callingTitle, { color: theme.textColor, fontFamily }]}>\n            {title}\n          </Text>\n          <StatusDot isLoading={isLoading} color={solidColor(isLoading ? theme.mutedTextColor : theme.successColor)} />\n        </View>\n        {description ? (\n          // Truncated on screen; web exposes the full string through a `title`\n          // tooltip, which here is the accessibility label.\n          <Text testID={ringgId(\"header-description\")} accessibilityLabel={description} numberOfLines={1} style={[styles.callingDescription, { color: theme.mutedTextColor, fontFamily }]}>\n            {description}\n          </Text>\n        ) : null}\n      </View>\n    </View>\n  );\n};\n\nexport default Header;\n\nconst styles = StyleSheet.create({\n  intro: { flex: 1, justifyContent: \"center\", gap: 16 },\n  introLogo: { width: 64, height: 64, borderRadius: 16 },\n  introText: { gap: 4 },\n  introTitle: { fontSize: 17, fontWeight: \"500\", textAlign: \"center\" },\n  // `leading-snug` (1.375) at 14px.\n  introDescription: { fontSize: 14, lineHeight: 19, fontWeight: \"400\", textAlign: \"center\", maxWidth: 210, alignSelf: \"center\" },\n\n  header: {\n    position: \"absolute\",\n    top: 0,\n    left: 0,\n    right: 0,\n    zIndex: 10,\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    justifyContent: \"flex-start\",\n    gap: 10,\n    paddingVertical: 12,\n    paddingLeft: 20,\n    // Clears the absolute minimize/close chrome so header content — including\n    // integrator-injected brand text — never slides under it.\n    paddingRight: 76,\n  },\n  scrim: { opacity: SCRIM_OPACITY },\n  callingLogo: { width: 36, height: 36, borderRadius: 12 },\n  headerText: { flexShrink: 1 },\n  headerTitleRow: { flexDirection: \"row\", alignItems: \"center\", gap: 8 },\n  // flexShrink lets the title truncate instead of pushing the dot out of view.\n  callingTitle: { fontSize: 15, fontWeight: \"600\", flexShrink: 1 },\n  callingDescription: { fontSize: 13, fontWeight: \"400\" },\n  statusDot: { width: 6, height: 6, borderRadius: 3, flexShrink: 0 },\n\n  logoSlot: { alignSelf: \"center\", flexShrink: 0 },\n  logo: { alignItems: \"center\", justifyContent: \"center\", overflow: \"hidden\" },\n  logoImage: { width: \"100%\", height: \"100%\" },\n  logoMark: { alignItems: \"center\", justifyContent: \"center\" },\n});\n","/**\n * Interactive component router — RN counterpart of the web widget's\n * `components/interactive-flow.tsx`.\n *\n * Everything about sequencing lives here: which step is on screen, what is\n * collected from each one, and how the last one reports back (RPC when the host\n * gave us `onSendResponse`, the legacy `on_complete` API call otherwise). That\n * behaviour is deliberately identical to web — the backend renders against it,\n * so a divergence shows up as a flow that never finishes.\n *\n * Three things could not cross verbatim:\n *  - Web publishes the merged component theme through a React context that the\n *    step files read. RN has no such module, so every step re-derives the same\n *    widget→component mapping from `useWidgetTheme()`. A `theme` on a *flow*\n *    payload therefore styles the card chrome but does not reach the steps; a\n *    `theme` on a single component still reaches its step, because the step\n *    receives that same payload.\n *  - `color-mix(in srgb, surface 50%, background)` has no RN equivalent. The\n *    tint is painted as a half-opaque surface layer over the background, which\n *    is the same sRGB compositing the CSS function performs.\n *  - `AnimatePresence` exits are dropped. RN cannot defer an unmount without a\n *    layout-animation dependency, so steps swap on their enter animation only.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type FC, type ReactNode } from \"react\";\nimport { Animated, Linking, StyleSheet, Text, View, type StyleProp, type ViewStyle } from \"react-native\";\nimport { Check, ChevronLeft } from \"lucide-react-native\";\n\nimport { buildPayload, formatSlotDate, formatSlotTime, isButtons, isInteractiveFlow, type ComponentActionResponse, type ConfirmationData, type FlowStep, type InteractiveFlowPayload, type SimpleComponentPayload } from \"../lib/component-types\";\nimport { GradientFill, solidColor } from \"../lib/gradient\";\nimport { ringgId } from \"../lib/testing\";\nimport { mergeTheme, toNumber } from \"../lib/theme-utils\";\nimport { resolveFontFamily, useWidgetTheme } from \"../lib/widget-theme\";\nimport ButtonsStep from \"./steps/buttons-step\";\nimport CalendarStep from \"./steps/calendar-step\";\nimport ConfirmationStep from \"./steps/confirmation-step\";\nimport FormStep from \"./steps/form-step\";\nimport { Touchable } from \"./ui/pressable\";\nimport { AnimatedSwap } from \"./ui/swap\";\n\ntype FormValue = string | number | boolean | string[];\n\ninterface InteractiveFlowProps {\n  // Can receive either a single component or a full flow\n  initialComponent: SimpleComponentPayload | InteractiveFlowPayload;\n  onApiCall: (method: \"POST\" | \"GET\", endpoint: string, payload: Record<string, string>) => Promise<ComponentActionResponse>;\n  onComplete?: (allData: Record<string, FormValue>) => void;\n  // Callback to send response back via RPC (for render_component_<name>_response pattern)\n  onSendResponse?: (componentId: string, responseData: Record<string, unknown>) => Promise<void>;\n  // When provided, a `selected_item` final-step selection is reported up to the\n  // parent instead of being rendered as an in-card pill — the parent can then\n  // show the choice as a regular (right-aligned) user chat message.\n  onSelectionDisplayed?: (componentId: string, label: string) => void;\n  // How free-presentation quick replies align within the panel:\n  // \"center\" for voice mode, \"end\" (right) for chat mode.\n  quickReplyAlign?: \"center\" | \"end\";\n}\n\ninterface EnterFadeProps {\n  /** Starting offset in dp; the value animates to 0 as the node fades in. */\n  translateX?: number;\n  translateY?: number;\n  durationMs?: number;\n  style?: StyleProp<ViewStyle>;\n  testID?: string;\n  children?: ReactNode;\n}\n\n/** framer-motion's default enter; the step swap overrides it with its own 200ms. */\nconst ENTER_DURATION_MS = 300;\nconst STEP_ENTER_DURATION_MS = 200;\n\nconst CARD_ENTER_OFFSET = 10;\nconst STEP_ENTER_OFFSET = 20;\nconst PILL_ENTER_OFFSET = 8;\n\n/** The `50%` of web's `color-mix`, applied as an alpha instead. */\nconst SURFACE_TINT_OPACITY = 0.5;\n\n/** `theme.borderRadius` default, kept numeric for the card. */\nconst DEFAULT_CARD_RADIUS = 8;\n\n/** Best-effort: an unhandled scheme must not take the widget down. */\nconst openExternalUrl = (url: string): void => {\n  void Linking.openURL(url).catch(() => {});\n};\n\nconst EnterFade: FC<EnterFadeProps> = ({ translateX = 0, translateY = 0, durationMs = ENTER_DURATION_MS, style, testID, children }) => {\n  const progress = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    Animated.timing(progress, { toValue: 1, duration: durationMs, useNativeDriver: true }).start();\n  }, [durationMs, progress]);\n\n  return (\n    <Animated.View\n      testID={testID}\n      style={[\n        style,\n        {\n          opacity: progress,\n          transform: [\n            { translateX: progress.interpolate({ inputRange: [0, 1], outputRange: [translateX, 0] }) },\n            { translateY: progress.interpolate({ inputRange: [0, 1], outputRange: [translateY, 0] }) },\n          ],\n        },\n      ]}\n    >\n      {children}\n    </Animated.View>\n  );\n};\n\nconst InteractiveFlow: FC<InteractiveFlowProps> = ({ initialComponent, onApiCall, onComplete, onSendResponse, onSelectionDisplayed, quickReplyAlign = \"end\" }) => {\n  // Determine if this is a multi-step flow or single component\n  const isMultiStepFlow = isInteractiveFlow(initialComponent);\n  const isFreeButtonGroup = !isMultiStepFlow && isButtons(initialComponent) && initialComponent.data.presentation === \"free\";\n\n  // Get widget theme as base, then merge with component theme\n  const widgetTheme = useWidgetTheme();\n\n  // Get theme from payload, using widget theme as fallback for colors\n  const theme = useMemo(\n    () =>\n      mergeTheme({\n        primaryColor: widgetTheme.primaryColor,\n        primaryTextColor: widgetTheme.primaryTextColor,\n        backgroundColor: widgetTheme.backgroundColor, // Cards sit on the panel as bordered white surfaces\n        surfaceColor: widgetTheme.surfaceColor,\n        textColor: widgetTheme.textColor,\n        mutedTextColor: widgetTheme.mutedTextColor,\n        borderColor: widgetTheme.borderColor,\n        ...initialComponent.theme,\n      }),\n    [initialComponent.theme, widgetTheme],\n  );\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  // For multi-step flow, extract steps; for single component, wrap it\n  const flowSteps: FlowStep[] = isMultiStepFlow ? initialComponent.data.steps : [{ id: \"single\", title: \"\", component: initialComponent }];\n\n  const totalSteps = flowSteps.length;\n\n  const [currentStepIndex, setCurrentStepIndex] = useState(0);\n  const [isProcessing, setIsProcessing] = useState(false);\n  const [allCollectedData, setAllCollectedData] = useState<Record<string, FormValue>>({});\n  const [confirmation, setConfirmation] = useState<ConfirmationData | null>(null);\n  const [submittedSelection, setSubmittedSelection] = useState<string | null>(null);\n  const [stepCompleted, setStepCompleted] = useState<boolean[]>(new Array<boolean>(totalSteps).fill(false));\n\n  const currentStep = flowSteps[currentStepIndex];\n  const currentComponent = currentStep?.component;\n  const showStepper = totalSteps > 1;\n\n  // Go back to previous step\n  const handleBack = useCallback(() => {\n    if (currentStepIndex > 0) {\n      setCurrentStepIndex((prev) => prev - 1);\n    }\n  }, [currentStepIndex]);\n\n  // Move to next step or complete flow\n  const handleStepComplete = useCallback(\n    async (stepData: Record<string, FormValue>) => {\n      setIsProcessing(true);\n\n      // Merge step data\n      const newAllData = { ...allCollectedData, ...stepData };\n      setAllCollectedData(newAllData);\n\n      // Mark current step as completed\n      setStepCompleted((prev) => {\n        const updated = [...prev];\n        updated[currentStepIndex] = true;\n        return updated;\n      });\n\n      try {\n        const isLastStep = currentStepIndex === totalSteps - 1;\n        const selectedButtonId = typeof stepData.selected_button === \"string\" ? stepData.selected_button : null;\n        const buttonsComponent = currentComponent !== undefined && isButtons(currentComponent) ? currentComponent : null;\n        const submittedButton =\n          buttonsComponent && selectedButtonId ? (buttonsComponent.data.buttons.find((button) => button.id === selectedButtonId) ?? { id: selectedButtonId, label: selectedButtonId, action: { type: \"trigger_component\" as const } }) : null;\n        const shouldShowSubmittedSelection = buttonsComponent?.data.completionDisplay === \"selected_item\" && !!submittedButton;\n\n        // If using RPC pattern (onSendResponse provided), send via RPC and skip API calls\n        if (onSendResponse) {\n          // Fast path: when the parent renders the chosen reply as a chat\n          // bubble (selected_item + onSelectionDisplayed), show it instantly\n          // and unmount the buttons — don't wait for the RPC round-trip.\n          const isInstantSelectedItem = isLastStep && shouldShowSubmittedSelection && !!submittedButton && !!onSelectionDisplayed;\n          if (isInstantSelectedItem) {\n            onSelectionDisplayed(initialComponent.component_id, submittedButton.label);\n            onComplete?.(newAllData);\n          }\n\n          await onSendResponse(initialComponent.component_id, {\n            step_index: currentStepIndex,\n            step_data: stepData,\n            all_data: newAllData,\n            is_final_step: isLastStep,\n          });\n\n          if (isLastStep) {\n            if (isInstantSelectedItem) {\n              // Already handled above — nothing more to do for this step.\n            } else if (shouldShowSubmittedSelection && submittedButton) {\n              // Fallback (no onSelectionDisplayed callback): render the\n              // in-card pill the legacy way.\n              setSubmittedSelection(submittedButton.label);\n              onComplete?.(newAllData);\n            } else {\n              // Show confirmation after RPC response is sent\n              setConfirmation({\n                title: \"Success!\",\n                message: \"Your selection has been submitted.\",\n                icon: \"success\",\n              });\n              onComplete?.(newAllData);\n            }\n          } else {\n            // Move to next step\n            setCurrentStepIndex((prev) => prev + 1);\n          }\n        } else {\n          // Legacy API call pattern (when onSendResponse is not provided)\n          if (isLastStep) {\n            // Final step - call the on_complete endpoint if it's a flow\n            if (isMultiStepFlow) {\n              const { on_complete } = initialComponent.data;\n              // Convert all values to strings for legacy API\n              const stringifiedData: Record<string, string> = {};\n              for (const [key, value] of Object.entries(newAllData)) {\n                stringifiedData[key] = Array.isArray(value) ? JSON.stringify(value) : String(value);\n              }\n              const apiPayload = buildPayload(on_complete.payload, {\n                ...stringifiedData,\n                all_data: JSON.stringify(newAllData),\n              });\n\n              const result = await onApiCall(on_complete.method, on_complete.endpoint, apiPayload);\n\n              if (result.success) {\n                setConfirmation(\n                  result.confirmation || {\n                    title: \"Success!\",\n                    message: result.message,\n                    icon: \"success\",\n                  },\n                );\n                onComplete?.(newAllData);\n              } else {\n                throw new Error(result.message || \"Failed to complete\");\n              }\n            } else {\n              // Single component - responses are sent via RPC, just complete\n              onComplete?.(newAllData);\n            }\n          } else {\n            // Not last step - move to next\n            setCurrentStepIndex((prev) => prev + 1);\n          }\n        }\n      } catch (error) {\n        console.error(\"Error processing step:\", error);\n        setConfirmation({\n          title: \"Something went wrong\",\n          message: (error as Error).message || \"Please try again.\",\n          icon: \"error\",\n        });\n      } finally {\n        setIsProcessing(false);\n      }\n    },\n    [allCollectedData, currentStepIndex, totalSteps, isMultiStepFlow, initialComponent, currentComponent, onApiCall, onComplete, onSendResponse, onSelectionDisplayed],\n  );\n\n  // Handle button clicks (special case)\n  const handleButtonClick = useCallback(\n    async (buttonId: string, action: { type: string; url?: string; endpoint?: string; method?: \"POST\" | \"GET\"; payload?: Record<string, string> }) => {\n      if (action.type === \"navigate\" && action.url) {\n        openExternalUrl(action.url);\n        return;\n      }\n\n      // If using RPC pattern, just send the button selection via RPC\n      if (onSendResponse) {\n        handleStepComplete({ selected_button: buttonId });\n        return;\n      }\n\n      // Legacy API call pattern\n      if (action.type === \"api_call\" && action.endpoint) {\n        setIsProcessing(true);\n        try {\n          const result = await onApiCall(action.method || \"POST\", action.endpoint, action.payload || {});\n\n          if (result.success) {\n            // Store button selection and move to next step\n            handleStepComplete({ selected_button: buttonId });\n          }\n        } catch (error) {\n          console.error(\"Error in button action:\", error);\n        } finally {\n          setIsProcessing(false);\n        }\n      } else {\n        // Just move to next step with button selection\n        handleStepComplete({ selected_button: buttonId });\n      }\n    },\n    [onApiCall, handleStepComplete, onSendResponse],\n  );\n\n  // A flow payload that carries no steps has nothing to render; bail after the\n  // hooks so the hook order stays stable.\n  if (!currentStep) return null;\n\n  const renderStepComponent = (component: SimpleComponentPayload): ReactNode => {\n    switch (component.component_type) {\n      case \"calendar_booking\":\n        return (\n          <CalendarStep\n            payload={component}\n            isProcessing={isProcessing}\n            onComplete={(slotId, slotDatetime) => {\n              const timezone = component.data.timezone;\n              handleStepComplete({\n                slot_id: slotId,\n                slot_datetime: slotDatetime,\n                slot_time: formatSlotTime(slotDatetime, timezone),\n                slot_date: formatSlotDate(slotDatetime, timezone),\n              });\n            }}\n          />\n        );\n      case \"form\":\n        return <FormStep payload={component} isProcessing={isProcessing} onComplete={(formData) => handleStepComplete(formData)} />;\n      case \"buttons\":\n        return <ButtonsStep payload={component} isProcessing={isProcessing} align={quickReplyAlign} onButtonClick={handleButtonClick} />;\n      case \"confirmation\":\n        return <ConfirmationStep data={component.data} />;\n      // Block Kit payloads reach the blocks renderer, never this router — web\n      // has no branch for them either.\n      case \"blocks\":\n      default:\n        return null;\n    }\n  };\n\n  return (\n    <EnterFade\n      testID={ringgId(\"interactive-flow\")}\n      translateY={CARD_ENTER_OFFSET}\n      style={[\n        styles.root,\n        isFreeButtonGroup\n          ? null\n          : [\n              styles.card,\n              {\n                backgroundColor: solidColor(theme.backgroundColor),\n                borderColor: solidColor(theme.borderColor),\n                borderRadius: toNumber(theme.borderRadius, DEFAULT_CARD_RADIUS),\n              },\n            ],\n      ]}\n    >\n      {/* Subtle grey card so widgets (calendar, forms, options) read as distinct\n          from the chat — half surface keeps them lighter than user bubbles. */}\n      {isFreeButtonGroup ? null : <View pointerEvents=\"none\" style={[StyleSheet.absoluteFill, styles.surfaceTint, { backgroundColor: solidColor(theme.surfaceColor) }]} />}\n\n      {/* Stepper Header - shows total steps from beginning */}\n      {showStepper && !confirmation && !submittedSelection && (\n        <View testID={ringgId(\"flow-stepper\")} style={styles.stepper}>\n          {/* Progress indicators */}\n          <View testID={ringgId(\"flow-stepper-progress\")} style={styles.stepperProgress}>\n            {flowSteps.map((step, index) => {\n              const isCompleted = stepCompleted[index] ?? false;\n              const isActive = index === currentStepIndex;\n              const indicatorColor = isCompleted ? theme.successColor : isActive ? theme.primaryColor : theme.borderColor;\n\n              return (\n                <View key={step.id} testID={ringgId(\"flow-step\")} style={styles.step}>\n                  {/* Step indicator. Web's `data-ringg-step-active` /\n                      `-completed` have no RN attribute namespace; the active\n                      step is exposed through accessibility state instead, and\n                      completion reads from the check glyph. */}\n                  <View testID={ringgId(\"flow-step-indicator\")} accessibilityState={{ selected: isActive }} style={styles.stepIndicator}>\n                    <GradientFill color={indicatorColor} style={StyleSheet.absoluteFill} />\n                    {isCompleted ? <Check size={14} color={solidColor(theme.primaryTextColor)} /> : <Text style={[styles.stepIndicatorLabel, { color: isActive ? theme.primaryTextColor : theme.mutedTextColor, fontFamily }]}>{index + 1}</Text>}\n                  </View>\n                  {/* Connector */}\n                  {index < flowSteps.length - 1 && <View testID={ringgId(\"flow-step-connector\")} style={[styles.stepConnector, { backgroundColor: solidColor(isCompleted ? theme.successColor : theme.borderColor) }]} />}\n                </View>\n              );\n            })}\n          </View>\n          {/* Current step title */}\n          <Text testID={ringgId(\"flow-step-title\")} numberOfLines={1} style={[styles.stepTitle, { color: theme.textColor, fontFamily }]}>\n            {currentStep.title || `Step ${currentStepIndex + 1} of ${totalSteps}`}\n          </Text>\n        </View>\n      )}\n\n      {/* Content Area */}\n      <View testID={ringgId(\"flow-content\")} style={[isFreeButtonGroup ? null : styles.content, !showStepper && !isFreeButtonGroup ? styles.contentTopPadding : null]}>\n        {/* Back Button (if not first step and not showing confirmation) */}\n        {currentStepIndex > 0 && !confirmation && !submittedSelection && (\n          <Touchable onPress={handleBack} testID={ringgId(\"flow-back-button\")} accessibilityLabel=\"Back\" style={styles.backButton}>\n            <ChevronLeft size={14} color={solidColor(theme.mutedTextColor)} />\n            <Text style={[styles.backLabel, { color: theme.mutedTextColor, fontFamily }]}>Back</Text>\n          </Touchable>\n        )}\n\n        {/* mode=\"wait\" on web: the outgoing branch finishes leaving before the\n            incoming one arrives, so a step advance reads as a hand-off rather\n            than a cut. Each branch keeps its own exit vector. */}\n        <AnimatedSwap\n          swapKey={submittedSelection ? \"submitted\" : confirmation ? \"confirmation\" : `step-${currentStepIndex}`}\n          durationMs={STEP_ENTER_DURATION_MS}\n          enterX={submittedSelection || confirmation ? 0 : STEP_ENTER_OFFSET}\n          exitX={submittedSelection || confirmation ? 0 : -STEP_ENTER_OFFSET}\n          enterY={submittedSelection ? PILL_ENTER_OFFSET : 0}\n          exitY={submittedSelection ? -PILL_ENTER_OFFSET : 0}\n        >\n        {submittedSelection ? (\n          <View testID={ringgId(\"flow-submitted-selection\")} style={styles.submittedSelection}>\n            <View testID={ringgId(\"flow-submitted-pill\")} style={[styles.submittedPill, { borderColor: solidColor(theme.primaryColor) }]}>\n              <GradientFill color={theme.primaryColor} style={StyleSheet.absoluteFill} />\n              <Check size={16} color={solidColor(theme.primaryTextColor)} />\n              <Text numberOfLines={1} accessibilityLabel={submittedSelection} style={[styles.submittedLabel, { color: theme.primaryTextColor, fontFamily }]}>\n                {submittedSelection}\n              </Text>\n            </View>\n          </View>\n        ) : confirmation ? (\n          /* Show Confirmation */\n          <ConfirmationStep data={confirmation} collectedData={allCollectedData} />\n        ) : (\n          renderStepComponent(currentStep.component)\n        )}\n        </AnimatedSwap>\n      </View>\n    </EnterFade>\n  );\n};\n\nexport default InteractiveFlow;\n\nconst styles = StyleSheet.create({\n  root: { width: \"100%\" },\n  card: { borderWidth: 1, overflow: \"hidden\" },\n  surfaceTint: { opacity: SURFACE_TINT_OPACITY },\n  stepper: { paddingHorizontal: 16, paddingTop: 16, paddingBottom: 12 },\n  stepperProgress: { flexDirection: \"row\", alignItems: \"center\", gap: 8 },\n  step: { flexDirection: \"row\", alignItems: \"center\", gap: 8, flex: 1 },\n  stepIndicator: { width: 28, height: 28, borderRadius: 9999, alignItems: \"center\", justifyContent: \"center\", flexShrink: 0, overflow: \"hidden\" },\n  stepIndicatorLabel: { fontSize: 12, lineHeight: 16, fontWeight: \"600\" },\n  stepConnector: { flex: 1, height: 2, borderRadius: 9999 },\n  stepTitle: { fontSize: 12, lineHeight: 16, fontWeight: \"500\", marginTop: 12 },\n  content: { paddingHorizontal: 16, paddingBottom: 16 },\n  contentTopPadding: { paddingTop: 16 },\n  // `alignSelf` keeps the touch target on the label: a stretched Pressable\n  // would make the whole width of the card tappable, which the <button> is not.\n  backButton: { alignSelf: \"flex-start\", flexDirection: \"row\", alignItems: \"center\", gap: 4, marginBottom: 12 },\n  backLabel: { fontSize: 12, lineHeight: 16 },\n  submittedSelection: { paddingVertical: 8 },\n  submittedPill: { alignSelf: \"flex-start\", maxWidth: \"100%\", flexDirection: \"row\", alignItems: \"center\", gap: 8, borderRadius: 10, borderWidth: 1, paddingHorizontal: 12, paddingVertical: 8, overflow: \"hidden\" },\n  submittedLabel: { flexShrink: 1, fontSize: 14, lineHeight: 20, fontWeight: \"600\" },\n});\n","// Dev-panel local port of agents-cdn's lib/component-types.\n//\n// Kept local (instead of using @ringg/core's component types) because the\n// source contract diverges from core in ways the preview renderer relies on:\n//   - `SimpleComponentPayload` includes `BlocksPayload` here (core's does not)\n//   - `ButtonsData` carries `presentation` / `completionDisplay` (not in core)\n//   - `BlocksPayload.data` is the structured `BlocksConfig` (core keeps blocks opaque)\n//   - `buildPayload` interpolates single-brace `{placeholder}` templates\n//   - `formatSlotDate` uses the short weekday/month format\nimport { BlocksConfig } from \"./block-types\";\n\nexport interface ComponentTheme {\n  primaryColor?: string;\n  primaryTextColor?: string;\n  backgroundColor?: string;\n  surfaceColor?: string;\n  textColor?: string;\n  mutedTextColor?: string;\n  borderColor?: string;\n  errorColor?: string;\n  successColor?: string;\n  fontFamily?: string;\n  fontSize?: string;\n  borderRadius?: string;\n  padding?: string;\n  buttonStyle?: \"rounded\" | \"pill\" | \"square\";\n  buttonSize?: \"sm\" | \"md\" | \"lg\";\n}\n\nexport interface BaseComponent {\n  component_type: string;\n  component_id: string;\n  data: unknown;\n  theme?: ComponentTheme;\n}\n\nexport interface CalendarSlot {\n  id: string;\n  datetime: string;\n}\n\nexport interface CalendarBookingData {\n  available_slots: CalendarSlot[];\n  timezone: string;\n  title: string;\n}\n\nexport interface CalendarBookingPayload extends BaseComponent {\n  component_type: \"calendar_booking\";\n  data: CalendarBookingData;\n}\n\nexport type FormFieldType = \"text\" | \"email\" | \"tel\" | \"number\" | \"select\" | \"multiselect\" | \"textarea\" | \"date\" | \"boolean\";\n\nexport interface FormFieldOption {\n  value: string;\n  label: string;\n}\n\nexport interface FormField {\n  name: string;\n  type: FormFieldType;\n  label: string;\n  placeholder?: string;\n  required?: boolean;\n  options?: string[] | FormFieldOption[]; // For select fields\n  validation?: {\n    pattern?: string;\n    minLength?: number;\n    maxLength?: number;\n    message?: string;\n  };\n}\n\nexport interface FormData {\n  title: string;\n  description?: string;\n  fields: FormField[];\n  submit_label?: string;\n}\n\nexport interface FormPayload extends BaseComponent {\n  component_type: \"form\";\n  data: FormData;\n}\n\nexport interface ButtonAction {\n  type: \"navigate\" | \"trigger_component\" | \"api_call\";\n  url?: string;\n  component_type?: string;\n  method?: \"POST\" | \"GET\";\n  endpoint?: string;\n  payload?: Record<string, string>;\n}\n\nexport interface ButtonItem {\n  id: string;\n  label: string;\n  style?: \"primary\" | \"secondary\" | \"outline\" | \"destructive\";\n  action: ButtonAction;\n}\n\nexport interface ButtonsData {\n  title?: string;\n  presentation?: \"boxed\" | \"free\";\n  completionDisplay?: \"confirmation\" | \"selected_item\";\n  buttons: ButtonItem[];\n}\n\nexport interface ButtonsPayload extends BaseComponent {\n  component_type: \"buttons\";\n  data: ButtonsData;\n}\n\nexport interface ConfirmationData {\n  title: string;\n  message: string;\n  icon?: \"success\" | \"info\" | \"warning\" | \"error\";\n  details?: Array<{ label: string; value: string }>;\n}\n\nexport interface ConfirmationPayload extends BaseComponent {\n  component_type: \"confirmation\";\n  data: ConfirmationData;\n}\n\nexport interface FlowStep {\n  id: string;\n  title: string;\n  component: SimpleComponentPayload;\n}\n\nexport interface InteractiveFlowData {\n  title?: string;\n  steps: FlowStep[];\n  // Final action after all steps complete\n  on_complete: {\n    method: \"POST\" | \"GET\";\n    endpoint: string;\n    payload: Record<string, string>;\n  };\n}\n\nexport interface InteractiveFlowPayload extends BaseComponent {\n  component_type: \"interactive_flow\";\n  data: InteractiveFlowData;\n}\n\n// Block Kit widget delivered over the `ringg.blocks` text stream (see lib/block-types.ts)\nexport interface BlocksPayload extends BaseComponent {\n  component_type: \"blocks\";\n  data: BlocksConfig;\n}\n\nexport type ComponentPayload = CalendarBookingPayload | FormPayload | ButtonsPayload | ConfirmationPayload | InteractiveFlowPayload | BlocksPayload;\n\nexport type SimpleComponentPayload = CalendarBookingPayload | FormPayload | ButtonsPayload | ConfirmationPayload | BlocksPayload;\n\nexport interface ComponentActionResponse {\n  success: boolean;\n  message: string;\n  next_step?: SimpleComponentPayload;\n  confirmation?: ConfirmationData;\n}\n\nexport interface GroupedSlots {\n  date: string;\n  dateLabel: string;\n  slots: CalendarSlot[];\n}\n\nexport function groupSlotsByDate(slots: CalendarSlot[]): GroupedSlots[] {\n  const grouped = new Map<string, CalendarSlot[]>();\n\n  slots.forEach((slot) => {\n    const date = new Date(slot.datetime);\n    const dateKey = date.toISOString().split(\"T\")[0] ?? \"\";\n\n    if (!grouped.has(dateKey)) {\n      grouped.set(dateKey, []);\n    }\n    grouped.get(dateKey)!.push(slot);\n  });\n\n  return Array.from(grouped.entries())\n    .sort(([a], [b]) => a.localeCompare(b))\n    .map(([dateKey, dateSlots]) => {\n      const date = new Date(dateKey);\n      return {\n        date: dateKey,\n        dateLabel: date.toLocaleDateString(\"en-US\", { weekday: \"short\", month: \"short\", day: \"numeric\" }),\n        slots: dateSlots.sort((a, b) => new Date(a.datetime).getTime() - new Date(b.datetime).getTime()),\n      };\n    });\n}\n\nexport function formatSlotTime(datetime: string, timezone?: string): string {\n  const date = new Date(datetime);\n  return date.toLocaleTimeString(\"en-US\", {\n    hour: \"numeric\",\n    minute: \"2-digit\",\n    hour12: true,\n    timeZone: timezone,\n  });\n}\n\nexport function formatSlotDate(datetime: string, timezone?: string): string {\n  const date = new Date(datetime);\n  return date.toLocaleDateString(\"en-US\", {\n    weekday: \"short\",\n    month: \"short\",\n    day: \"numeric\",\n    timeZone: timezone,\n  });\n}\n\n// Replace placeholders in payload with actual values\nexport function buildPayload(template: Record<string, string>, values: Record<string, string>): Record<string, string> {\n  const result: Record<string, string> = {};\n\n  for (const [key, value] of Object.entries(template)) {\n    if (typeof value === \"string\" && value.startsWith(\"{\") && value.endsWith(\"}\")) {\n      const placeholder = value.slice(1, -1);\n      result[key] = values[placeholder] ?? value;\n    } else {\n      result[key] = value;\n    }\n  }\n\n  return result;\n}\n\n// Type guard functions\nexport function isCalendarBooking(payload: ComponentPayload): payload is CalendarBookingPayload {\n  return payload.component_type === \"calendar_booking\";\n}\n\nexport function isForm(payload: ComponentPayload): payload is FormPayload {\n  return payload.component_type === \"form\";\n}\n\nexport function isButtons(payload: ComponentPayload): payload is ButtonsPayload {\n  return payload.component_type === \"buttons\";\n}\n\nexport function isConfirmation(payload: ComponentPayload): payload is ConfirmationPayload {\n  return payload.component_type === \"confirmation\";\n}\n\nexport function isInteractiveFlow(payload: ComponentPayload): payload is InteractiveFlowPayload {\n  return payload.component_type === \"interactive_flow\";\n}\n\nexport function isBlocks(payload: ComponentPayload): payload is BlocksPayload {\n  return payload.component_type === \"blocks\";\n}\n","/**\n * Component-level theme resolution for the interactive components.\n *\n * Port of the web widget's `lib/theme-utils.ts`, with the same deliberate\n * quirk preserved: component-level radii (4px/8px) differ from widget-level\n * radii (6px/12px). That is not a bug in the source — the interactive cards\n * are visually tighter than the widget chrome — so it survives the port.\n *\n * Everything is resolved to NUMBERS here. The web version returns CSS strings\n * (`\"8px\"`, `\"8px 16px\"`) because it hands them to the DOM; RN needs numeric\n * style values, and a padding shorthand has to become explicit vertical and\n * horizontal components.\n */\n\nimport type { ButtonSize, ButtonStyle, ComponentTheme } from \"@ringg/core\";\n\n/** Vertical/horizontal padding pair — RN has no shorthand string. */\nexport interface ButtonPadding {\n  paddingVertical: number;\n  paddingHorizontal: number;\n}\n\nexport const DEFAULT_THEME: Required<ComponentTheme> = {\n  primaryColor: \"#0a0a0b\",\n  primaryTextColor: \"#ffffff\",\n  backgroundColor: \"#ffffff\",\n  surfaceColor: \"#f3f4f6\",\n  textColor: \"#0a0a0b\",\n  mutedTextColor: \"#6b7280\",\n  borderColor: \"#e5e7eb\",\n  errorColor: \"#ef4444\",\n  successColor: \"#16a34a\",\n  fontFamily: \"inherit\",\n  fontSize: \"14px\",\n  borderRadius: \"8px\",\n  padding: \"12px\",\n  buttonStyle: \"pill\",\n  buttonSize: \"md\",\n};\n\n/** Matches `resolveRadius`'s pill clamp — RN cannot lay out an infinite radius. */\nconst PILL_RADIUS = 9999;\n\nexport const mergeTheme = (theme?: ComponentTheme): Required<ComponentTheme> => ({ ...DEFAULT_THEME, ...theme });\n\n/** `\"14px\"` → `14`, for the string-typed `fontSize` / `padding` theme fields. */\nexport const toNumber = (value: string | undefined, fallback: number): number => {\n  if (value === undefined) return fallback;\n  const trimmed = value.trim();\n  const parsed = Number(trimmed.endsWith(\"px\") ? trimmed.slice(0, -2) : trimmed);\n  return Number.isFinite(parsed) ? parsed : fallback;\n};\n\nexport const getButtonRadius = (style?: ButtonStyle): number => {\n  switch (style) {\n    case \"pill\":\n      return PILL_RADIUS;\n    case \"square\":\n      return 4;\n    case \"rounded\":\n    default:\n      return 8;\n  }\n};\n\nexport const getButtonPadding = (size?: ButtonSize): ButtonPadding => {\n  switch (size) {\n    case \"sm\":\n      return { paddingVertical: 6, paddingHorizontal: 12 };\n    case \"lg\":\n      return { paddingVertical: 12, paddingHorizontal: 24 };\n    case \"md\":\n    default:\n      return { paddingVertical: 8, paddingHorizontal: 16 };\n  }\n};\n\nexport const getButtonHeight = (size?: ButtonSize): number => {\n  switch (size) {\n    case \"sm\":\n      return 32;\n    case \"lg\":\n      return 44;\n    case \"md\":\n    default:\n      return 36;\n  }\n};\n","/**\n * Button step — RN counterpart of the web widget's\n * `components/steps/buttons-step.tsx`.\n *\n * One payload, two presentations: `presentation: \"free\"` renders chat\n * quick-reply chips (wrapping, aligned by the caller — centred in voice mode,\n * right in chat mode), anything else renders the boxed single-choice list with\n * radio affordances and hairline dividers.\n *\n * Web gets its hover dim and `disabled:` opacity from CSS. RN has neither, so\n * both come from <Touchable>'s press/disabled states and no button carries\n * state styling of its own.\n */\n\nimport { useEffect, useMemo, useRef, useState, type FC } from \"react\";\nimport { Animated, Easing, StyleSheet, Text, View } from \"react-native\";\nimport { ExternalLink, LoaderCircle } from \"lucide-react-native\";\nimport type { ComponentTheme } from \"@ringg/core\";\n\nimport type { ButtonItem, ButtonsPayload } from \"../../lib/component-types\";\nimport { GradientFill, solidColor } from \"../../lib/gradient\";\nimport { ringgId } from \"../../lib/testing\";\nimport { mergeTheme } from \"../../lib/theme-utils\";\nimport { resolveFontFamily, useWidgetTheme } from \"../../lib/widget-theme\";\nimport { Touchable } from \"../ui/pressable\";\n\ninterface ButtonsStepProps {\n  payload: ButtonsPayload;\n  isProcessing?: boolean;\n  // Quick-reply chip row alignment: \"center\" for voice mode, \"end\" for chat mode.\n  align?: \"center\" | \"end\";\n  onButtonClick: (buttonId: string, action: ButtonItem[\"action\"]) => void;\n}\n\ninterface SpinnerProps {\n  size: number;\n  color: string;\n}\n\n/** A button surface: `background` may be a gradient, `foreground` never is. */\ninterface ButtonSurface {\n  background: string;\n  foreground: string;\n}\n\n/** One turn per second — Tailwind's `animate-spin`. */\nconst SPIN_DURATION_MS = 1000;\n\nconst Spinner: FC<SpinnerProps> = ({ size, color }) => {\n  const rotation = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    const animation = Animated.loop(Animated.timing(rotation, { toValue: 1, duration: SPIN_DURATION_MS, easing: Easing.linear, useNativeDriver: true }));\n    animation.start();\n    return () => animation.stop();\n  }, [rotation]);\n\n  return (\n    <Animated.View style={{ transform: [{ rotate: rotation.interpolate({ inputRange: [0, 1], outputRange: [\"0deg\", \"360deg\"] }) }] }}>\n      <LoaderCircle size={size} color={color} />\n    </Animated.View>\n  );\n};\n\n// Quick-reply chips: filled pills, honoring the payload's per-button emphasis\nconst buttonSurface = (theme: Required<ComponentTheme>, style: ButtonItem[\"style\"]): ButtonSurface => {\n  switch (style) {\n    case \"secondary\":\n    case \"outline\":\n      return { background: theme.surfaceColor, foreground: theme.textColor };\n    case \"destructive\":\n      return { background: theme.errorColor, foreground: theme.primaryTextColor };\n    case \"primary\":\n    default:\n      return { background: theme.primaryColor, foreground: theme.primaryTextColor };\n  }\n};\n\nconst ButtonsStep: FC<ButtonsStepProps> = ({ payload, isProcessing, align = \"end\", onButtonClick }) => {\n  // Web reads this from the router's ThemeContext; RN resolves the same\n  // widget→component mapping locally (see components/interactive-flow.tsx).\n  const widgetTheme = useWidgetTheme();\n  const theme = useMemo(\n    () =>\n      mergeTheme({\n        primaryColor: widgetTheme.primaryColor,\n        primaryTextColor: widgetTheme.primaryTextColor,\n        backgroundColor: widgetTheme.backgroundColor,\n        surfaceColor: widgetTheme.surfaceColor,\n        textColor: widgetTheme.textColor,\n        mutedTextColor: widgetTheme.mutedTextColor,\n        borderColor: widgetTheme.borderColor,\n        ...payload.theme,\n      }),\n    [payload.theme, widgetTheme],\n  );\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  const { data } = payload;\n  const isFreePresentation = data.presentation === \"free\";\n  const [loadingButtonId, setLoadingButtonId] = useState<string | null>(null);\n\n  const handleClick = async (button: ButtonItem) => {\n    if (button.action.type === \"navigate\") {\n      onButtonClick(button.id, button.action);\n      return;\n    }\n\n    setLoadingButtonId(button.id);\n    try {\n      await onButtonClick(button.id, button.action);\n    } finally {\n      setLoadingButtonId(null);\n    }\n  };\n\n  const title = data.title ? (\n    <Text testID={ringgId(\"buttons-step-title\")} style={[styles.title, { color: theme.textColor, fontFamily }]}>\n      {data.title}\n    </Text>\n  ) : null;\n\n  if (isFreePresentation) {\n    // Web also tags the row with `data-ringg-align`; RN has no attribute\n    // namespace beyond testID, and the alignment is readable from the layout.\n    return (\n      <View testID={ringgId(\"quick-replies\")} style={styles.root}>\n        {title}\n        <View style={[styles.chipRow, align === \"center\" ? styles.alignCenter : styles.alignEnd]}>\n          {data.buttons.map((button) => {\n            const isLoading = loadingButtonId === button.id;\n            const isNavigate = button.action.type === \"navigate\";\n            const isDisabled = isLoading || isProcessing;\n            const surface = buttonSurface(theme, button.style);\n\n            return (\n              <Touchable key={button.id} testID={ringgId(\"quick-reply-button\")} accessibilityLabel={button.label} disabled={isDisabled} onPress={() => void handleClick(button)} style={styles.chip}>\n                <GradientFill color={surface.background} style={StyleSheet.absoluteFill} />\n                {isLoading ? <Spinner size={12} color={solidColor(surface.foreground)} /> : null}\n                <Text style={[styles.chipLabel, { color: surface.foreground, fontFamily }]}>{button.label}</Text>\n                {isNavigate ? <ExternalLink size={12} color={solidColor(surface.foreground)} /> : null}\n              </Touchable>\n            );\n          })}\n        </View>\n      </View>\n    );\n  }\n\n  // Boxed presentation: a single-choice list with radio affordances and hairline dividers\n  return (\n    <View>\n      {title}\n      <View testID={ringgId(\"options-list\")} style={styles.optionsList}>\n        {data.buttons.map((button, index) => {\n          const isLoading = loadingButtonId === button.id;\n          const isNavigate = button.action.type === \"navigate\";\n          const isDisabled = isLoading || isProcessing;\n          const isDestructive = button.style === \"destructive\";\n          const isLastRow = index === data.buttons.length - 1;\n          const labelColor = isDestructive ? theme.errorColor : theme.textColor;\n\n          return (\n            <Touchable\n              key={button.id}\n              testID={ringgId(\"option-row\")}\n              accessibilityLabel={button.label}\n              disabled={isDisabled}\n              onPress={() => void handleClick(button)}\n              // Full-width rows are already past the 44dp target, and slop\n              // between stacked rows would make the boundary ambiguous.\n              hitSlop={0}\n              style={[styles.optionRow, isLastRow ? null : { borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: solidColor(theme.borderColor) }]}\n            >\n              {isLoading ? (\n                <Spinner size={16} color={solidColor(labelColor)} />\n              ) : (\n                <View testID={ringgId(\"option-radio\")} accessibilityElementsHidden importantForAccessibility=\"no\" style={[styles.optionRadio, { borderColor: solidColor(theme.mutedTextColor) }]} />\n              )}\n              <Text style={[styles.optionLabel, { color: labelColor, fontFamily }]}>{button.label}</Text>\n              {isNavigate ? <ExternalLink size={14} color={solidColor(labelColor)} /> : null}\n            </Touchable>\n          );\n        })}\n      </View>\n    </View>\n  );\n};\n\nexport default ButtonsStep;\n\nconst styles = StyleSheet.create({\n  root: { width: \"100%\" },\n  title: { fontSize: 14, lineHeight: 20, fontWeight: \"500\", marginBottom: 8 },\n  chipRow: { flexDirection: \"row\", flexWrap: \"wrap\", gap: 8 },\n  alignCenter: { justifyContent: \"center\" },\n  alignEnd: { justifyContent: \"flex-end\" },\n  // `flexShrink` is 1 by default on web and 0 in RN, so a chip wide enough to\n  // fill the row has to be told it may shrink or it overflows the panel.\n  chip: { flexDirection: \"row\", alignItems: \"center\", gap: 6, height: 36, paddingHorizontal: 16, borderRadius: 9999, flexShrink: 1, overflow: \"hidden\" },\n  chipLabel: { flexShrink: 1, fontSize: 15, fontWeight: \"500\" },\n  optionsList: { flexDirection: \"column\" },\n  optionRow: { flexDirection: \"row\", alignItems: \"center\", gap: 12, paddingHorizontal: 8, paddingVertical: 12 },\n  optionRadio: { width: 16, height: 16, borderRadius: 9999, borderWidth: 1, flexShrink: 0 },\n  optionLabel: { flex: 1, fontSize: 15 },\n});\n","/**\n * Calendar booking step — RN counterpart of the web widget's\n * `components/steps/calendar-step.tsx`.\n *\n * The selection model is unchanged: pick a day, then a slot inside that day,\n * then confirm. Grouping, ordering and labelling all come from\n * `component-types` (`groupSlotsByDate` / `formatSlotTime`), so both platforms\n * show the same slots in the same words for the same payload.\n *\n * Two surfaces could not cross unchanged: the 3-column CSS grid, which becomes\n * fixed-width flex cells, and the framer-motion reveal, which becomes a fade\n * (RN cannot animate to an intrinsic height without measuring it first).\n */\n\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState, type FC } from \"react\";\nimport { Animated, Easing, StyleSheet, Text, View } from \"react-native\";\nimport { Calendar, Clock, LoaderCircle } from \"lucide-react-native\";\nimport type { ComponentTheme } from \"@ringg/core\";\n\nimport { formatSlotTime, groupSlotsByDate, type CalendarBookingPayload, type CalendarSlot } from \"../../lib/component-types\";\nimport { GradientFill, solidColor } from \"../../lib/gradient\";\nimport { getButtonRadius, mergeTheme } from \"../../lib/theme-utils\";\nimport { resolveFontFamily, useWidgetTheme } from \"../../lib/widget-theme\";\nimport { Touchable } from \"../ui/pressable\";\n\ninterface CalendarStepProps {\n  payload: CalendarBookingPayload;\n  isProcessing?: boolean;\n  onComplete: (slotId: string, slotDatetime: string) => void;\n}\n\n/** `animate-spin` — one linear turn per second, the CSS default. */\nconst SPIN_DURATION_MS = 1000;\n\n/** Long enough to read as a reveal, short enough not to delay a second tap. */\nconst SLOT_FADE_MS = 200;\n\n/** Gutter between time slots (web's `gap-1.5`), split across the two cells. */\nconst SLOT_GUTTER = 6;\n\n/**\n * Half the gap between neighbouring chips. Anything larger and the expanded\n * touch areas overlap, which hands taps near the seam to whichever chip\n * happens to be first in the tree.\n */\nconst DATE_HIT_SLOP = 4;\nconst SLOT_HIT_SLOP = SLOT_GUTTER / 2;\n\n/**\n * Web resolves the component theme from a context that `interactive-flow`\n * installs. RN resolves it at the leaf: the inputs are the same — widget\n * colours as the base, the payload's own `theme` on top — and a step rendered\n * on its own, outside a flow, still themes correctly.\n */\nconst useStepTheme = (componentTheme?: ComponentTheme): Required<ComponentTheme> => {\n  const widgetTheme = useWidgetTheme();\n\n  return useMemo(\n    () =>\n      mergeTheme({\n        primaryColor: widgetTheme.primaryColor,\n        primaryTextColor: widgetTheme.primaryTextColor,\n        // Cards read as bordered surfaces sitting ON the panel, so they take\n        // the widget background rather than the (greyer) surface colour.\n        backgroundColor: widgetTheme.backgroundColor,\n        surfaceColor: widgetTheme.surfaceColor,\n        textColor: widgetTheme.textColor,\n        mutedTextColor: widgetTheme.mutedTextColor,\n        borderColor: widgetTheme.borderColor,\n        errorColor: widgetTheme.errorColor,\n        successColor: widgetTheme.successColor,\n        buttonStyle: widgetTheme.buttonStyle,\n        // Web inherits the family from the flow container; RN has no cascade,\n        // so it travels through the theme and is applied per <Text>.\n        fontFamily: widgetTheme.fontFamily,\n        ...componentTheme,\n      }),\n    [componentTheme, widgetTheme],\n  );\n};\n\n/** `LoaderCircle` is lucide's current name for the web source's `Loader2`. */\nconst Spinner: FC<{ color: string }> = ({ color }) => {\n  const turn = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    const loop = Animated.loop(Animated.timing(turn, { toValue: 1, duration: SPIN_DURATION_MS, easing: Easing.linear, useNativeDriver: true }));\n    loop.start();\n    return () => loop.stop();\n  }, [turn]);\n\n  return (\n    <Animated.View style={{ transform: [{ rotate: turn.interpolate({ inputRange: [0, 1], outputRange: [\"0deg\", \"360deg\"] }) }] }}>\n      <LoaderCircle size={16} color={color} />\n    </Animated.View>\n  );\n};\n\nconst CalendarStep: FC<CalendarStepProps> = ({ payload, isProcessing, onComplete }) => {\n  const theme = useStepTheme(payload.theme);\n  const buttonRadius = getButtonRadius(theme.buttonStyle);\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  const { data } = payload;\n  const groupedSlots = useMemo(() => groupSlotsByDate(data.available_slots), [data.available_slots]);\n\n  const [selectedDate, setSelectedDate] = useState<string>(groupedSlots[0]?.date || \"\");\n  const [selectedSlot, setSelectedSlot] = useState<CalendarSlot | null>(null);\n\n  const selectedDateGroup = groupedSlots.find((g) => g.date === selectedDate);\n\n  // Web animates opacity AND height from 0 on every date change; only the\n  // opacity half survives, so the slots take their space immediately.\n  const slotFade = useRef(new Animated.Value(0)).current;\n\n  // Layout effect, not passive: resetting the value after paint lets the new\n  // slots show at full opacity for one frame before fading in.\n  useLayoutEffect(() => {\n    slotFade.setValue(0);\n    const fade = Animated.timing(slotFade, { toValue: 1, duration: SLOT_FADE_MS, useNativeDriver: true });\n    fade.start();\n    return () => fade.stop();\n  }, [selectedDate, slotFade]);\n\n  const handleConfirm = () => {\n    if (selectedSlot) {\n      onComplete(selectedSlot.id, selectedSlot.datetime);\n    }\n  };\n\n  const isConfirmDisabled = !selectedSlot || isProcessing;\n  const confirmTextColor = isConfirmDisabled ? theme.mutedTextColor : theme.primaryTextColor;\n\n  return (\n    <View>\n      <View style={styles.header}>\n        <Calendar size={16} color={solidColor(theme.primaryColor)} />\n        <Text style={[styles.title, { color: theme.textColor, fontFamily }]}>{data.title}</Text>\n      </View>\n\n      <Text style={[styles.timezone, { color: theme.mutedTextColor, fontFamily }]}>Timezone: {data.timezone}</Text>\n\n      <View style={styles.section}>\n        <Text style={[styles.sectionLabel, styles.sectionLabelSpacing, { color: theme.mutedTextColor, fontFamily }]}>Select Date</Text>\n        <View style={styles.dateRow}>\n          {groupedSlots.map((group) => {\n            const isSelected = selectedDate === group.date;\n\n            return (\n              <Touchable\n                key={group.date}\n                hitSlop={DATE_HIT_SLOP}\n                onPress={() => {\n                  setSelectedDate(group.date);\n                  setSelectedSlot(null);\n                }}\n              >\n                <GradientFill\n                  color={isSelected ? theme.primaryColor : theme.backgroundColor}\n                  style={[styles.dateChip, { borderRadius: buttonRadius }, isSelected ? styles.selectedShadow : { borderWidth: 1, borderColor: theme.borderColor }]}\n                >\n                  <Text style={[styles.dateChipLabel, { color: isSelected ? theme.primaryTextColor : theme.textColor, fontFamily }]}>{group.dateLabel}</Text>\n                </GradientFill>\n              </Touchable>\n            );\n          })}\n        </View>\n      </View>\n\n      {selectedDateGroup ? (\n        <Animated.View style={[styles.section, { opacity: slotFade }]}>\n          <View style={styles.sectionLabelRow}>\n            <Clock size={12} color={theme.mutedTextColor} />\n            <Text style={[styles.sectionLabel, { color: theme.mutedTextColor, fontFamily }]}>Select Time</Text>\n          </View>\n          <View style={styles.slotGrid}>\n            {selectedDateGroup.slots.map((slot) => {\n              const isSelected = selectedSlot?.id === slot.id;\n\n              return (\n                <View key={slot.id} style={styles.slotCell}>\n                  <Touchable hitSlop={SLOT_HIT_SLOP} onPress={() => setSelectedSlot(slot)}>\n                    <GradientFill\n                      color={isSelected ? theme.primaryColor : theme.backgroundColor}\n                      style={[styles.slot, { borderRadius: buttonRadius, borderColor: isSelected ? solidColor(theme.primaryColor) : theme.borderColor }, isSelected ? styles.selectedShadow : null]}\n                    >\n                      <Text style={[styles.slotLabel, { color: isSelected ? theme.primaryTextColor : theme.textColor, fontFamily }]} numberOfLines={1}>\n                        {formatSlotTime(slot.datetime, data.timezone)}\n                      </Text>\n                    </GradientFill>\n                  </Touchable>\n                </View>\n              );\n            })}\n          </View>\n        </Animated.View>\n      ) : null}\n\n      <Touchable onPress={handleConfirm} disabled={isConfirmDisabled}>\n        <GradientFill color={isConfirmDisabled ? theme.borderColor : theme.primaryColor} style={[styles.confirmButton, { borderRadius: buttonRadius }]}>\n          {isProcessing ? (\n            <>\n              <Spinner color={confirmTextColor} />\n              <Text style={[styles.confirmLabel, { color: confirmTextColor, fontFamily }]}>Processing...</Text>\n            </>\n          ) : (\n            <Text style={[styles.confirmLabel, { color: confirmTextColor, fontFamily }]}>Next</Text>\n          )}\n        </GradientFill>\n      </Touchable>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  header: { flexDirection: \"row\", alignItems: \"center\", gap: 8, marginBottom: 12 },\n  title: { fontSize: 14, lineHeight: 20, fontWeight: \"500\" },\n  timezone: { fontSize: 12, lineHeight: 16, marginBottom: 12 },\n  section: { marginBottom: 12 },\n  sectionLabel: { fontSize: 12, lineHeight: 16, fontWeight: \"600\", textTransform: \"uppercase\", letterSpacing: 0.3 },\n  sectionLabelSpacing: { marginBottom: 8 },\n  sectionLabelRow: { flexDirection: \"row\", alignItems: \"center\", gap: 4, marginBottom: 8 },\n  dateRow: { flexDirection: \"row\", flexWrap: \"wrap\", gap: 8 },\n  dateChip: { paddingHorizontal: 12, paddingVertical: 8, alignItems: \"center\", justifyContent: \"center\" },\n  dateChipLabel: { fontSize: 12, lineHeight: 16, fontWeight: \"600\" },\n  // Web's `0 2px 4px rgba(0,0,0,0.1)` on the chosen chip, in both platforms' terms.\n  selectedShadow: { shadowColor: \"#000000\", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2 },\n  // Three equal columns with `SLOT_GUTTER` between them: each cell pads half a\n  // gutter per side and the row pulls that padding back off its outer edges.\n  slotGrid: { flexDirection: \"row\", flexWrap: \"wrap\", rowGap: SLOT_GUTTER, marginHorizontal: -SLOT_GUTTER / 2 },\n  slotCell: { width: \"33.3333%\", paddingHorizontal: SLOT_GUTTER / 2 },\n  slot: { paddingHorizontal: 8, paddingVertical: 8, alignItems: \"center\", justifyContent: \"center\", borderWidth: 1 },\n  slotLabel: { fontSize: 12, lineHeight: 16, fontWeight: \"500\" },\n  confirmButton: { height: 36, flexDirection: \"row\", alignItems: \"center\", justifyContent: \"center\", gap: 8 },\n  confirmLabel: { fontSize: 14, lineHeight: 20, fontWeight: \"600\" },\n});\n\nexport default CalendarStep;\n","/**\n * Confirmation card — RN counterpart of the web widget's\n * `components/steps/confirmation-step.tsx`.\n *\n * Terminal state for a flow: a status glyph, the copy the backend sent, and up\n * to four detail rows. The rows come from the payload when it carries\n * `details`, otherwise from the data the flow collected, filtered and ordered\n * by `PRIORITY_KEYS` so a booking always reads date → time → who.\n *\n * The framer-motion entrance survives as RN `Animated`: the same 100ms/150ms\n * stagger, and the same spring on the glyph (`stiffness: 400, damping: 15`\n * transfers one-to-one, since both libraries take real spring physics).\n */\n\nimport { useEffect, useRef, type FC } from \"react\";\nimport { Animated, StyleSheet, Text, View } from \"react-native\";\nimport { Calendar, Check, CircleX, Clock, Info, Mail, TriangleAlert, User, type LucideIcon } from \"lucide-react-native\";\n\nimport type { ConfirmationData } from \"../../lib/component-types\";\nimport { GradientFill, solidColor } from \"../../lib/gradient\";\nimport { mergeTheme } from \"../../lib/theme-utils\";\nimport { resolveFontFamily, useWidgetTheme } from \"../../lib/widget-theme\";\n\ntype FormValue = string | number | boolean | string[];\n\ninterface ConfirmationStepProps {\n  data: ConfirmationData;\n  collectedData?: Record<string, FormValue>;\n}\n\n/** A status glyph and the colour of the disc behind it. */\ninterface IconConfig {\n  icon: LucideIcon;\n  bgColor: string;\n}\n\nconst ENTER_DURATION_MS = 300;\nconst TITLE_DELAY_MS = 100;\nconst DETAILS_DELAY_MS = 150;\n\n/** Amber-500. The only status colour with no theme slot of its own. */\nconst WARNING_COLOR = \"#f59e0b\";\n\n/** Web's `text-white`: the glyph always sits on a saturated disc. */\nconst GLYPH_COLOR = \"#ffffff\";\n\n/** Which collected fields are worth echoing back, in reading order. */\nconst PRIORITY_KEYS = [\"slot_date\", \"slot_time\", \"name\", \"email\", \"phone\"];\n\nconst MAX_DETAILS = 4;\n\n/** Fades a node in, optionally after `delayMs` — framer-motion's `delay`. */\nconst useEnter = (delayMs = 0): Animated.Value => {\n  const progress = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    Animated.timing(progress, { toValue: 1, duration: ENTER_DURATION_MS, delay: delayMs, useNativeDriver: true }).start();\n  }, [delayMs, progress]);\n\n  return progress;\n};\n\n/** The glyph's `scale: 0 → 1` spring. */\nconst usePop = (): Animated.Value => {\n  const scale = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    Animated.spring(scale, { toValue: 1, stiffness: 400, damping: 15, mass: 1, useNativeDriver: true }).start();\n  }, [scale]);\n\n  return scale;\n};\n\nconst formatValue = (value: FormValue): string => {\n  if (Array.isArray(value)) return value.join(\", \");\n  if (typeof value === \"boolean\") return value ? \"Yes\" : \"No\";\n  return String(value);\n};\n\nconst getDetailIcon = (key?: string): LucideIcon | null => {\n  if (!key) return null;\n  if (key.includes(\"date\")) return Calendar;\n  if (key.includes(\"time\")) return Clock;\n  if (key.includes(\"email\")) return Mail;\n  if (key.includes(\"name\")) return User;\n  return null;\n};\n\nconst ConfirmationStep: FC<ConfirmationStepProps> = ({ data, collectedData }) => {\n  // Web reads this from the router's ThemeContext; RN resolves the same\n  // widget→component mapping locally (see components/interactive-flow.tsx).\n  const widgetTheme = useWidgetTheme();\n  const theme = mergeTheme({\n    primaryColor: widgetTheme.primaryColor,\n    primaryTextColor: widgetTheme.primaryTextColor,\n    backgroundColor: widgetTheme.backgroundColor,\n    surfaceColor: widgetTheme.surfaceColor,\n    textColor: widgetTheme.textColor,\n    mutedTextColor: widgetTheme.mutedTextColor,\n    borderColor: widgetTheme.borderColor,\n  });\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  const cardProgress = useEnter();\n  const glyphScale = usePop();\n  const titleProgress = useEnter(TITLE_DELAY_MS);\n  const detailsProgress = useEnter(DETAILS_DELAY_MS);\n\n  const iconType = data.icon || \"success\";\n\n  const getIconConfig = (): IconConfig => {\n    switch (iconType) {\n      case \"success\":\n        return { icon: Check, bgColor: theme.successColor };\n      case \"info\":\n        return { icon: Info, bgColor: theme.primaryColor };\n      case \"warning\":\n        return { icon: TriangleAlert, bgColor: WARNING_COLOR };\n      case \"error\":\n        return { icon: CircleX, bgColor: theme.errorColor };\n      default:\n        return { icon: Check, bgColor: theme.successColor };\n    }\n  };\n\n  const { icon: Icon, bgColor } = getIconConfig();\n  const displayDetails = data.details || [];\n\n  const formattedCollectedData = collectedData\n    ? Object.entries(collectedData)\n        .filter(([key]) => PRIORITY_KEYS.includes(key))\n        .sort((a, b) => PRIORITY_KEYS.indexOf(a[0]) - PRIORITY_KEYS.indexOf(b[0]))\n        .map(([key, value]) => ({\n          key,\n          label: key\n            .replace(/slot_/g, \"\")\n            .replace(/_/g, \" \")\n            .replace(/\\b\\w/g, (l) => l.toUpperCase()),\n          value: formatValue(value),\n        }))\n    : [];\n\n  const detailsToShow: Array<{ label: string; value: string; key?: string }> = displayDetails.length > 0 ? displayDetails : formattedCollectedData;\n\n  return (\n    <Animated.View style={[styles.root, { opacity: cardProgress }]}>\n      <View style={styles.header}>\n        <Animated.View style={[styles.glyph, { transform: [{ scale: glyphScale }] }]}>\n          <GradientFill color={bgColor} style={StyleSheet.absoluteFill} />\n          <Icon size={18} color={GLYPH_COLOR} />\n        </Animated.View>\n\n        <Animated.View style={[styles.headerText, { opacity: titleProgress, transform: [{ translateX: titleProgress.interpolate({ inputRange: [0, 1], outputRange: [-8, 0] }) }] }]}>\n          <Text style={[styles.title, { color: theme.textColor, fontFamily }]}>{data.title}</Text>\n          {data.message ? <Text style={[styles.message, { color: theme.mutedTextColor, fontFamily }]}>{data.message}</Text> : null}\n        </Animated.View>\n      </View>\n\n      {detailsToShow.length > 0 && (\n        <Animated.View style={[styles.details, { backgroundColor: theme.surfaceColor, opacity: detailsProgress, transform: [{ translateY: detailsProgress.interpolate({ inputRange: [0, 1], outputRange: [8, 0] }) }] }]}>\n          {detailsToShow.slice(0, MAX_DETAILS).map((detail, index) => {\n            const DetailIcon = detail.key ? getDetailIcon(detail.key) : null;\n            return (\n              <View key={index} style={[styles.detailRow, index === 0 ? null : { borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: solidColor(theme.borderColor) }]}>\n                {DetailIcon ? <DetailIcon size={14} color={solidColor(theme.mutedTextColor)} /> : null}\n                <Text style={[styles.detailLabel, { color: theme.mutedTextColor, fontFamily }]}>{detail.label}</Text>\n                <Text numberOfLines={1} accessibilityLabel={detail.value} style={[styles.detailValue, { color: theme.textColor, fontFamily }]}>\n                  {detail.value}\n                </Text>\n              </View>\n            );\n          })}\n        </Animated.View>\n      )}\n    </Animated.View>\n  );\n};\n\nexport default ConfirmationStep;\n\nconst styles = StyleSheet.create({\n  root: { paddingVertical: 8 },\n  header: { flexDirection: \"row\", alignItems: \"flex-start\", gap: 12, marginBottom: 16 },\n  glyph: { width: 36, height: 36, borderRadius: 9999, alignItems: \"center\", justifyContent: \"center\", flexShrink: 0, overflow: \"hidden\" },\n  headerText: { flex: 1, paddingTop: 2 },\n  title: { fontSize: 14, lineHeight: 17.5, fontWeight: \"600\" },\n  message: { fontSize: 12, lineHeight: 19.5, marginTop: 4 },\n  details: { borderRadius: 8, overflow: \"hidden\" },\n  detailRow: { flexDirection: \"row\", alignItems: \"center\", gap: 10, paddingHorizontal: 12, paddingVertical: 10 },\n  detailLabel: { fontSize: 12, lineHeight: 16, flexShrink: 0 },\n  // `ml-auto` — pushes the value to the trailing edge, and lets it truncate\n  // rather than shove the label out of the row.\n  detailValue: { fontSize: 12, lineHeight: 16, fontWeight: \"500\", marginLeft: \"auto\", flexShrink: 1 },\n});\n","/**\n * Form step — RN counterpart of the web widget's `components/steps/form-step.tsx`.\n *\n * The validation rules, their messages and their timing (validate on submit,\n * clear a field's error the moment it changes) are ported unchanged, because\n * the agent on the other end reads these values and the operator wrote these\n * messages.\n *\n * Three controls have no RN primitive and are rebuilt from a `<Touchable>`:\n * `<select>` becomes an inline option list, and both checkbox flavours become\n * a drawn box. `date` has no picker either and falls through to a text field —\n * a real picker means a new dependency.\n */\n\nimport { useEffect, useMemo, useRef, useState, type FC } from \"react\";\nimport { Animated, Easing, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, Text, TextInput, View, type KeyboardTypeOptions, type ViewStyle } from \"react-native\";\nimport { Calendar, Check, ChevronDown, FileText, List, LoaderCircle, Mail, Phone, SquareCheckBig, Type, type LucideIcon } from \"lucide-react-native\";\nimport type { ComponentTheme } from \"@ringg/core\";\n\nimport type { FormField, FormFieldOption, FormFieldType, FormPayload } from \"../../lib/component-types\";\nimport { GradientFill, solidColor } from \"../../lib/gradient\";\nimport { getButtonRadius, mergeTheme, toNumber } from \"../../lib/theme-utils\";\nimport { resolveFontFamily, useWidgetTheme } from \"../../lib/widget-theme\";\nimport { Touchable } from \"../ui/pressable\";\n\ntype FormValue = string | number | boolean | string[];\n\ninterface FormStepProps {\n  payload: FormPayload;\n  isProcessing?: boolean;\n  onComplete: (formData: Record<string, FormValue>) => void;\n}\n\ninterface FieldControlProps {\n  field: FormField;\n  value: FormValue | undefined;\n  theme: Required<ComponentTheme>;\n  fontFamily: string | undefined;\n  hasError: boolean;\n  onChange: (value: FormValue) => void;\n  /** Multiselect only — adds or removes one option from the array value. */\n  onToggleOption: (optionValue: string, checked: boolean) => void;\n}\n\ninterface CheckboxProps {\n  checked: boolean;\n  /** Web sizes the two checkbox flavours differently (`w-3.5` vs `w-4`). */\n  size: number;\n  theme: Required<ComponentTheme>;\n}\n\ninterface OptionRowProps {\n  label: string;\n  selected: boolean;\n  /** The placeholder row, which reads as absence rather than a choice. */\n  muted?: boolean;\n  theme: Required<ComponentTheme>;\n  fontFamily: string | undefined;\n  onPress: () => void;\n}\n\n/** Keyboard and correction behaviour a field type asks for. */\ninterface TextInputTraits {\n  keyboardType: KeyboardTypeOptions;\n  autoCapitalize: \"none\" | \"sentences\";\n  autoCorrect: boolean;\n}\n\n/** `animate-spin` — one linear turn per second, the CSS default. */\nconst SPIN_DURATION_MS = 1000;\n\n/** Used only if a theme ships an unparseable `borderRadius`. */\nconst FIELD_RADIUS_FALLBACK = 8;\n\n/** Half the gap between stacked rows, so neighbouring touch areas never overlap. */\nconst OPTION_HIT_SLOP = 3;\n\n/** `SquareCheckBig` is lucide's current name for the web source's `CheckSquare`. */\nconst fieldIcons: Record<string, LucideIcon> = {\n  text: Type,\n  email: Mail,\n  tel: Phone,\n  number: Type,\n  select: ChevronDown,\n  multiselect: List,\n  textarea: FileText,\n  boolean: SquareCheckBig,\n  date: Calendar,\n};\n\n/**\n * Web resolves the component theme from a context that `interactive-flow`\n * installs. RN resolves it at the leaf: the inputs are the same — widget\n * colours as the base, the payload's own `theme` on top — and a step rendered\n * on its own, outside a flow, still themes correctly.\n */\nconst useStepTheme = (componentTheme?: ComponentTheme): Required<ComponentTheme> => {\n  const widgetTheme = useWidgetTheme();\n\n  return useMemo(\n    () =>\n      mergeTheme({\n        primaryColor: widgetTheme.primaryColor,\n        primaryTextColor: widgetTheme.primaryTextColor,\n        // Cards read as bordered surfaces sitting ON the panel, so they take\n        // the widget background rather than the (greyer) surface colour.\n        backgroundColor: widgetTheme.backgroundColor,\n        surfaceColor: widgetTheme.surfaceColor,\n        textColor: widgetTheme.textColor,\n        mutedTextColor: widgetTheme.mutedTextColor,\n        borderColor: widgetTheme.borderColor,\n        errorColor: widgetTheme.errorColor,\n        successColor: widgetTheme.successColor,\n        buttonStyle: widgetTheme.buttonStyle,\n        // Web inherits the family from the flow container; RN has no cascade,\n        // so it travels through the theme and is applied per <Text>.\n        fontFamily: widgetTheme.fontFamily,\n        ...componentTheme,\n      }),\n    [componentTheme, widgetTheme],\n  );\n};\n\nconst getOptionLabel = (option: string | FormFieldOption): string => (typeof option === \"string\" ? option : option.label);\n\nconst getOptionValue = (option: string | FormFieldOption): string => (typeof option === \"string\" ? option : option.value);\n\nconst placeholderFor = (field: FormField): string => field.placeholder || `Enter ${field.label.toLowerCase()}`;\n\nconst textInputTraits = (type: FormFieldType): TextInputTraits => {\n  switch (type) {\n    case \"email\":\n      return { keyboardType: \"email-address\", autoCapitalize: \"none\", autoCorrect: false };\n    case \"tel\":\n      return { keyboardType: \"phone-pad\", autoCapitalize: \"none\", autoCorrect: false };\n    // No picker without a dependency, so a date is typed. The punctuation\n    // keyboard at least puts `-` and `/` on the first layer.\n    case \"date\":\n      return { keyboardType: \"numbers-and-punctuation\", autoCapitalize: \"none\", autoCorrect: false };\n    default:\n      return { keyboardType: \"default\", autoCapitalize: \"sentences\", autoCorrect: true };\n  }\n};\n\nconst inputSurface = (theme: Required<ComponentTheme>, hasError: boolean, isFocused: boolean): ViewStyle => ({\n  backgroundColor: theme.backgroundColor,\n  borderWidth: 1,\n  // Web draws a 2px focus ring, which RN has no equivalent for, so the border\n  // itself carries focus. An error outranks it — it is the more urgent signal.\n  borderColor: hasError ? theme.errorColor : isFocused ? solidColor(theme.primaryColor) : theme.borderColor,\n  // Fields follow the card radius, not the button radius — pill-shaped\n  // textareas read badly.\n  borderRadius: toNumber(theme.borderRadius, FIELD_RADIUS_FALLBACK),\n});\n\nconst validateField = (field: FormField, value: FormValue | undefined): string | null => {\n  // Handle required validation for different types\n  if (field.required) {\n    if (value === undefined || value === null || value === \"\") {\n      return `${field.label} is required`;\n    }\n    if (Array.isArray(value) && value.length === 0) {\n      return `${field.label} is required`;\n    }\n    if (typeof value === \"string\" && !value.trim()) {\n      return `${field.label} is required`;\n    }\n  }\n\n  // String-specific validations\n  if (typeof value === \"string\" && value) {\n    if (field.validation) {\n      if (field.validation.minLength && value.length < field.validation.minLength) {\n        return field.validation.message || `${field.label} must be at least ${field.validation.minLength} characters`;\n      }\n      if (field.validation.maxLength && value.length > field.validation.maxLength) {\n        return field.validation.message || `${field.label} must be at most ${field.validation.maxLength} characters`;\n      }\n      if (field.validation.pattern) {\n        const regex = new RegExp(field.validation.pattern);\n        if (!regex.test(value)) {\n          return field.validation.message || `${field.label} is invalid`;\n        }\n      }\n    }\n\n    if (field.type === \"email\") {\n      const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n      if (!emailRegex.test(value)) {\n        return \"Please enter a valid email address\";\n      }\n    }\n\n    if (field.type === \"tel\") {\n      const phoneRegex = /^[\\d\\s\\-+()]{7,}$/;\n      if (!phoneRegex.test(value)) {\n        return \"Please enter a valid phone number\";\n      }\n    }\n  }\n\n  return null;\n};\n\n/** `LoaderCircle` is lucide's current name for the web source's `Loader2`. */\nconst Spinner: FC<{ color: string }> = ({ color }) => {\n  const turn = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    const loop = Animated.loop(Animated.timing(turn, { toValue: 1, duration: SPIN_DURATION_MS, easing: Easing.linear, useNativeDriver: true }));\n    loop.start();\n    return () => loop.stop();\n  }, [turn]);\n\n  return (\n    <Animated.View style={{ transform: [{ rotate: turn.interpolate({ inputRange: [0, 1], outputRange: [\"0deg\", \"360deg\"] }) }] }}>\n      <LoaderCircle size={16} color={color} />\n    </Animated.View>\n  );\n};\n\n/** Stands in for `<input type=\"checkbox\">`, whose `accentColor` is the fill. */\nconst Checkbox: FC<CheckboxProps> = ({ checked, size, theme }) => (\n  <GradientFill color={checked ? theme.primaryColor : theme.backgroundColor} style={[styles.checkbox, { width: size, height: size, borderColor: checked ? solidColor(theme.primaryColor) : theme.borderColor }]}>\n    {checked ? <Check size={size - 4} color={theme.primaryTextColor} strokeWidth={3} /> : null}\n  </GradientFill>\n);\n\nconst OptionRow: FC<OptionRowProps> = ({ label, selected, muted = false, theme, fontFamily, onPress }) => (\n  <Touchable style={styles.optionRow} hitSlop={OPTION_HIT_SLOP} onPress={onPress}>\n    <Text style={[styles.optionLabel, { color: muted ? theme.mutedTextColor : theme.textColor, fontFamily }, selected ? styles.optionLabelSelected : null]} numberOfLines={1}>\n      {label}\n    </Text>\n    {selected ? <Check size={14} color={solidColor(theme.primaryColor)} /> : null}\n  </Touchable>\n);\n\nconst FieldControl: FC<FieldControlProps> = ({ field, value, theme, fontFamily, hasError, onChange, onToggleOption }) => {\n  const [isFocused, setIsFocused] = useState(false);\n  // A DOM number input holds half-typed text (\"12.\", \"-\") in the node itself\n  // and reports a value only once it parses. RN's TextInput has no such\n  // buffer, so the raw text lives here and `formData` keeps the number the web\n  // version would have submitted.\n  const [numberText, setNumberText] = useState(typeof value === \"number\" ? String(value) : \"\");\n\n  const surface = inputSurface(theme, hasError, isFocused);\n  const textStyle = [styles.input, surface, { color: theme.textColor, fontFamily }];\n  const focusHandlers = { onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false) };\n\n  switch (field.type) {\n    case \"select\": {\n      if (!field.options) return null;\n      const selected = typeof value === \"string\" ? value : \"\";\n\n      // RN has no `<select>`, and a modal picker would hide the choices behind\n      // a tap the web version does not ask for. The options are rendered\n      // inline instead, keeping the DOM's empty placeholder option as the row\n      // that clears the field.\n      return (\n        <View style={[styles.optionList, surface]}>\n          <OptionRow label={field.placeholder || `Select ${field.label.toLowerCase()}`} muted selected={selected === \"\"} theme={theme} fontFamily={fontFamily} onPress={() => onChange(\"\")} />\n          {field.options.map((option, idx) => (\n            <OptionRow key={idx} label={getOptionLabel(option)} selected={selected === getOptionValue(option)} theme={theme} fontFamily={fontFamily} onPress={() => onChange(getOptionValue(option))} />\n          ))}\n        </View>\n      );\n    }\n\n    case \"multiselect\": {\n      if (!field.options) return null;\n      const chosen = Array.isArray(value) ? value : [];\n\n      return (\n        <View style={[styles.optionList, surface]}>\n          {field.options.map((option, idx) => {\n            const optionValue = getOptionValue(option);\n            const isChecked = chosen.includes(optionValue);\n\n            return (\n              <Touchable key={idx} style={styles.checkRow} hitSlop={OPTION_HIT_SLOP} onPress={() => onToggleOption(optionValue, !isChecked)}>\n                <Checkbox checked={isChecked} size={14} theme={theme} />\n                <Text style={[styles.optionLabel, { color: theme.textColor, fontFamily }]}>{getOptionLabel(option)}</Text>\n              </Touchable>\n            );\n          })}\n        </View>\n      );\n    }\n\n    case \"boolean\":\n      return (\n        <Touchable style={styles.booleanRow} onPress={() => onChange(value !== true)}>\n          <Checkbox checked={value === true} size={16} theme={theme} />\n          <Text style={[styles.optionLabel, { color: theme.mutedTextColor, fontFamily }]}>{field.placeholder || \"Yes\"}</Text>\n        </Touchable>\n      );\n\n    case \"textarea\":\n      return (\n        <TextInput\n          {...focusHandlers}\n          style={[textStyle, styles.textarea]}\n          placeholder={placeholderFor(field)}\n          placeholderTextColor={theme.mutedTextColor}\n          value={typeof value === \"string\" ? value : \"\"}\n          onChangeText={onChange}\n          multiline\n          numberOfLines={2}\n        />\n      );\n\n    case \"number\":\n      return (\n        <TextInput\n          {...focusHandlers}\n          style={textStyle}\n          placeholder={placeholderFor(field)}\n          placeholderTextColor={theme.mutedTextColor}\n          value={numberText}\n          onChangeText={(text) => {\n            setNumberText(text);\n            const parsed = Number(text);\n            // A numeric keyboard still allows \"1.2.3\" and a lone \"-\", which the\n            // DOM would have reported as an empty value.\n            onChange(text.trim() === \"\" || Number.isNaN(parsed) ? \"\" : parsed);\n          }}\n          keyboardType=\"numeric\"\n        />\n      );\n\n    default: {\n      const traits = textInputTraits(field.type);\n\n      return (\n        <TextInput\n          {...focusHandlers}\n          style={textStyle}\n          placeholder={placeholderFor(field)}\n          placeholderTextColor={theme.mutedTextColor}\n          value={typeof value === \"string\" ? value : \"\"}\n          onChangeText={onChange}\n          keyboardType={traits.keyboardType}\n          autoCapitalize={traits.autoCapitalize}\n          autoCorrect={traits.autoCorrect}\n        />\n      );\n    }\n  }\n};\n\nconst FormStep: FC<FormStepProps> = ({ payload, isProcessing, onComplete }) => {\n  const theme = useStepTheme(payload.theme);\n  const buttonRadius = getButtonRadius(theme.buttonStyle);\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  const { data } = payload;\n  const [formData, setFormData] = useState<Record<string, FormValue>>({});\n  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});\n\n  const clearFieldError = (fieldName: string) => {\n    setFieldErrors((prev) => {\n      if (!prev[fieldName]) return prev;\n      const next = { ...prev };\n      delete next[fieldName];\n      return next;\n    });\n  };\n\n  const validateAllFields = (): boolean => {\n    const errors: Record<string, string> = {};\n    let isValid = true;\n\n    data.fields.forEach((field) => {\n      const error = validateField(field, formData[field.name]);\n      if (error) {\n        errors[field.name] = error;\n        isValid = false;\n      }\n    });\n\n    setFieldErrors(errors);\n    return isValid;\n  };\n\n  const handleFieldChange = (fieldName: string, value: FormValue) => {\n    setFormData((prev) => ({ ...prev, [fieldName]: value }));\n    clearFieldError(fieldName);\n  };\n\n  const handleMultiselectChange = (fieldName: string, optionValue: string, checked: boolean) => {\n    setFormData((prev) => {\n      const currentValues = (prev[fieldName] as string[] | undefined) || [];\n      if (checked) {\n        return { ...prev, [fieldName]: [...currentValues, optionValue] };\n      } else {\n        return { ...prev, [fieldName]: currentValues.filter((v) => v !== optionValue) };\n      }\n    });\n    clearFieldError(fieldName);\n  };\n\n  const handleSubmit = () => {\n    if (validateAllFields()) {\n      onComplete(formData);\n    }\n  };\n\n  const submitTextColor = isProcessing ? theme.mutedTextColor : theme.primaryTextColor;\n\n  return (\n    // The form may be the tallest thing on screen in a host app, so it owns its\n    // keyboard handling. With an unbounded parent the ScrollView simply lays\n    // out at content height and never steals a scroll gesture from the chat.\n    <KeyboardAvoidingView behavior={Platform.OS === \"ios\" ? \"padding\" : undefined}>\n      <ScrollView keyboardShouldPersistTaps=\"handled\" nestedScrollEnabled bounces={false} showsVerticalScrollIndicator={false}>\n        <View style={styles.header}>\n          <FileText size={16} color={solidColor(theme.primaryColor)} />\n          <Text style={[styles.title, { color: theme.textColor, fontFamily }]}>{data.title}</Text>\n        </View>\n\n        {data.description ? <Text style={[styles.description, { color: theme.mutedTextColor, fontFamily }]}>{data.description}</Text> : null}\n\n        <View style={styles.fields}>\n          {data.fields.map((field) => {\n            const FieldIcon = fieldIcons[field.type] ?? Type;\n            const error = fieldErrors[field.name];\n\n            return (\n              <View key={field.name}>\n                <View style={styles.labelRow}>\n                  <FieldIcon size={12} color={theme.mutedTextColor} />\n                  <Text style={[styles.label, { color: theme.mutedTextColor, fontFamily }]}>{field.label}</Text>\n                  {field.required ? <Text style={[styles.label, { color: theme.errorColor, fontFamily }]}>*</Text> : null}\n                </View>\n\n                <FieldControl\n                  field={field}\n                  value={formData[field.name]}\n                  theme={theme}\n                  fontFamily={fontFamily}\n                  hasError={!!error}\n                  onChange={(value) => handleFieldChange(field.name, value)}\n                  onToggleOption={(optionValue, checked) => handleMultiselectChange(field.name, optionValue, checked)}\n                />\n\n                {error ? <Text style={[styles.error, { color: theme.errorColor, fontFamily }]}>{error}</Text> : null}\n              </View>\n            );\n          })}\n        </View>\n\n        <Touchable onPress={handleSubmit} disabled={isProcessing}>\n          <GradientFill color={isProcessing ? theme.borderColor : theme.primaryColor} style={[styles.submitButton, { borderRadius: buttonRadius }]}>\n            {isProcessing ? (\n              <>\n                <Spinner color={submitTextColor} />\n                <Text style={[styles.submitLabel, { color: submitTextColor, fontFamily }]}>Submitting...</Text>\n              </>\n            ) : (\n              <Text style={[styles.submitLabel, { color: submitTextColor, fontFamily }]}>{data.submit_label || \"Next\"}</Text>\n            )}\n          </GradientFill>\n        </Touchable>\n      </ScrollView>\n    </KeyboardAvoidingView>\n  );\n};\n\nconst styles = StyleSheet.create({\n  header: { flexDirection: \"row\", alignItems: \"center\", gap: 8, marginBottom: 8 },\n  title: { fontSize: 14, lineHeight: 20, fontWeight: \"500\" },\n  description: { fontSize: 12, lineHeight: 16, marginBottom: 12 },\n  fields: { gap: 10, marginBottom: 12 },\n  labelRow: { flexDirection: \"row\", alignItems: \"center\", gap: 4, marginBottom: 4 },\n  label: { fontSize: 12, lineHeight: 16, fontWeight: \"500\" },\n  // No `lineHeight`: Android centres single-line input text off it.\n  input: { fontSize: 12, paddingHorizontal: 12, paddingVertical: 8, minHeight: 34 },\n  // Web's `rows={2}` at this type size: two 16px lines plus the padding.\n  textarea: { minHeight: 50, textAlignVertical: \"top\" },\n  optionList: { padding: 8, gap: 6 },\n  optionRow: { flexDirection: \"row\", alignItems: \"center\", justifyContent: \"space-between\", gap: 8 },\n  optionLabel: { flexShrink: 1, fontSize: 12, lineHeight: 16 },\n  optionLabelSelected: { fontWeight: \"600\" },\n  checkRow: { flexDirection: \"row\", alignItems: \"center\", gap: 8 },\n  checkbox: { borderRadius: 4, borderWidth: 1, alignItems: \"center\", justifyContent: \"center\" },\n  booleanRow: { flexDirection: \"row\", alignItems: \"center\", gap: 8, paddingVertical: 4 },\n  error: { fontSize: 12, lineHeight: 16, marginTop: 2 },\n  submitButton: { height: 36, flexDirection: \"row\", alignItems: \"center\", justifyContent: \"center\", gap: 8 },\n  submitLabel: { fontSize: 14, lineHeight: 20, fontWeight: \"600\" },\n});\n\nexport default FormStep;\n","/**\n * `<AnimatePresence mode=\"wait\">` for React Native.\n *\n * framer-motion's \"wait\" mode is a two-beat hand-off: the outgoing child plays\n * its exit to completion, and only then does the incoming child enter. React\n * gives neither beat for free — swapping a `key` replaces the subtree in one\n * commit, so the old content disappears instantly and the two animations that\n * should have been sequential collapse into one.\n *\n * This keeps the outgoing node in state, animates it out, and swaps only when\n * that finishes. Each node carries the offsets it should leave by, so a step\n * sliding out sideways and a pill dropping upward stay distinct — the outgoing\n * animation uses the vector that was active when it was rendered, not whatever\n * the incoming child wants.\n */\n\nimport { useEffect, useRef, useState, type FC, type ReactNode } from \"react\";\nimport { Animated, Easing } from \"react-native\";\n\n/** Where a node comes from on enter, and leaves to on exit, in dp. */\nexport interface SwapOffsets {\n  enterX?: number;\n  enterY?: number;\n  exitX?: number;\n  exitY?: number;\n}\n\ninterface AnimatedSwapProps extends SwapOffsets {\n  /** Changing this plays the hand-off. Equal keys re-render in place. */\n  swapKey: string | number;\n  durationMs?: number;\n  children: ReactNode;\n}\n\ninterface Held extends SwapOffsets {\n  key: string | number;\n  node: ReactNode;\n}\n\n/** framer's default tween easing, and the source's 0.2s step transition. */\nconst DEFAULT_DURATION_MS = 200;\nconst SWAP_EASING = Easing.inOut(Easing.ease);\n\nconst offsetsOf = (props: SwapOffsets): SwapOffsets => ({ enterX: props.enterX ?? 0, enterY: props.enterY ?? 0, exitX: props.exitX ?? 0, exitY: props.exitY ?? 0 });\n\nexport const AnimatedSwap: FC<AnimatedSwapProps> = ({ swapKey, durationMs = DEFAULT_DURATION_MS, children, ...offsets }) => {\n  const progress = useRef(new Animated.Value(1)).current;\n  const [held, setHeld] = useState<Held>({ key: swapKey, node: children, ...offsetsOf(offsets) });\n\n  // Kept in a ref so the swap effect depends only on the key: re-rendering the\n  // SAME step with new props must update the content in place, never restart\n  // the hand-off.\n  const incoming = useRef<Held>(held);\n  incoming.current = { key: swapKey, node: children, ...offsetsOf(offsets) };\n\n  const heldKey = useRef(held.key);\n  heldKey.current = held.key;\n\n  useEffect(() => {\n    if (heldKey.current === swapKey) {\n      // Same node, fresh props — adopt them without animating.\n      setHeld(incoming.current);\n      return;\n    }\n\n    const exit = Animated.timing(progress, { toValue: 0, duration: durationMs, easing: SWAP_EASING, useNativeDriver: true });\n    exit.start(({ finished }) => {\n      if (!finished) return;\n      setHeld(incoming.current);\n      progress.setValue(0);\n      Animated.timing(progress, { toValue: 1, duration: durationMs, easing: SWAP_EASING, useNativeDriver: true }).start();\n    });\n    return () => exit.stop();\n    // Deliberately keyed on `swapKey` alone: `held` is read through the ref as\n    // a comparison target, and depending on the node itself would restart the\n    // hand-off on every parent render.\n  }, [swapKey, durationMs, progress]);\n\n  // Leaving uses the held node's own exit vector; arriving uses its enter one.\n  // `progress` runs 0→1 in both directions, so one interpolation covers both.\n  const translateX = progress.interpolate({ inputRange: [0, 1], outputRange: [held.key === swapKey ? (held.enterX ?? 0) : (held.exitX ?? 0), 0] });\n  const translateY = progress.interpolate({ inputRange: [0, 1], outputRange: [held.key === swapKey ? (held.enterY ?? 0) : (held.exitY ?? 0), 0] });\n\n  return <Animated.View style={{ opacity: progress, transform: [{ translateX }, { translateY }] }}>{held.node}</Animated.View>;\n};\n","/**\n * One transcript entry — RN counterpart of the web widget's `message-item`.\n *\n * Two shapes, decided by one flag: user messages always sit in a bubble on the\n * surface colour; agent messages render bubble-less on the panel unless the\n * theme sets `agentBubbleColor`, which may be a gradient and so paints through\n * <GradientFill>.\n *\n * The web `data-ringg-role` attribute has no counterpart here — an RN node\n * carries exactly one queryable string, `testID`, and that slot belongs to the\n * contract name. Which side spoke stays readable from the bubble's alignment.\n */\n\nimport type { FC, ReactNode } from \"react\";\nimport { Linking, StyleSheet, Text, View } from \"react-native\";\nimport type { ChatMessage } from \"@ringg/core\";\n\nimport { GradientFill, solidColor } from \"../lib/gradient\";\nimport { Markdown } from \"../lib/markdown\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveFontFamily, useWidgetTheme } from \"../lib/widget-theme\";\nimport { Touchable } from \"./ui/pressable\";\n\ninterface MessageItemProps {\n  /** Position in the transcript. Web feeds it to the list key; kept so both\n   *  trees take the same props and a caller can be ported line for line. */\n  itemIndex: number;\n  message: ChatMessage;\n  /** Rendered full width below the body, inside the bubble. */\n  children?: ReactNode;\n  /** Feedback replay shows component prompts without their text. */\n  hideMessageContent?: boolean;\n}\n\n/** `text-[15px]` on the bubble's `leading-[1.3]`. */\nconst BODY_FONT_SIZE = 15;\nconst LINE_HEIGHT_RATIO = 1.3;\n\n/** The RAG citation's `text-[13px]`. */\nconst SOURCE_FONT_SIZE = 13;\n\n/** `rounded-xl`, with the corner nearest the speaker pinched to 2. */\nconst BUBBLE_RADIUS = 12;\nconst ANCHORED_RADIUS = 2;\n\n/** `pl-3 pr-2 py-2` — the bubble is tighter on the side the content ends. */\nconst BUBBLE_PADDING_LEFT = 12;\nconst BUBBLE_PADDING_RIGHT = 8;\nconst BUBBLE_PADDING_VERTICAL = 8;\n\n/** `gap-2.5` between body, source link and attachment. */\nconst CONTENT_GAP = 10;\n\nconst MessageItem: FC<MessageItemProps> = ({ message, children, hideMessageContent = false }) => {\n  const theme = useWidgetTheme();\n  // Side is decided by isSelf, never by name — live agents carry their display\n  // name (\"Neha\"), so name-sniffing misclassifies them as user messages.\n  const isAgentMessage = !message.isSelf;\n  const agentBubble = theme.agentBubbleColor.trim();\n  const bubbled = !isAgentMessage || Boolean(agentBubble);\n  const shouldRenderMessageBody = !hideMessageContent && Boolean(message.message.trim());\n  const sourceUrl = message.sourceUrl;\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  const body = isAgentMessage ? (\n    <View testID={ringgId(\"message-body\")}>\n      <Markdown\n        content={message.message}\n        color={theme.textColor}\n        mutedColor={theme.mutedTextColor}\n        // prose leaves markdown links at its near-black default. A tappable run\n        // on a phone has to read as tappable, so it takes the same primary\n        // colour the source link below already uses.\n        linkColor={solidColor(theme.primaryColor)}\n        fontSize={BODY_FONT_SIZE}\n        fontFamily={fontFamily}\n      />\n    </View>\n  ) : (\n    // Self messages are an echo of what the user typed; running them through\n    // markdown would reformat their own text back at them.\n    <Text testID={ringgId(\"message-body\")} style={[styles.body, { color: theme.textColor, fontFamily }]}>\n      {message.message}\n    </Text>\n  );\n\n  return (\n    <View style={isAgentMessage ? styles.rowStart : styles.rowEnd} testID={ringgId(\"message\")}>\n      <View testID={ringgId(\"message-bubble\")} style={[styles.bubble, bubbled ? [styles.bubbleBox, isAgentMessage ? styles.agentCorners : styles.userCorners] : null]}>\n        {/* Painted as a layer rather than a background colour: agentBubbleColor\n            may be a gradient, and RN has no gradient `backgroundColor`. */}\n        {bubbled ? <GradientFill color={isAgentMessage ? agentBubble : theme.surfaceColor} style={StyleSheet.absoluteFill} /> : null}\n        <View testID={ringgId(\"message-content\")} style={[styles.content, bubbled ? styles.contentPadding : null]}>\n          {shouldRenderMessageBody ? body : null}\n          {sourceUrl ? (\n            <Touchable\n              testID={ringgId(\"message-source\")}\n              style={styles.source}\n              accessibilityLabel={`Source: ${sourceUrl}`}\n              onPress={() => {\n                // Best-effort: a malformed or unhandled scheme must not crash\n                // the widget. `Linking` is RN's `target=\"_blank\"`.\n                void Linking.openURL(sourceUrl).catch(() => {});\n              }}\n            >\n              <Text style={[styles.sourceText, { color: solidColor(theme.primaryColor), fontFamily }]}>Source: {sourceUrl}</Text>\n            </Touchable>\n          ) : null}\n          {children ? (\n            <View testID={ringgId(\"message-attachment\")} style={styles.attachment}>\n              {children}\n            </View>\n          ) : null}\n        </View>\n      </View>\n    </View>\n  );\n};\n\nexport default MessageItem;\n\nconst styles = StyleSheet.create({\n  // Web anchors the bubble with `mr-auto` / `ml-auto` inside a `flex-col\n  // items-start` column; alignItems says the same thing natively.\n  rowStart: { alignItems: \"flex-start\" },\n  rowEnd: { alignItems: \"flex-end\" },\n  // `max-w-[80%]` — the bubble hugs its content up to 80% of the transcript.\n  bubble: { maxWidth: \"80%\" },\n  // The gradient layer fills the bubble, so the padding lives one level in on\n  // the content; `overflow` is what clips that layer to the rounded corners.\n  bubbleBox: { overflow: \"hidden\" },\n  agentCorners: { borderTopLeftRadius: BUBBLE_RADIUS, borderTopRightRadius: BUBBLE_RADIUS, borderBottomLeftRadius: ANCHORED_RADIUS, borderBottomRightRadius: BUBBLE_RADIUS },\n  userCorners: { borderTopLeftRadius: BUBBLE_RADIUS, borderTopRightRadius: BUBBLE_RADIUS, borderBottomLeftRadius: BUBBLE_RADIUS, borderBottomRightRadius: ANCHORED_RADIUS },\n  content: { gap: CONTENT_GAP },\n  contentPadding: { paddingLeft: BUBBLE_PADDING_LEFT, paddingRight: BUBBLE_PADDING_RIGHT, paddingVertical: BUBBLE_PADDING_VERTICAL },\n  body: { fontSize: BODY_FONT_SIZE, lineHeight: BODY_FONT_SIZE * LINE_HEIGHT_RATIO },\n  // `w-fit`: the citation's touch area stops at the end of the URL rather than\n  // spanning the bubble. Press feedback replaces the web's hover underline.\n  source: { alignSelf: \"flex-start\" },\n  sourceText: { fontSize: SOURCE_FONT_SIZE, lineHeight: SOURCE_FONT_SIZE * LINE_HEIGHT_RATIO },\n  attachment: { alignSelf: \"stretch\" },\n});\n","/**\n * Markdown for chat bubbles.\n *\n * The web widget hands agent replies to `react-markdown` + `remark-gfm` and\n * lets Tailwind's prose plugin style the result. Neither of those crosses to\n * RN, and this package takes no dependency for it, so what lives here is a\n * renderer for the subset that actually appears in agent replies. Everything\n * else falls through as the literal text the model wrote — a reply must never\n * show half-parsed markup.\n *\n * Supported: paragraphs, `**bold**`, `*italic*`, inline code, `[links](url)`\n * (handed to `Linking`), bullet and ordered lists, `#` through `######`\n * headings, fenced code blocks, blockquotes (which may contain further\n * blocks), horizontal rules, and backslash escapes.\n *\n * Not supported, deliberately: TABLES — GFM's headline feature, but a\n * phone-width bubble has nowhere to put one, so a table degrades to a\n * paragraph of its pipe-separated source. Also absent: images (rendered as\n * their alt text), strikethrough, task lists, footnotes, reference links, raw\n * HTML, and nested list indentation (nested items flatten into their parent\n * list).\n *\n * Soft line breaks inside a paragraph collapse into spaces, which is what the\n * browser does for the web widget.\n */\n\nimport { Fragment, useMemo, type FC, type ReactNode } from \"react\";\nimport { Linking, Platform, StyleSheet, Text, View } from \"react-native\";\n\ntype HeadingLevel = 1 | 2 | 3 | 4;\n\n/**\n * `strong` / `em` / `link` nest, so they carry children rather than a string:\n * `**bold with a [link](x)**` has to render as one styled run.\n */\ntype InlineToken =\n  | { kind: \"text\"; value: string }\n  | { kind: \"code\"; value: string }\n  | { kind: \"strong\"; children: InlineToken[] }\n  | { kind: \"em\"; children: InlineToken[] }\n  | { kind: \"link\"; href: string; children: InlineToken[] };\n\ntype Block =\n  | { kind: \"paragraph\"; content: InlineToken[] }\n  | { kind: \"heading\"; level: HeadingLevel; content: InlineToken[] }\n  | { kind: \"code\"; text: string }\n  | { kind: \"quote\"; children: Block[] }\n  | { kind: \"list\"; ordered: boolean; start: number; items: InlineToken[][] }\n  | { kind: \"rule\" };\n\n/** Typography resolved once per render and threaded down to every renderer. */\ninterface MarkdownTheme {\n  color: string;\n  mutedColor: string;\n  linkColor: string;\n  fontSize: number;\n  lineHeight: number;\n  codeFontSize: number;\n  fontFamily: string | undefined;\n}\n\ninterface BlocksProps {\n  blocks: Block[];\n  theme: MarkdownTheme;\n}\n\ninterface MarkdownProps {\n  content: string;\n  /** Body text. */\n  color: string;\n  /** Chrome that is not text: the rule, the quote bar, the code outline. */\n  mutedColor: string;\n  linkColor: string;\n  fontSize?: number;\n  fontFamily?: string;\n}\n\n/** The widget's chat body size, matching the web bubble's `text-[15px]`. */\nconst DEFAULT_FONT_SIZE = 15;\n\n/** The bubble's `leading-[1.3]`. */\nconst LINE_HEIGHT_RATIO = 1.3;\n\n/**\n * prose renders code at ~0.86em; on the 15px chat body that lands on 12, which\n * is what the Flutter widget settles on too. Kept as a ratio so a caller that\n * overrides `fontSize` moves the code with it.\n */\nconst CODE_FONT_RATIO = 0.8;\n\n/** Space between stacked blocks — prose's paragraph margin, tightened for a bubble. */\nconst BLOCK_GAP = 8;\n\nconst LIST_ITEM_GAP = 4;\nconst BULLET = \"•\";\n\nconst MONOSPACE_FONT = Platform.select({ ios: \"Menlo\", default: \"monospace\" });\n\nconst FENCE_PATTERN = /^\\s{0,3}(`{3,}|~{3,})/;\nconst HEADING_PATTERN = /^\\s{0,3}(#{1,6})\\s+(.*)$/;\nconst RULE_PATTERN = /^\\s{0,3}(?:-{3,}|\\*{3,}|_{3,})\\s*$/;\nconst QUOTE_PATTERN = /^\\s{0,3}>\\s?(.*)$/;\nconst BULLET_PATTERN = /^(\\s*)[-*+]\\s+(.*)$/;\nconst ORDERED_PATTERN = /^(\\s*)(\\d{1,9})[.)]\\s+(.*)$/;\n\n/**\n * One alternation over every inline construct, so the tokenizer always takes\n * the leftmost one and never has to guess precedence between two passes.\n * Groups: 1 escaped char, 2 code, 3 emphasis delimiter, 4 its body, 5 image\n * bang, 6 link text, 7 href.\n *\n * `\\3` forces the run of `*`/`_` that closes to be the run that opened, which\n * is what keeps `***both***` from leaving a stray asterisk behind. The `\\S…\\S`\n * body is CommonMark's \"no space just inside the delimiter\" rule — it is what\n * stops `2 * 3 * 4` from turning italic.\n */\nconst INLINE_PATTERN = /\\\\([\\\\`*_[\\]()#+\\-.!>])|`([^`]+)`|(\\*{1,3}|_{1,3})(\\S[\\s\\S]*?\\S|\\S)\\3|(!?)\\[([^\\]]*)\\]\\(\\s*<?([^)>\\s]*)>?(?:\\s+\"[^\"]*\")?\\s*\\)/;\n\nconst HEADING_SCALE: Record<HeadingLevel, { sizeDelta: number; fontWeight: \"600\" | \"700\" }> = {\n  // 20 / 18 / 16 / 15 against the 15px body — prose-sm's scale, and the same\n  // steps the Flutter widget uses. h4 and below share the body size.\n  1: { sizeDelta: 5, fontWeight: \"700\" },\n  2: { sizeDelta: 3, fontWeight: \"700\" },\n  3: { sizeDelta: 1, fontWeight: \"600\" },\n  4: { sizeDelta: 0, fontWeight: \"600\" },\n};\n\nconst isWordChar = (char: string | undefined): boolean => char !== undefined && /[A-Za-z0-9]/.test(char);\n\n/** `*` italic, `**` bold, `***` both — CommonMark's emphasis nesting. */\nconst emphasis = (delimiters: number, children: InlineToken[]): InlineToken => {\n  switch (delimiters) {\n    case 1:\n      return { kind: \"em\", children };\n    case 2:\n      return { kind: \"strong\", children };\n    default:\n      return { kind: \"strong\", children: [{ kind: \"em\", children }] };\n  }\n};\n\nconst headingLevel = (hashes: string): HeadingLevel => {\n  switch (hashes.length) {\n    case 1:\n      return 1;\n    case 2:\n      return 2;\n    case 3:\n      return 3;\n    default:\n      return 4;\n  }\n};\n\nconst openUrl = (url: string): void => {\n  // Best-effort: a malformed or unhandled scheme must not crash the widget.\n  void Linking.openURL(url).catch(() => {});\n};\n\nconst tokenizeInline = (source: string): InlineToken[] => {\n  const tokens: InlineToken[] = [];\n  // A fresh instance per call — this function recurses, and a shared\n  // `lastIndex` would corrupt the scan it returns into.\n  const pattern = new RegExp(INLINE_PATTERN.source, \"g\");\n  let cursor = 0;\n\n  const pushText = (value: string): void => {\n    if (value) tokens.push({ kind: \"text\", value });\n  };\n\n  let match = pattern.exec(source);\n  while (match !== null) {\n    pushText(source.slice(cursor, match.index));\n    cursor = match.index + match[0].length;\n\n    const escaped = match[1];\n    const code = match[2];\n    const delimiter = match[3];\n    const label = match[6];\n\n    if (escaped !== undefined) {\n      pushText(escaped);\n    } else if (code !== undefined) {\n      tokens.push({ kind: \"code\", value: code });\n    } else if (delimiter !== undefined) {\n      // `snake_case_name` is one word, not an emphasised middle. CommonMark\n      // only opens `_` emphasis at a word boundary; `*` may open anywhere.\n      if (delimiter.startsWith(\"_\") && isWordChar(source[match.index - 1])) pushText(match[0]);\n      else tokens.push(emphasis(delimiter.length, tokenizeInline(match[4] ?? \"\")));\n    } else if (label !== undefined) {\n      const href = match[7] ?? \"\";\n      // An image has no place in a text run — RN cannot size a remote image\n      // inline, and the alt text is what a screen reader would announce anyway.\n      // A link with nothing to press (no href, or no label) is dropped whole.\n      if (match[5] === \"!\" || !href || !label) pushText(label);\n      else tokens.push({ kind: \"link\", href, children: tokenizeInline(label) });\n    }\n\n    match = pattern.exec(source);\n  }\n\n  pushText(source.slice(cursor));\n  return tokens;\n};\n\n/** Whether a line would open a new block, used to end a paragraph run. */\nconst startsBlock = (line: string): boolean =>\n  FENCE_PATTERN.test(line) || HEADING_PATTERN.test(line) || RULE_PATTERN.test(line) || QUOTE_PATTERN.test(line) || BULLET_PATTERN.test(line) || ORDERED_PATTERN.test(line);\n\nconst splitBlocks = (source: string): Block[] => {\n  const lines = source.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n  const blocks: Block[] = [];\n  let index = 0;\n\n  while (index < lines.length) {\n    const line = lines[index] ?? \"\";\n\n    if (!line.trim()) {\n      index += 1;\n      continue;\n    }\n\n    const fence = FENCE_PATTERN.exec(line);\n    if (fence !== null) {\n      // Never fall back to \"\" — `startsWith(\"\")` would close the block instantly.\n      const marker = fence[1] ?? \"```\";\n      const body: string[] = [];\n      index += 1;\n      while (index < lines.length) {\n        const next = lines[index] ?? \"\";\n        index += 1;\n        if (next.trimStart().startsWith(marker)) break;\n        body.push(next);\n      }\n      // An unterminated fence runs to the end of the message, as CommonMark says.\n      blocks.push({ kind: \"code\", text: body.join(\"\\n\") });\n      continue;\n    }\n\n    const heading = HEADING_PATTERN.exec(line);\n    if (heading !== null) {\n      blocks.push({ kind: \"heading\", level: headingLevel(heading[1] ?? \"\"), content: tokenizeInline((heading[2] ?? \"\").trim()) });\n      index += 1;\n      continue;\n    }\n\n    if (RULE_PATTERN.test(line)) {\n      blocks.push({ kind: \"rule\" });\n      index += 1;\n      continue;\n    }\n\n    if (QUOTE_PATTERN.test(line)) {\n      const quoted: string[] = [];\n      while (index < lines.length) {\n        const marker = QUOTE_PATTERN.exec(lines[index] ?? \"\");\n        if (marker === null) break;\n        quoted.push(marker[1] ?? \"\");\n        index += 1;\n      }\n      // Every line shed its `>`, so the recursion is strictly smaller.\n      blocks.push({ kind: \"quote\", children: splitBlocks(quoted.join(\"\\n\")) });\n      continue;\n    }\n\n    const bullet = BULLET_PATTERN.exec(line);\n    const numbered = bullet === null ? ORDERED_PATTERN.exec(line) : null;\n    if (bullet !== null || numbered !== null) {\n      const ordered = numbered !== null;\n      const start = numbered === null ? 1 : Number(numbered[2] ?? \"1\");\n      const items: string[] = [];\n      while (index < lines.length) {\n        const current = lines[index] ?? \"\";\n        const item = ordered ? ORDERED_PATTERN.exec(current) : BULLET_PATTERN.exec(current);\n        if (item !== null) {\n          items.push((ordered ? item[3] : item[2]) ?? \"\");\n          index += 1;\n          continue;\n        }\n        // Lazy continuation: a plain wrapped line belongs to the item above it.\n        const lastIndex = items.length - 1;\n        const last = items[lastIndex];\n        if (last !== undefined && current.trim() && !startsBlock(current)) {\n          items[lastIndex] = `${last} ${current.trim()}`;\n          index += 1;\n          continue;\n        }\n        break;\n      }\n      blocks.push({ kind: \"list\", ordered, start, items: items.map((item) => tokenizeInline(item)) });\n      continue;\n    }\n\n    const paragraph: string[] = [];\n    while (index < lines.length) {\n      const current = lines[index] ?? \"\";\n      if (!current.trim()) break;\n      // The first line already failed every block test above; the guard is what\n      // guarantees the outer loop always consumes at least one line.\n      if (paragraph.length > 0 && startsBlock(current)) break;\n      paragraph.push(current.trim());\n      index += 1;\n    }\n    blocks.push({ kind: \"paragraph\", content: tokenizeInline(paragraph.join(\" \")) });\n  }\n\n  return blocks;\n};\n\n/**\n * Nested `<Text>` inherits colour and size from its parent, so only the\n * property each token changes is set here.\n */\nconst renderInline = (tokens: InlineToken[], theme: MarkdownTheme): ReactNode[] =>\n  tokens.map((token, index) => {\n    const key = `${token.kind}-${index}`;\n    switch (token.kind) {\n      case \"text\":\n        return <Fragment key={key}>{token.value}</Fragment>;\n      case \"code\":\n        return (\n          <Text key={key} style={[styles.code, { fontFamily: MONOSPACE_FONT, fontSize: theme.codeFontSize }]}>\n            {token.value}\n          </Text>\n        );\n      case \"strong\":\n        return (\n          <Text key={key} style={styles.strong}>\n            {renderInline(token.children, theme)}\n          </Text>\n        );\n      case \"em\":\n        return (\n          <Text key={key} style={styles.em}>\n            {renderInline(token.children, theme)}\n          </Text>\n        );\n      case \"link\":\n        // A link inside a text run has to stay a `<Text>` — a Touchable cannot\n        // live inside `<Text>` without breaking the line box.\n        return (\n          <Text key={key} accessibilityRole=\"link\" style={[styles.link, { color: theme.linkColor }]} onPress={() => openUrl(token.href)}>\n            {renderInline(token.children, theme)}\n          </Text>\n        );\n      default:\n        return null;\n    }\n  });\n\nconst Blocks: FC<BlocksProps> = ({ blocks, theme }) => {\n  const body = { color: theme.color, fontSize: theme.fontSize, lineHeight: theme.lineHeight, fontFamily: theme.fontFamily };\n\n  return (\n    <View style={styles.stack}>\n      {blocks.map((block, index) => {\n        const key = `${block.kind}-${index}`;\n        switch (block.kind) {\n          case \"paragraph\":\n            return (\n              <Text key={key} style={body}>\n                {renderInline(block.content, theme)}\n              </Text>\n            );\n          case \"heading\": {\n            const scale = HEADING_SCALE[block.level];\n            const fontSize = theme.fontSize + scale.sizeDelta;\n            return (\n              <Text key={key} style={[body, { fontSize, lineHeight: fontSize * LINE_HEIGHT_RATIO, fontWeight: scale.fontWeight }]}>\n                {renderInline(block.content, theme)}\n              </Text>\n            );\n          }\n          case \"code\":\n            // Long lines wrap rather than scroll: a horizontal scroller nested\n            // in the transcript's vertical one fights the user's gestures, and\n            // the bubble is already capped at 80% of the panel.\n            return (\n              <View key={key} style={[styles.codeBlock, { borderColor: theme.mutedColor }]}>\n                <Text style={{ color: theme.color, fontFamily: MONOSPACE_FONT, fontSize: theme.codeFontSize, lineHeight: theme.codeFontSize * LINE_HEIGHT_RATIO }}>{block.text}</Text>\n              </View>\n            );\n          case \"quote\":\n            return (\n              <View key={key} style={[styles.quote, { borderLeftColor: theme.mutedColor }]}>\n                <Blocks blocks={block.children} theme={theme} />\n              </View>\n            );\n          case \"list\":\n            return (\n              <View key={key} style={styles.list}>\n                {block.items.map((item, itemIndex) => (\n                  <View key={`item-${itemIndex}`} style={styles.listItem}>\n                    <Text style={body}>{block.ordered ? `${block.start + itemIndex}.` : BULLET}</Text>\n                    <Text style={[body, styles.listItemText]}>{renderInline(item, theme)}</Text>\n                  </View>\n                ))}\n              </View>\n            );\n          case \"rule\":\n            return <View key={key} style={[styles.rule, { backgroundColor: theme.mutedColor }]} />;\n          default:\n            return null;\n        }\n      })}\n    </View>\n  );\n};\n\nexport const Markdown: FC<MarkdownProps> = ({ content, color, mutedColor, linkColor, fontSize = DEFAULT_FONT_SIZE, fontFamily }) => {\n  // The transcript re-renders on every store snapshot; parsing is keyed to the\n  // message text so a typing indicator tick does not re-tokenize the history.\n  const blocks = useMemo(() => splitBlocks(content), [content]);\n  const theme = useMemo<MarkdownTheme>(\n    () => ({ color, mutedColor, linkColor, fontSize, lineHeight: fontSize * LINE_HEIGHT_RATIO, codeFontSize: Math.round(fontSize * CODE_FONT_RATIO), fontFamily }),\n    [color, mutedColor, linkColor, fontSize, fontFamily],\n  );\n\n  return <Blocks blocks={blocks} theme={theme} />;\n};\n\nconst styles = StyleSheet.create({\n  stack: { gap: BLOCK_GAP },\n  strong: { fontWeight: \"600\" },\n  em: { fontStyle: \"italic\" },\n  /** prose renders inline code semibold, which is what separates it from prose text. */\n  code: { fontWeight: \"600\" },\n  link: { textDecorationLine: \"underline\" },\n  codeBlock: { borderWidth: StyleSheet.hairlineWidth, borderRadius: 4, paddingHorizontal: 8, paddingVertical: 6 },\n  quote: { borderLeftWidth: 4, paddingLeft: 12, paddingVertical: 4 },\n  list: { gap: LIST_ITEM_GAP },\n  listItem: { flexDirection: \"row\", gap: 6 },\n  // Shrink rather than grow: the bubble hugs its content, and `flex: 1` would\n  // collapse that intrinsic width to zero.\n  listItemText: { flexShrink: 1 },\n  rule: { height: StyleSheet.hairlineWidth, alignSelf: \"stretch\" },\n});\n","// Renderer for the composable Block Kit widget.\n// Contract: tools-framework-sdk/tools_framework_sdk/blocks/ — the bot sends a\n// FULLY-RESOLVED tree (bindings substituted, repeats expanded) over the\n// `ringg.blocks` text stream; this component only renders structure and\n// collects discrete intents. Unknown block types render nothing (forward\n// compat with a newer catalog). It mirrors the web renderer node for node —\n// same catalog, same wire payload, same test ids — so the two files can be\n// read side by side when the catalog grows.\n//\n// What the platform forces to differ, and nothing else:\n//   - there is no `color-mix()` and no cascade: tints are blended here, and\n//     every text node states its own colour, size and family\n//   - there is no native `<select>` and no popup layer: selects expand inline,\n//     in flow, pushing the rest of the tree down\n//   - there is no date/time picker without a new dependency: those inputs are\n//     typed, with the same themed affordance icon\n//   - `window.open` / `CustomEvent` become `Linking.openURL` / the host handler\n//   - a table cannot auto-size its columns: every column takes an equal share\n//\n// Embed rules kept from web:\n//   - `markdown: true` text renders through the shared Markdown renderer\n//   - https-only backstop on image URLs (§9 of the integration guide) — the\n//     placeholder/broken chrome shows instead, without fetching\n//   - unsupported schema_version renders a graceful fallback (§12)\n//   - respond actions disable the tree while the RPC is in flight, and echo\n//     the pressed button's label as a user bubble (label param on onAction)\n\nimport { Calendar, Check, ChevronDown, Clock, Image as ImageIcon, ImageOff } from \"lucide-react-native\";\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, type FC, type ReactElement, type ReactNode } from \"react\";\nimport { Animated, Image, Linking, ScrollView, StyleSheet, Text, TextInput, View, type KeyboardTypeOptions, type TextStyle, type ViewStyle } from \"react-native\";\nimport Svg, { Path } from \"react-native-svg\";\nimport type { ComponentTheme } from \"@ringg/core\";\n\nimport { SUPPORTED_BLOCKS_SCHEMA_VERSION, type BlockAction, type BlockNode, type BlockValue, type BlocksActionPayload, type BlocksConfig, type VisibleIf } from \"../../lib/block-types\";\nimport { GradientFill, solidColor } from \"../../lib/gradient\";\nimport { Markdown } from \"../../lib/markdown\";\nimport { ringgId } from \"../../lib/testing\";\nimport { mergeTheme, toNumber } from \"../../lib/theme-utils\";\nimport { resolveButtonRadius, resolveFontFamily, useWidgetTheme } from \"../../lib/widget-theme\";\nimport { Touchable } from \"../ui/pressable\";\n\n/** The palette every node in one blocks tree draws from. */\ntype BlocksTheme = Required<ComponentTheme>;\n\n/** RN spells the three catalog alignments the same way for items and self. */\ntype Align = \"flex-start\" | \"center\" | \"flex-end\";\n\n/** Catalog widths are percentages of the parent. */\ntype Percent = `${number}%`;\n\n// Widget state shared by all nodes of one blocks tree\ninterface BlocksState {\n  getValue: (name: string, fallback?: unknown) => BlockValue | undefined;\n  setValue: (name: string, value: BlockValue) => void;\n  errors: Record<string, string>;\n  disabled: boolean;\n  submitRespond: (action: BlockAction, formNames: string[] | null, label?: string) => void;\n  /** Sandbox hosts (dev panel / builder preview): receives open_url / dom_event instead of executing them. */\n  onSandboxAction?: (action: BlockAction) => void;\n}\n\ninterface BlocksStepProps {\n  config: BlocksConfig;\n  disabled?: boolean;\n  onAction: (payload: BlocksActionPayload) => void | Promise<void>;\n  onSandboxAction?: (action: BlockAction) => void;\n}\n\ninterface NodeProps {\n  node: BlockNode;\n  // Input names of the nearest ancestor `form` (null = no form ancestor).\n  formNames: string[] | null;\n  inCarousel: boolean;\n}\n\ninterface ImageBlockProps {\n  node: BlockNode;\n}\n\ninterface ExpanderBlockProps {\n  node: BlockNode;\n  /** Already-rendered body, so the expander never re-enters the renderer. */\n  children: ReactNode;\n}\n\ninterface ButtonBlockProps {\n  node: BlockNode;\n  formNames: string[] | null;\n}\n\ninterface InputBlockProps {\n  node: BlockNode;\n}\n\ninterface CheckSquareProps {\n  checked: boolean;\n  theme: BlocksTheme;\n}\n\ninterface PillToggleProps {\n  label: string;\n  selected: boolean;\n  disabled?: boolean;\n  fontSize: number;\n  theme: BlocksTheme;\n  onPress: () => void;\n}\n\ninterface SelectDropdownProps {\n  options: string[];\n  selected: string[];\n  placeholder: string;\n  disabled?: boolean;\n  /** Multi keeps the list open and shows check squares; single closes on pick. */\n  multiple: boolean;\n  fontSize: number;\n  inputStyle: ViewStyle;\n  theme: BlocksTheme;\n  onSelect: (option: string) => void;\n}\n\n/** Button surface for one `style` value — background may be a gradient. */\ninterface ButtonVisual {\n  background: string;\n  color: string;\n  borderColor: string;\n}\n\nconst ALLOWED_URL_SCHEMES = [\"https:\", \"mailto:\", \"tel:\"];\n\nconst ALIGN: Record<string, Align> = { start: \"flex-start\", center: \"center\", end: \"flex-end\" };\nconst JUSTIFY: Record<string, ViewStyle[\"justifyContent\"]> = { start: \"flex-start\", center: \"center\", end: \"flex-end\", between: \"space-between\" };\nconst TEXT_ALIGN: Record<string, TextStyle[\"textAlign\"]> = { start: \"left\", center: \"center\", end: \"right\" };\n\n// The keyboard is the only affordance an input_* type can ask for here; the\n// DOM's `type=` also brought validation and pickers, which RN has no equivalent\n// for (email format is checked on submit, same as web's own re-check).\nconst INPUT_KEYBOARD_TYPE: Record<string, KeyboardTypeOptions> = {\n  input_email: \"email-address\",\n  input_phone_number: \"phone-pad\",\n  input_number: \"numeric\",\n};\n\n// Filled-star colour for input_rating — conventional amber, independent of the\n// (possibly non-warm) brand primary so stars always read as a rating.\nconst RATING_COLOR = \"#F5A623\";\n\n// Cards in a carousel are a fixed pitch, which is also what makes snapping\n// possible — RN can only snap on a constant interval.\nconst CAROUSEL_CARD_WIDTH = 256;\nconst CAROUSEL_GAP = 12;\n\n/** Web caps an unsized picture at `max-h-28`; RN needs it as a real height. */\nconst IMAGE_DEFAULT_HEIGHT = 112;\n\n// Tailwind's animate-pulse: 2s, opacity 1 → .5 → 1.\nconst PULSE_HALF_CYCLE_MS = 1000;\nconst PULSE_MIN_OPACITY = 0.5;\n\n/** Two rows of text, matching the web textarea's `rows={2}`. */\nconst TEXTAREA_MIN_HEIGHT = 60;\n\nconst DIVIDER_THICKNESS = 1.5;\n\n/** Options and rows fill their own touch area — the default slop would overlap neighbours. */\nconst NO_HIT_SLOP = 0;\n\n// A block node only ever renders under the provider below. The inert default\n// keeps that fact out of the type system (and out of a non-null assertion): a\n// node rendered standalone reads nothing and writes nowhere.\nconst NO_BLOCKS_STATE: BlocksState = {\n  getValue: () => undefined,\n  setValue: () => {},\n  errors: {},\n  disabled: true,\n  submitRespond: () => {},\n};\n\nconst BlocksStateContext = createContext<BlocksState>(NO_BLOCKS_STATE);\n\nconst useBlocksState = (): BlocksState => useContext(BlocksStateContext);\n\n/**\n * Component palette for one blocks tree.\n *\n * Web reads this from a theme context that interactive components may override\n * per payload; blocks never carry a per-tree theme, so the widget theme is the\n * only input and `mergeTheme` supplies the component defaults for what a widget\n * theme has no opinion on (radius, padding, sizes). `fontFamily` is carried\n * over here even though web leaves it out: web inherits it through the cascade,\n * RN has to hand it to every text node.\n */\nconst useBlocksTheme = (): BlocksTheme => {\n  const widget = useWidgetTheme();\n  return useMemo(\n    () =>\n      mergeTheme({\n        primaryColor: widget.primaryColor,\n        primaryTextColor: widget.primaryTextColor,\n        backgroundColor: widget.backgroundColor,\n        surfaceColor: widget.surfaceColor,\n        textColor: widget.textColor,\n        mutedTextColor: widget.mutedTextColor,\n        borderColor: widget.borderColor,\n        errorColor: widget.errorColor,\n        successColor: widget.successColor,\n        buttonStyle: widget.buttonStyle,\n        fontFamily: widget.fontFamily,\n      }),\n    [widget],\n  );\n};\n\n// Names of all input nodes under a subtree (form submit scope).\nconst collectInputNames = (nodes: BlockNode[] | undefined): string[] => {\n  const names: string[] = [];\n  for (const node of nodes || []) {\n    if (node.type.startsWith(\"input_\") && node.name) names.push(node.name);\n    names.push(...collectInputNames(node.children));\n  }\n  return names;\n};\n\nconst findInputs = (nodes: BlockNode[] | undefined, scope: string[] | null): BlockNode[] => {\n  const inputs: BlockNode[] = [];\n  for (const node of nodes || []) {\n    if (node.type.startsWith(\"input_\") && node.name && (scope === null || scope.includes(node.name))) inputs.push(node);\n    inputs.push(...findInputs(node.children, scope));\n  }\n  return inputs;\n};\n\nconst evaluateVisibleIf = (condition: VisibleIf | undefined, getValue: BlocksState[\"getValue\"]): boolean => {\n  if (!condition) return true;\n  if (condition.all) return condition.all.every((leaf) => evaluateVisibleIf(leaf, getValue));\n  if (condition.any) return condition.any.some((leaf) => evaluateVisibleIf(leaf, getValue));\n  if (!condition.field) return true;\n  const actual = getValue(condition.field);\n  switch (condition.op || \"truthy\") {\n    case \"eq\":\n      return actual === condition.value;\n    case \"ne\":\n      return actual !== condition.value;\n    case \"in\":\n      return Array.isArray(condition.value) && condition.value.includes(actual);\n    case \"gt\":\n      return typeof actual === \"number\" && typeof condition.value === \"number\" && actual > condition.value;\n    case \"lt\":\n      return typeof actual === \"number\" && typeof condition.value === \"number\" && actual < condition.value;\n    case \"truthy\":\n    default:\n      return Array.isArray(actual) ? actual.length > 0 : !!actual;\n  }\n};\n\nconst percentWidth = (value: number): Percent => `${value}%`;\n\nconst fontSizeOf = (props: Record<string, unknown>, fallback: number): number => (typeof props.font_size === \"number\" ? props.font_size : fallback);\n\n// Catalog 1.6 sizing model — numeric props instead of a discrete sm/md/lg\n// scale: width is a % of the parent, height and font_size are dp. Layered on\n// top of each block's defaults, so an unset prop keeps the original look and a\n// set prop overrides it. `defaultFontPx` preserves the block's own text size\n// when the author hasn't set font_size; omit it for boxes that hand the size to\n// a child <Text> instead.\nconst sizeStyle = (props: Record<string, unknown>, defaultFontPx?: number): TextStyle => {\n  const fontSize = typeof props.font_size === \"number\" ? props.font_size : defaultFontPx;\n  // Built as one literal rather than mutated: RN's style types are readonly,\n  // and an undefined entry would punch a hole in whatever this is spread over.\n  return {\n    ...(typeof props.width === \"number\" ? { width: percentWidth(props.width) } : null),\n    ...(typeof props.height === \"number\" ? { height: props.height } : null),\n    ...(fontSize !== undefined ? { fontSize } : null),\n  };\n};\n\n// padding/gap are numeric dp (catalog 1.6) — resolve to the value, or the default.\nconst spacing = (value: unknown, fallback: number): number => (typeof value === \"number\" ? value : fallback);\n\nconst alignOf = (value: unknown): Align | undefined => (typeof value === \"string\" ? ALIGN[value] : undefined);\n\nconst justifyOf = (value: unknown): ViewStyle[\"justifyContent\"] => (typeof value === \"string\" ? JUSTIFY[value] : undefined);\n\nconst textAlignOf = (value: unknown): TextStyle[\"textAlign\"] => (typeof value === \"string\" ? TEXT_ALIGN[value] : undefined);\n\n/** `#rgb` / `#rrggbb(aa)` / `rgb()` / `rgba()` → channels. Anything else is unknown. */\nconst parseColor = (color: string): [number, number, number] | undefined => {\n  const value = color.trim();\n  const hex = /^#([0-9a-f]+)$/i.exec(value)?.[1];\n  if (hex) {\n    // Shorthand doubles each digit (#abc → #aabbcc); an alpha byte is dropped.\n    const six = hex.length === 3 || hex.length === 4 ? hex.slice(0, 3).replace(/./g, (digit) => digit + digit) : hex.length === 6 || hex.length === 8 ? hex.slice(0, 6) : \"\";\n    if (!six) return undefined;\n    const packed = Number.parseInt(six, 16);\n    return Number.isFinite(packed) ? [(packed >> 16) & 0xff, (packed >> 8) & 0xff, packed & 0xff] : undefined;\n  }\n  const channels = /^rgba?\\(([^)]+)\\)$/i.exec(value)?.[1];\n  if (!channels) return undefined;\n  const parts = channels.split(/[\\s,/]+/).filter(Boolean).slice(0, 3).map(Number);\n  if (parts.length < 3 || parts.some((part) => !Number.isFinite(part))) return undefined;\n  return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];\n};\n\n/**\n * `color-mix(in srgb, overlay <amount>, base)` for the four tinted surfaces in\n * this file. RN has no colour arithmetic, and layering a translucent view\n * instead would tint the block's children too. A colour we cannot read (a\n * gradient, a named CSS colour) returns `base` — the untinted look, never a\n * wrong one.\n */\nconst tint = (base: string, overlay: string, amount: number): string => {\n  const from = parseColor(base);\n  const to = parseColor(overlay);\n  if (!from || !to) return base;\n  const blend = (channel: 0 | 1 | 2): number => Math.round(from[channel] * (1 - amount) + to[channel] * amount);\n  return `rgb(${blend(0)}, ${blend(1)}, ${blend(2)})`;\n};\n\nconst headerFontSize = (level: number): number => {\n  switch (level) {\n    case 1:\n      return 16;\n    case 2:\n      return 14;\n    default:\n      return 12;\n  }\n};\n\nconst badgeToneColor = (tone: string, theme: BlocksTheme): string => {\n  switch (tone) {\n    case \"success\":\n      return theme.successColor;\n    case \"danger\":\n    case \"warning\":\n      return theme.errorColor;\n    case \"info\":\n      return solidColor(theme.primaryColor);\n    default:\n      return theme.mutedTextColor;\n  }\n};\n\n// Default/info picks up the brand primary so a callout doesn't read as a flat\n// grey box; success/warning/error use their semantic colours.\nconst calloutAccent = (tone: string, theme: BlocksTheme): string => {\n  switch (tone) {\n    case \"success\":\n      return solidColor(theme.successColor);\n    case \"warning\":\n    case \"error\":\n      return solidColor(theme.errorColor);\n    default:\n      return solidColor(theme.primaryColor);\n  }\n};\n\nconst buttonVisual = (style: string, theme: BlocksTheme): ButtonVisual => {\n  switch (style) {\n    case \"destructive\":\n      return { background: theme.errorColor, color: theme.primaryTextColor, borderColor: \"transparent\" };\n    case \"secondary\":\n      return { background: theme.surfaceColor, color: theme.textColor, borderColor: theme.borderColor };\n    case \"primary\":\n      return { background: theme.primaryColor, color: theme.primaryTextColor, borderColor: \"transparent\" };\n    default:\n      return { background: \"transparent\", color: theme.textColor, borderColor: theme.borderColor };\n  }\n};\n\nconst openExternalUrl = (url: string): void => {\n  // Best effort: an unsupported scheme or a missing handler must not crash the\n  // widget, and there is nothing useful to tell the user about it.\n  void Linking.openURL(url).catch(() => {});\n};\n\n// Custom check square: brand-primary fill + tick when checked, themed border\n// when not.\nconst CheckSquare: FC<CheckSquareProps> = ({ checked, theme }) => (\n  <View\n    style={[\n      styles.checkSquare,\n      checked\n        ? { backgroundColor: solidColor(theme.primaryColor), borderColor: solidColor(theme.primaryColor) }\n        : { backgroundColor: theme.backgroundColor, borderColor: solidColor(theme.borderColor) },\n    ]}\n  >\n    {checked && (\n      <Svg width={11} height={11} viewBox=\"0 0 12 12\" fill=\"none\">\n        <Path d=\"M2.5 6.2 5 8.7l4.5-5.4\" stroke={theme.primaryTextColor} strokeWidth={1.8} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      </Svg>\n    )}\n  </View>\n);\n\n// Chip used by the \"pills\" variant of single/multi select: selected = filled\n// with the brand primary, unselected = outline.\nconst PillToggle: FC<PillToggleProps> = ({ label, selected, disabled, fontSize, theme, onPress }) => (\n  <Touchable\n    disabled={disabled}\n    onPress={onPress}\n    accessibilityLabel={label}\n    hitSlop={NO_HIT_SLOP}\n    style={[\n      styles.pill,\n      selected\n        ? { backgroundColor: solidColor(theme.primaryColor), borderColor: solidColor(theme.primaryColor) }\n        : { backgroundColor: \"transparent\", borderColor: solidColor(theme.borderColor) },\n    ]}\n  >\n    <Text style={[styles.pillLabel, { color: selected ? theme.primaryTextColor : theme.textColor, fontSize, fontFamily: resolveFontFamily(theme.fontFamily) }]}>{label}</Text>\n  </Touchable>\n);\n\n// One dropdown serves both selects: RN has no native picker, and the web\n// multi-select menu was already modelled on the single-select trigger, so the\n// anatomy is shared and only the picking rule differs.\nconst SelectDropdown: FC<SelectDropdownProps> = ({ options, selected, placeholder, disabled, multiple, fontSize, inputStyle, theme, onSelect }) => {\n  const [open, setOpen] = useState(false);\n  const font = resolveFontFamily(theme.fontFamily);\n  const border = solidColor(theme.borderColor);\n\n  return (\n    <View>\n      <Touchable disabled={disabled} onPress={() => setOpen((prev) => !prev)} accessibilityLabel={selected.length ? selected.join(\", \") : placeholder} hitSlop={NO_HIT_SLOP} style={[styles.selectTrigger, inputStyle]}>\n        <Text numberOfLines={1} style={[styles.selectValue, { color: selected.length ? theme.textColor : theme.mutedTextColor, fontSize, fontFamily: font }]}>\n          {selected.length ? selected.join(\", \") : placeholder}\n        </Text>\n        <ChevronDown size={14} color={theme.mutedTextColor} style={{ transform: [{ rotate: open ? \"180deg\" : \"0deg\" }] }} />\n      </Touchable>\n      {open && (\n        // Web floats this menu over the page. RN has no overlay layer inside the\n        // transcript and a nested vertical scroller would fight the transcript's\n        // own, so the list expands in flow and pushes the tree below it down.\n        <View style={[styles.selectMenu, { backgroundColor: theme.backgroundColor, borderColor: border, borderRadius: toNumber(theme.borderRadius, 8) }]}>\n          {options.map((option, index) => {\n            const isSelected = selected.includes(option);\n            return (\n              <Touchable\n                key={`${option}-${index}`}\n                disabled={disabled}\n                onPress={() => {\n                  onSelect(option);\n                  if (!multiple) setOpen(false);\n                }}\n                accessibilityLabel={option}\n                hitSlop={NO_HIT_SLOP}\n                style={styles.selectOption}\n              >\n                {multiple && <CheckSquare checked={isSelected} theme={theme} />}\n                <Text numberOfLines={1} style={[styles.selectOptionLabel, { color: theme.textColor, fontSize: 14, fontFamily: font }]}>\n                  {option}\n                </Text>\n                {!multiple && isSelected && <Check size={14} color={solidColor(theme.primaryColor)} />}\n              </Touchable>\n            );\n          })}\n        </View>\n      )}\n    </View>\n  );\n};\n\n// A bare picture hid itself on error and rendered nothing without a URL, which\n// read as \"images don't work\". Instead: a labelled placeholder when no URL is\n// set (or a ${{binding}} arrived unresolved), a pulse while bytes load, and a\n// visible broken state for bad URLs. Non-https URLs take the broken state\n// without ever being fetched (§9 of the integration guide).\nconst ImageBlock: FC<ImageBlockProps> = ({ node }) => {\n  const theme = useBlocksTheme();\n  const props = node.props || {};\n  const url = typeof props.url === \"string\" ? props.url : \"\";\n  const isBinding = url.includes(\"${{\");\n  const isBlockedScheme = !!url && !isBinding && !url.trim().toLowerCase().startsWith(\"https:\");\n  const [status, setStatus] = useState<\"loading\" | \"loaded\" | \"error\">(\"loading\");\n  const pulse = useRef(new Animated.Value(1)).current;\n\n  useEffect(() => {\n    setStatus(\"loading\");\n  }, [url]);\n\n  useEffect(() => {\n    if (status !== \"loading\") return;\n    const loop = Animated.loop(\n      Animated.sequence([\n        Animated.timing(pulse, { toValue: PULSE_MIN_OPACITY, duration: PULSE_HALF_CYCLE_MS, useNativeDriver: true }),\n        Animated.timing(pulse, { toValue: 1, duration: PULSE_HALF_CYCLE_MS, useNativeDriver: true }),\n      ]),\n    );\n    loop.start();\n    return () => loop.stop();\n  }, [pulse, status]);\n\n  const radius = toNumber(theme.borderRadius, 8);\n  const alignSelf = alignOf(props.align) ?? \"flex-start\";\n\n  if (!url || isBinding || isBlockedScheme || status === \"error\") {\n    const label = !url ? \"Add an image URL\" : isBinding ? url : \"Couldn't load image\";\n    const broken = isBlockedScheme || (status === \"error\" && !isBinding);\n    return (\n      <View\n        testID={ringgId(\"block-image\")}\n        style={[\n          styles.imagePlaceholder,\n          { alignSelf, borderColor: solidColor(theme.borderColor), borderRadius: radius, backgroundColor: tint(theme.backgroundColor, theme.surfaceColor, 0.5) },\n          sizeStyle(props),\n        ]}\n      >\n        {broken ? <ImageOff size={20} color={theme.mutedTextColor} /> : <ImageIcon size={20} color={theme.mutedTextColor} />}\n        <Text numberOfLines={1} style={[styles.placeholderText, { color: theme.mutedTextColor, fontFamily: resolveFontFamily(theme.fontFamily) }]}>\n          {label}\n        </Text>\n      </View>\n    );\n  }\n\n  // An RN picture has no intrinsic size to grow into, so the box it is\n  // contained in is always explicit: the author's numbers, or a full-width box\n  // capped at web's `max-h-28`.\n  const box: ViewStyle = {\n    width: typeof props.width === \"number\" ? percentWidth(props.width) : \"100%\",\n    height: typeof props.height === \"number\" ? props.height : IMAGE_DEFAULT_HEIGHT,\n  };\n\n  return (\n    <View style={[styles.imageBox, box, { alignSelf, borderRadius: radius }]}>\n      <Image\n        key={url}\n        testID={ringgId(\"block-image\")}\n        source={{ uri: url }}\n        accessibilityLabel={String(props.alt ?? \"\")}\n        resizeMode=\"contain\"\n        onLoad={() => setStatus(\"loaded\")}\n        onError={() => setStatus(\"error\")}\n        style={styles.imageFill}\n      />\n      {status === \"loading\" && <Animated.View testID={ringgId(\"block-image-loading\")} style={[StyleSheet.absoluteFill, { backgroundColor: theme.surfaceColor, opacity: pulse }]} />}\n    </View>\n  );\n};\n\n// Actions: respond | open_url | dom_event\nconst ButtonBlock: FC<ButtonBlockProps> = ({ node, formNames }) => {\n  const theme = useBlocksTheme();\n  const state = useBlocksState();\n  const props = node.props || {};\n  const label = String(props.label ?? \"\");\n  const press = node.on?.press;\n\n  const handlePress = (): void => {\n    if (!press || state.disabled) return;\n    switch (press.action) {\n      case \"respond\":\n        state.submitRespond(press, formNames, label);\n        return;\n      case \"open_url\": {\n        if (state.onSandboxAction) {\n          state.onSandboxAction(press);\n          return;\n        }\n        if (!press.url) return;\n        const url = String(press.url);\n        // `target` has no meaning here: RN always leaves the app for the\n        // system browser, which is what `_blank` asked for anyway.\n        if (ALLOWED_URL_SCHEMES.some((scheme) => url.trim().toLowerCase().startsWith(scheme))) openExternalUrl(url);\n        return;\n      }\n      case \"dom_event\":\n        // There is no ambient event bus outside the browser, so the host\n        // handler is the only listener; without one the action is inert.\n        state.onSandboxAction?.(press);\n        return;\n      default:\n        // Unknown action strings are inert by contract (reserved for future use).\n        return;\n    }\n  };\n\n  const visual = buttonVisual(typeof props.style === \"string\" && props.style ? props.style : \"primary\", theme);\n\n  return (\n    <Touchable\n      testID={ringgId(\"block-button\")}\n      accessibilityLabel={label}\n      onPress={handlePress}\n      disabled={state.disabled}\n      hitSlop={NO_HIT_SLOP}\n      // Unset width fills the line (what the builder's W control shows), so\n      // side-by-side buttons in a row each need an explicit width%.\n      style={[{ alignSelf: alignOf(props.align) }, sizeStyle(props)]}\n    >\n      <GradientFill color={visual.background} style={[styles.button, { borderColor: visual.borderColor, borderRadius: resolveButtonRadius(theme.buttonStyle) }]}>\n        <Text style={[styles.buttonLabel, { color: visual.color, fontSize: fontSizeOf(props, 14), fontFamily: resolveFontFamily(theme.fontFamily) }]}>{label}</Text>\n      </GradientFill>\n    </Touchable>\n  );\n};\n\n// input_* catalog types → same visuals as form-step\nconst InputBlock: FC<InputBlockProps> = ({ node }) => {\n  const theme = useBlocksTheme();\n  const state = useBlocksState();\n  const props = node.props || {};\n  const name = node.name ?? \"\";\n  const error = state.errors[name];\n  const font = resolveFontFamily(theme.fontFamily);\n\n  // Inputs are keyed by name in the values bag; a name-less input (a config\n  // error) would read and write an \"\" state key. Show a hint instead of\n  // corrupting shared state.\n  if (!name) {\n    return (\n      <View style={[styles.nameless, { borderColor: solidColor(theme.borderColor) }]}>\n        <Text style={[styles.namelessText, { color: theme.mutedTextColor, fontFamily: font }]}>Input needs a name</Text>\n      </View>\n    );\n  }\n\n  const inputStyle: ViewStyle = {\n    backgroundColor: theme.backgroundColor,\n    borderColor: error ? solidColor(theme.errorColor) : solidColor(theme.borderColor),\n    borderRadius: toNumber(theme.borderRadius, 8),\n  };\n  // Rating shows just stars unless a label is explicitly set; other inputs fall\n  // back to the field name so they never render label-less.\n  const label = String(props.label ?? (node.type === \"input_rating\" ? \"\" : name));\n  // What web inherits from the wrapper's font size; text-sm controls state 14.\n  const bodyFontSize = fontSizeOf(props, 14);\n  const placeholder = String(props.placeholder ?? `Enter ${label.toLowerCase()}`);\n  const selectPlaceholder = String(props.placeholder ?? `Select ${label.toLowerCase()}`);\n  const options = (props.options as string[] | undefined) || [];\n\n  const control = (): ReactElement => {\n    switch (node.type) {\n      case \"input_checkbox\": {\n        const checked = (state.getValue(name) as boolean) || false;\n        return (\n          <Touchable disabled={state.disabled} onPress={() => state.setValue(name, !checked)} accessibilityLabel={label} hitSlop={NO_HIT_SLOP} style={styles.checkboxRow}>\n            <CheckSquare checked={checked} theme={theme} />\n            <Text style={{ color: theme.textColor, fontSize: 14, fontFamily: font }}>{label}</Text>\n          </Touchable>\n        );\n      }\n      case \"input_rating\": {\n        const max = Math.min(Math.max(Math.round(Number(props.max) || 5), 3), 10);\n        const current = Math.round(Number(state.getValue(name)) || 0);\n        // font_size drives the star size (default 24 = the old md/text-2xl).\n        const starPx = fontSizeOf(props, 24);\n        return (\n          <View style={[styles.ratingRow, { justifyContent: justifyOf(props.align) }]} accessibilityRole=\"radiogroup\" accessibilityLabel={label}>\n            {Array.from({ length: max }, (_unused, index) => {\n              const filled = index < current;\n              return (\n                <Touchable\n                  key={index}\n                  disabled={state.disabled}\n                  onPress={() => state.setValue(name, index + 1)}\n                  accessibilityLabel={`${index + 1} star${index ? \"s\" : \"\"}`}\n                  hitSlop={NO_HIT_SLOP}\n                >\n                  <Text style={{ color: filled ? RATING_COLOR : solidColor(theme.borderColor), fontSize: starPx, fontFamily: font }}>{filled ? \"★\" : \"☆\"}</Text>\n                </Touchable>\n              );\n            })}\n          </View>\n        );\n      }\n      case \"input_single_select\": {\n        const value = (state.getValue(name) as string) || \"\";\n        if (props.variant === \"pills\") {\n          return (\n            <View style={[styles.pillRow, { justifyContent: justifyOf(props.align) }]}>\n              {options.map((option, index) => (\n                <PillToggle key={`${option}-${index}`} label={option} selected={value === option} disabled={state.disabled} fontSize={bodyFontSize} theme={theme} onPress={() => state.setValue(name, option)} />\n              ))}\n            </View>\n          );\n        }\n        return (\n          <SelectDropdown\n            options={options}\n            selected={value ? [value] : []}\n            placeholder={selectPlaceholder}\n            disabled={state.disabled}\n            multiple={false}\n            fontSize={bodyFontSize}\n            inputStyle={inputStyle}\n            theme={theme}\n            onSelect={(option) => state.setValue(name, option)}\n          />\n        );\n      }\n      case \"input_multi_select\": {\n        const current = (state.getValue(name) as string[]) || [];\n        const toggle = (option: string): void => state.setValue(name, current.includes(option) ? current.filter((entry) => entry !== option) : [...current, option]);\n        if (props.variant === \"pills\") {\n          return (\n            <View style={[styles.pillRow, { justifyContent: justifyOf(props.align) }]}>\n              {options.map((option, index) => (\n                <PillToggle key={`${option}-${index}`} label={option} selected={current.includes(option)} disabled={state.disabled} fontSize={bodyFontSize} theme={theme} onPress={() => toggle(option)} />\n              ))}\n            </View>\n          );\n        }\n        return <SelectDropdown options={options} selected={current} placeholder={selectPlaceholder} disabled={state.disabled} multiple fontSize={14} inputStyle={inputStyle} theme={theme} onSelect={toggle} />;\n      }\n      case \"input_textarea\":\n        return (\n          <TextInput\n            multiline\n            placeholder={placeholder}\n            placeholderTextColor={theme.mutedTextColor}\n            accessibilityLabel={label}\n            value={String(state.getValue(name) ?? \"\")}\n            onChangeText={(text) => state.setValue(name, text)}\n            editable={!state.disabled}\n            style={[\n              styles.field,\n              styles.textarea,\n              inputStyle,\n              { color: theme.textColor, fontSize: bodyFontSize, fontFamily: font },\n              // height sizes the control itself, not the label+error wrapper.\n              typeof props.height === \"number\" ? { height: props.height } : null,\n            ]}\n          />\n        );\n      default: {\n        const isDateOrTime = node.type === \"input_date\" || node.type === \"input_time\";\n        const field = (\n          <TextInput\n            placeholder={placeholder}\n            placeholderTextColor={theme.mutedTextColor}\n            accessibilityLabel={label}\n            value={String(state.getValue(name) ?? \"\")}\n            keyboardType={INPUT_KEYBOARD_TYPE[node.type] ?? \"default\"}\n            autoCapitalize={node.type === \"input_email\" ? \"none\" : \"sentences\"}\n            autoCorrect={node.type !== \"input_email\"}\n            onChangeText={(text) => {\n              if (node.type !== \"input_number\") {\n                state.setValue(name, text);\n                return;\n              }\n              // The wire value stays numeric; text that doesn't parse collapses\n              // to \"\", exactly what a DOM number input reports for it.\n              const parsed = Number(text);\n              state.setValue(name, text === \"\" || !Number.isFinite(parsed) ? \"\" : parsed);\n            }}\n            editable={!state.disabled}\n            style={[styles.field, isDateOrTime && styles.fieldWithIcon, inputStyle, { color: theme.textColor, fontSize: 14, fontFamily: font }]}\n          />\n        );\n        if (!isDateOrTime) return field;\n        // No calendar/clock picker without a new dependency, so the date and\n        // time fields are typed. The icon still marks what the field wants.\n        const PickerIcon = node.type === \"input_date\" ? Calendar : Clock;\n        return (\n          <View>\n            {field}\n            <View pointerEvents=\"none\" style={styles.fieldIcon}>\n              <PickerIcon size={16} color={theme.mutedTextColor} />\n            </View>\n          </View>\n        );\n      }\n    }\n  };\n\n  return (\n    <View testID={ringgId(`block-${node.type}`)} style={sizeStyle({ ...props, height: undefined })}>\n      {node.type !== \"input_checkbox\" && label.trim() !== \"\" && (\n        <View style={styles.labelRow}>\n          <Text style={[styles.label, { color: theme.mutedTextColor, fontFamily: font }]}>{label}</Text>\n          {!!props.required && <Text style={[styles.label, { color: theme.errorColor, fontFamily: font }]}>*</Text>}\n        </View>\n      )}\n      {control()}\n      {!!error && <Text style={[styles.error, { color: theme.errorColor, fontFamily: font }]}>{error}</Text>}\n    </View>\n  );\n};\n\n// `<details>` has no RN counterpart, so the open/closed flag lives here. A\n// collapsed body is unmounted rather than hidden: RN lays out `display: none`\n// subtrees anyway, and a hidden ScrollView or image would still do work.\nconst ExpanderBlock: FC<ExpanderBlockProps> = ({ node, children }) => {\n  const theme = useBlocksTheme();\n  const props = node.props || {};\n  const [open, setOpen] = useState(!!props.open);\n  const font = resolveFontFamily(theme.fontFamily);\n  const title = String(props.title ?? \"\");\n\n  return (\n    <View testID={ringgId(`block-${node.type}`)} style={[styles.expander, { borderColor: solidColor(theme.borderColor), borderRadius: toNumber(theme.borderRadius, 8) }, sizeStyle(props)]}>\n      <Touchable onPress={() => setOpen((prev) => !prev)} accessibilityLabel={title} hitSlop={NO_HIT_SLOP} style={styles.expanderSummary}>\n        <Text style={[styles.expanderTitle, { color: theme.textColor, fontSize: fontSizeOf(props, 14), fontFamily: font }]}>{title}</Text>\n        <ChevronDown size={14} color={theme.mutedTextColor} style={{ transform: [{ rotate: open ? \"180deg\" : \"0deg\" }] }} />\n      </Touchable>\n      {open && <View style={styles.expanderBody}>{children}</View>}\n    </View>\n  );\n};\n\nconst BlockRenderer: FC<NodeProps> = ({ node, formNames, inCarousel }) => {\n  const theme = useBlocksTheme();\n  const state = useBlocksState();\n  const props = node.props || {};\n\n  if (!evaluateVisibleIf(node.visible_if, state.getValue)) return null;\n\n  const children = (scope: string[] | null, carousel = false): ReactElement[] =>\n    (node.children || []).map((child, index) => <BlockRenderer key={`${child.id ?? \"b\"}-${index}`} node={child} formNames={scope} inCarousel={carousel} />);\n\n  // RN carries one node identifier, so `data-block-id` has no counterpart —\n  // `testID` keeps the name integrators already select on.\n  const testID = ringgId(`block-${node.type}`);\n  const font = resolveFontFamily(theme.fontFamily);\n  const border = solidColor(theme.borderColor);\n  const radius = toNumber(theme.borderRadius, 8);\n\n  switch (node.type) {\n    case \"box\":\n      return (\n        <View testID={testID} style={[styles.column, { alignItems: alignOf(props.align), gap: spacing(props.gap, 8), padding: spacing(props.padding, 0) }, sizeStyle(props)]}>\n          {children(formNames)}\n        </View>\n      );\n    case \"column\":\n      return (\n        <View testID={testID} style={[styles.column, { alignItems: alignOf(props.align), gap: spacing(props.gap, 12) }, sizeStyle(props)]}>\n          {children(formNames)}\n        </View>\n      );\n    case \"row\":\n      return (\n        <View\n          testID={testID}\n          style={[\n            styles.row,\n            { alignItems: alignOf(props.align) ?? \"center\", justifyContent: justifyOf(props.justify), flexWrap: props.wrap === false ? \"nowrap\" : \"wrap\", gap: spacing(props.gap, 8) },\n            sizeStyle(props),\n          ]}\n        >\n          {children(formNames)}\n        </View>\n      );\n    case \"form\":\n      return (\n        <View testID={testID} style={[styles.form, sizeStyle(props)]}>\n          {children(collectInputNames(node.children))}\n        </View>\n      );\n    case \"card\": {\n      // Trailing buttons pin to the card bottom — in a carousel the cards\n      // stretch to the tallest sibling, so CTAs align across cards regardless\n      // of how much content sits above them. Outside a carousel the card hugs\n      // its content and the wrapper changes nothing.\n      const kids = node.children || [];\n      let bodyEnd = kids.length;\n      while (bodyEnd > 0 && kids[bodyEnd - 1]?.type === \"button\") bodyEnd -= 1;\n      const renderKids = (list: BlockNode[], offset: number): ReactElement[] =>\n        list.map((child, index) => <BlockRenderer key={`${child.id ?? \"b\"}-${offset + index}`} node={child} formNames={formNames} inCarousel={false} />);\n      return (\n        <View\n          testID={testID}\n          style={[\n            styles.card,\n            { alignItems: alignOf(props.align), backgroundColor: theme.backgroundColor, borderColor: border, borderRadius: radius, padding: spacing(props.padding, 12) },\n            inCarousel && styles.carouselCard,\n            sizeStyle(props),\n          ]}\n        >\n          {renderKids(kids.slice(0, bodyEnd), 0)}\n          {bodyEnd < kids.length && <View style={styles.cardFooter}>{renderKids(kids.slice(bodyEnd), bodyEnd)}</View>}\n        </View>\n      );\n    }\n    case \"carousel\":\n      return (\n        // alignItems stretch (explicit): every card matches the tallest one.\n        // Snapping runs on the fixed card pitch — the only interval RN can snap\n        // to, and the only child width the catalog pins down.\n        <ScrollView\n          testID={testID}\n          horizontal\n          showsHorizontalScrollIndicator={false}\n          snapToInterval={CAROUSEL_CARD_WIDTH + CAROUSEL_GAP}\n          snapToAlignment=\"start\"\n          decelerationRate=\"fast\"\n          style={[styles.carousel, sizeStyle(props)]}\n          contentContainerStyle={styles.carouselContent}\n        >\n          {children(formNames, true)}\n        </ScrollView>\n      );\n    case \"header\":\n      return (\n        <Text testID={testID} style={[styles.header, { color: theme.textColor, fontFamily: font, textAlign: textAlignOf(props.align) }, sizeStyle(props, headerFontSize(Number(props.level) || 1))]}>\n          {String(props.text ?? \"\")}\n        </Text>\n      );\n    case \"text\": {\n      if (props.markdown === true) {\n        return (\n          // Markdown renders a stack of blocks, so `align` places those blocks\n          // in the column; it cannot re-align the wrapped lines inside them.\n          <View testID={testID} style={[{ alignItems: alignOf(props.align) }, sizeStyle(props)]}>\n            <Markdown\n              content={String(props.text ?? \"\")}\n              color={theme.textColor}\n              mutedColor={theme.mutedTextColor}\n              linkColor={solidColor(theme.primaryColor)}\n              fontSize={fontSizeOf(props, 14)}\n              fontFamily={font}\n            />\n          </View>\n        );\n      }\n      return (\n        <Text testID={testID} style={[{ color: theme.textColor, fontFamily: font, textAlign: textAlignOf(props.align) }, sizeStyle(props, 14)]}>\n          {String(props.text ?? \"\")}\n        </Text>\n      );\n    }\n    case \"image\":\n      return <ImageBlock node={node} />;\n    case \"divider\":\n      // width % shortens the rule; height sets its thickness.\n      return (\n        <View\n          testID={testID}\n          style={[\n            styles.divider,\n            {\n              alignSelf: alignOf(props.align),\n              backgroundColor: tint(border, \"#000000\", 0.08),\n              height: typeof props.height === \"number\" ? props.height : DIVIDER_THICKNESS,\n              width: typeof props.width === \"number\" ? percentWidth(props.width) : \"100%\",\n            },\n          ]}\n        />\n      );\n    case \"facts\": {\n      const items = (props.items as Array<{ label: string; value: string }> | undefined) || [];\n      const fontSize = fontSizeOf(props, 14);\n      return (\n        <View testID={testID} style={[styles.facts, sizeStyle(props)]}>\n          {items.map((item, index) => (\n            <View key={index} style={styles.factsRow}>\n              <Text style={{ color: theme.mutedTextColor, fontSize, fontFamily: font }}>{item.label}</Text>\n              <Text style={[styles.factsValue, { color: theme.textColor, fontSize, fontFamily: font }]}>{item.value}</Text>\n            </View>\n          ))}\n        </View>\n      );\n    }\n    case \"badge\": {\n      const toneColor = badgeToneColor(String(props.tone ?? \"neutral\"), theme);\n      return (\n        <View testID={testID} style={[styles.badge, { alignSelf: alignOf(props.align) ?? \"flex-start\", borderColor: toneColor }, sizeStyle(props)]}>\n          <Text numberOfLines={1} style={[styles.badgeText, { color: toneColor, fontSize: fontSizeOf(props, 12), fontFamily: font }]}>\n            {String(props.text ?? \"\")}\n          </Text>\n        </View>\n      );\n    }\n    case \"table\": {\n      const columns = (props.columns as string[] | undefined) || [];\n      // rows must be an array of arrays. Guard against an unresolved ${{binding}}\n      // string AND against array-of-objects (wrong shape) — filter to array rows\n      // so neither reaches the inner map and crashes the widget.\n      const rows = (Array.isArray(props.rows) ? (props.rows as unknown[]) : []).filter(Array.isArray) as Array<Array<string | number | boolean>>;\n      const cellFontSize = fontSizeOf(props, 14);\n      const cellBorder = { borderBottomWidth: 1, borderColor: border };\n      return (\n        // Card chrome (surface, border, theme radius) so the table reads like\n        // the other block widgets instead of bare rows floating in the chat.\n        // Columns share the width evenly and cells wrap: RN has no auto table\n        // layout, and equal shares are the only split that keeps every row's\n        // cells aligned without measuring text.\n        <View testID={testID} style={[styles.table, { backgroundColor: tint(theme.backgroundColor, theme.surfaceColor, 0.5), borderColor: border, borderRadius: radius }, sizeStyle(props)]}>\n          <View style={styles.row}>\n            {columns.map((column, index) => (\n              <View key={index} style={[styles.tableCell, cellBorder]}>\n                <Text numberOfLines={1} style={[styles.tableHeaderText, { color: theme.mutedTextColor, fontFamily: font }]}>\n                  {column}\n                </Text>\n              </View>\n            ))}\n          </View>\n          {rows.map((row, rowIndex) => (\n            <View key={rowIndex} style={styles.row}>\n              {row.map((cell, cellIndex) => (\n                // Last row keeps the card's own edge — no trailing border line.\n                <View key={cellIndex} style={[styles.tableCell, rowIndex < rows.length - 1 && cellBorder]}>\n                  <Text style={{ color: theme.textColor, fontSize: cellFontSize, fontFamily: font }}>{String(cell)}</Text>\n                </View>\n              ))}\n            </View>\n          ))}\n        </View>\n      );\n    }\n    case \"steps\": {\n      const items = (props.items as string[] | undefined) || [];\n      const current = Math.max(1, Math.min(Number(props.current) || 1, items.length));\n      const fontSize = fontSizeOf(props, 15);\n      return (\n        // align moves the whole tracker as a unit so rows stay internally\n        // left-aligned and the dots keep a straight vertical line. compact\n        // (default): natural gap. stretch: spread steps to fill the container\n        // height (pairs with the height prop).\n        <View\n          testID={testID}\n          style={[styles.column, { alignSelf: alignOf(props.align) }, props.layout === \"stretch\" ? styles.stepsStretch : styles.stepsCompact, sizeStyle(props)]}\n        >\n          {items.map((label, index) => {\n            const stepNo = index + 1;\n            const done = stepNo < current;\n            const active = stepNo === current;\n            const dotColor = done || active ? solidColor(theme.primaryColor) : border;\n            return (\n              <View key={index} style={styles.stepRow}>\n                <View style={[styles.stepDot, { backgroundColor: done || active ? dotColor : \"transparent\", borderColor: dotColor }]}>\n                  <Text style={[styles.stepIndex, { color: done || active ? theme.primaryTextColor : theme.mutedTextColor, fontFamily: font }]}>{done ? \"✓\" : String(stepNo)}</Text>\n                </View>\n                <Text style={[styles.stepLabel, { color: active ? theme.textColor : theme.mutedTextColor, fontWeight: active ? \"600\" : \"400\", fontSize, fontFamily: font }]}>{label}</Text>\n              </View>\n            );\n          })}\n        </View>\n      );\n    }\n    case \"callout\": {\n      const accent = calloutAccent(String(props.tone ?? \"info\"), theme);\n      const fontSize = fontSizeOf(props, 14);\n      const textAlign = textAlignOf(props.align);\n      return (\n        // Soft brand-tinted card; the tint + accent title carry the tone.\n        <View testID={testID} style={[styles.callout, { backgroundColor: tint(theme.backgroundColor, accent, 0.07), borderRadius: radius }, sizeStyle(props)]}>\n          {!!props.title && <Text style={[styles.calloutTitle, { color: accent, fontFamily: font, textAlign }]}>{String(props.title)}</Text>}\n          <Text style={{ color: theme.textColor, fontSize, lineHeight: fontSize * 1.625, fontFamily: font, textAlign }}>{String(props.text ?? \"\")}</Text>\n        </View>\n      );\n    }\n    case \"expander\":\n      return <ExpanderBlock node={node}>{children(formNames)}</ExpanderBlock>;\n    case \"button\":\n      return <ButtonBlock node={node} formNames={formNames} />;\n    default:\n      if (node.type.startsWith(\"input_\")) return <InputBlock node={node} />;\n      // Unknown type: render children if any (container-ish), else nothing.\n      return node.children?.length ? <>{children(formNames)}</> : null;\n  }\n};\n\nconst BlocksStep: FC<BlocksStepProps> = ({ config, disabled, onAction, onSandboxAction }) => {\n  const theme = useBlocksTheme();\n  const [values, setValues] = useState<Record<string, BlockValue>>({});\n  const [errors, setErrors] = useState<Record<string, string>>({});\n  const [submitting, setSubmitting] = useState(false);\n\n  // Newer envelope than we understand — degrade instead of guessing (§12)\n  if ((config.schema_version ?? 1) > SUPPORTED_BLOCKS_SCHEMA_VERSION) {\n    return (\n      <Text testID={ringgId(\"blocks-unsupported\")} style={[styles.unsupported, { color: theme.mutedTextColor, fontFamily: resolveFontFamily(theme.fontFamily) }]}>\n        This content needs a newer version of the widget.\n      </Text>\n    );\n  }\n\n  const defaultsOf = (name: string): unknown => findInputs(config.blocks, [name])[0]?.props?.default;\n\n  const getValue: BlocksState[\"getValue\"] = (name, fallback) => {\n    if (name in values) return values[name];\n    const fromProps = defaultsOf(name);\n    return (fromProps as BlockValue | undefined) ?? (fallback as BlockValue | undefined);\n  };\n\n  const setValue = (name: string, value: BlockValue): void => {\n    setValues((prev) => ({ ...prev, [name]: value }));\n    setErrors((prev) => {\n      if (!prev[name]) return prev;\n      const next = { ...prev };\n      delete next[name];\n      return next;\n    });\n  };\n\n  const submitRespond = (action: BlockAction, formNames: string[] | null, label?: string): void => {\n    if (!action.action_id) return;\n    // Validate required inputs within the submit scope (visible ones only —\n    // fields hidden by visible_if are intentionally not filled).\n    const scopeInputs = findInputs(config.blocks, formNames).filter((input) => evaluateVisibleIf(input.visible_if, getValue));\n    const nextErrors: Record<string, string> = {};\n    const collected: Record<string, BlockValue> = {};\n    for (const input of scopeInputs) {\n      const name = input.name;\n      if (!name) continue;\n      const value = getValue(name);\n      const isEmpty = value === undefined || value === \"\" || (Array.isArray(value) && value.length === 0);\n      if ((input.props?.required as boolean) && isEmpty) {\n        nextErrors[name] = `${(input.props?.label as string) || name} is required`;\n        continue;\n      }\n      if (input.type === \"input_email\" && typeof value === \"string\" && value && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)) {\n        nextErrors[name] = \"Please enter a valid email address\";\n        continue;\n      }\n      if (!isEmpty && value !== undefined) collected[name] = value;\n    }\n    if (Object.keys(nextErrors).length) {\n      setErrors(nextErrors);\n      return;\n    }\n    const result = onAction({ action_id: action.action_id, value: action.value, values: collected, label });\n    if (result instanceof Promise) {\n      setSubmitting(true);\n      void result.finally(() => setSubmitting(false));\n    }\n  };\n\n  const state: BlocksState = { getValue, setValue, errors, disabled: !!disabled || submitting, submitRespond, onSandboxAction };\n\n  return (\n    <BlocksStateContext.Provider value={state}>\n      <View testID={ringgId(\"blocks\")} style={styles.blocks}>\n        {config.blocks.map((node, index) => (\n          <BlockRenderer key={`${node.id ?? \"b\"}-${index}`} node={node} formNames={null} inCarousel={false} />\n        ))}\n      </View>\n    </BlocksStateContext.Provider>\n  );\n};\n\nconst styles = StyleSheet.create({\n  badge: { flexDirection: \"row\", alignItems: \"center\", borderWidth: 1, borderRadius: 9999, paddingHorizontal: 8, paddingVertical: 2 },\n  badgeText: { fontWeight: \"600\" },\n  blocks: { width: \"100%\", flexDirection: \"column\", gap: 12 },\n  button: { flexDirection: \"row\", alignItems: \"center\", justifyContent: \"center\", borderWidth: 1, paddingHorizontal: 16, paddingVertical: 8 },\n  buttonLabel: { fontWeight: \"600\", textAlign: \"center\" },\n  callout: { flexDirection: \"column\", gap: 6, paddingHorizontal: 16, paddingVertical: 12 },\n  // tracking-wider (0.05em) at the title's 11px.\n  calloutTitle: { fontSize: 11, fontWeight: \"600\", textTransform: \"uppercase\", letterSpacing: 0.55 },\n  card: { flexDirection: \"column\", gap: 8, borderWidth: 1 },\n  cardFooter: { marginTop: \"auto\", flexDirection: \"column\", gap: 8 },\n  carousel: { marginHorizontal: -4 },\n  carouselCard: { width: CAROUSEL_CARD_WIDTH, flexShrink: 0 },\n  carouselContent: { flexDirection: \"row\", alignItems: \"stretch\", gap: CAROUSEL_GAP, paddingHorizontal: 4, paddingBottom: 8 },\n  checkSquare: { width: 18, height: 18, flexShrink: 0, alignItems: \"center\", justifyContent: \"center\", borderWidth: 1, borderRadius: 5 },\n  checkboxRow: { flexDirection: \"row\", alignItems: \"center\", gap: 10, paddingVertical: 4 },\n  column: { flexDirection: \"column\" },\n  divider: { flexShrink: 0 },\n  error: { fontSize: 12, marginTop: 2 },\n  expander: { borderWidth: 1, overflow: \"hidden\" },\n  expanderBody: { flexDirection: \"column\", gap: 8, paddingHorizontal: 12, paddingBottom: 12 },\n  expanderSummary: { flexDirection: \"row\", alignItems: \"center\", justifyContent: \"space-between\", gap: 8, paddingHorizontal: 12, paddingVertical: 8 },\n  expanderTitle: { flexShrink: 1, fontWeight: \"500\" },\n  facts: { flexDirection: \"column\", gap: 4 },\n  factsRow: { flexDirection: \"row\", alignItems: \"baseline\", justifyContent: \"space-between\", gap: 12 },\n  factsValue: { flexShrink: 1, textAlign: \"right\", fontWeight: \"500\" },\n  field: { borderWidth: 1, paddingHorizontal: 12, paddingVertical: 10 },\n  fieldIcon: { position: \"absolute\", right: 12, top: 0, bottom: 0, justifyContent: \"center\" },\n  fieldWithIcon: { minHeight: 42, paddingRight: 40 },\n  form: { flexDirection: \"column\", gap: 12 },\n  header: { fontWeight: \"600\" },\n  imageBox: { overflow: \"hidden\" },\n  imageFill: { width: \"100%\", height: \"100%\" },\n  imagePlaceholder: {\n    minHeight: 80,\n    width: \"100%\",\n    flexDirection: \"column\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    gap: 6,\n    borderWidth: 1,\n    borderStyle: \"dashed\",\n    paddingHorizontal: 12,\n    paddingVertical: 16,\n  },\n  label: { fontSize: 12, fontWeight: \"500\" },\n  labelRow: { flexDirection: \"row\", alignItems: \"center\", gap: 4, marginBottom: 4 },\n  nameless: { borderWidth: 1, borderStyle: \"dashed\", borderRadius: 4, paddingHorizontal: 12, paddingVertical: 8 },\n  namelessText: { fontSize: 12 },\n  pill: { borderWidth: 1, borderRadius: 9999, paddingHorizontal: 14, paddingVertical: 6 },\n  pillLabel: { fontWeight: \"500\" },\n  pillRow: { flexDirection: \"row\", flexWrap: \"wrap\", gap: 8 },\n  placeholderText: { maxWidth: \"100%\", fontSize: 12 },\n  ratingRow: { flexDirection: \"row\", alignItems: \"center\", gap: 6 },\n  row: { flexDirection: \"row\" },\n  selectMenu: { borderWidth: 1, marginTop: 4, paddingVertical: 4 },\n  selectOption: { flexDirection: \"row\", alignItems: \"center\", gap: 10, paddingHorizontal: 12, paddingVertical: 8 },\n  selectOptionLabel: { flex: 1 },\n  selectTrigger: { flexDirection: \"row\", alignItems: \"center\", justifyContent: \"space-between\", gap: 8, borderWidth: 1, paddingHorizontal: 12, paddingVertical: 10 },\n  selectValue: { flex: 1 },\n  stepDot: { width: 20, height: 20, flexShrink: 0, alignItems: \"center\", justifyContent: \"center\", borderWidth: 1.5, borderRadius: 9999 },\n  stepIndex: { fontSize: 10, fontWeight: \"600\" },\n  stepLabel: { flexShrink: 1 },\n  stepRow: { flexDirection: \"row\", alignItems: \"center\", gap: 10 },\n  stepsCompact: { gap: 8 },\n  stepsStretch: { justifyContent: \"space-between\" },\n  table: { overflow: \"hidden\", borderWidth: 1 },\n  tableCell: { flex: 1, paddingHorizontal: 12, paddingVertical: 8 },\n  tableHeaderText: { fontSize: 12, fontWeight: \"600\" },\n  textarea: { minHeight: TEXTAREA_MIN_HEIGHT, textAlignVertical: \"top\" },\n  unsupported: { fontSize: 15 },\n});\n\nexport default BlocksStep;\n","// Block Kit wire contract — mirror of the SDK's resolved BlockNode envelope.\n// The bot sends a FULLY-RESOLVED tree (bindings substituted, repeats expanded)\n// over the `ringg.blocks` text stream; interactions go back over the\n// `receive_dynamic_data` RPC as `receive_component_blocks`.\n// Spec: GET /tools/v1/blocks-catalog · docs: blockkit-agents-cdn-integration.md\n\nexport type BlockValue = string | number | boolean | string[];\n\nexport interface BlockAction {\n  action: \"respond\" | \"open_url\" | \"dom_event\" | string;\n  action_id?: string;\n  value?: unknown;\n  url?: string;\n  target?: \"_blank\" | \"_self\";\n  event_name?: string;\n}\n\nexport interface VisibleIf {\n  field?: string;\n  op?: \"eq\" | \"ne\" | \"in\" | \"gt\" | \"lt\" | \"truthy\";\n  value?: unknown;\n  all?: VisibleIf[];\n  any?: VisibleIf[];\n}\n\nexport interface BlockNode {\n  type: string;\n  id?: string;\n  name?: string;\n  slot?: string;\n  props?: Record<string, unknown>;\n  children?: BlockNode[];\n  visible_if?: VisibleIf;\n  on?: Record<string, BlockAction>;\n  /** Authored-envelope only (builder): server binding, resolved away at call time. */\n  visible?: string | boolean;\n  /** Authored-envelope only (builder): repeat expansion, resolved away at call time. */\n  repeat?: { source: string; as: string; max_items?: number };\n}\n\nexport interface BlocksConfig {\n  tool_id?: string;\n  schema_version?: number;\n  blocks: BlockNode[];\n}\n\nexport interface BlocksActionPayload {\n  action_id: string;\n  value?: unknown;\n  values: Record<string, BlockValue>;\n  // The tapped button's label — shown as the user's right-aligned chat bubble,\n  // like a quick-reply selection. Not sent to the bot.\n  label?: string;\n}\n\n// Envelope of one `ringg.blocks` stream message\nexport interface BlocksStreamMessage {\n  component_type: \"render_component_blocks\";\n  component_config: BlocksConfig;\n}\n\n// The envelope/wire version this renderer supports; higher versions render a\n// graceful fallback instead of failing (§12 of the integration guide).\nexport const SUPPORTED_BLOCKS_SCHEMA_VERSION = 1;\n","/**\n * Indeterminate progress bar shown while a chat/call is connecting.\n *\n * Web expresses the sweep as a CSS keyframe (`indeterminate-progress` in the\n * widget's tailwind config): a one-third-width fill that starts off the left\n * edge, catches up at 40% of the cycle, then overshoots the right edge, all\n * while stretching from 0.4x to 0.6x and back. RN has no keyframes, so the same\n * three stops are driven by a single `Animated.Value` and read back as a\n * translate + scale — both transform properties, so the whole thing runs on the\n * native driver and survives a busy JS thread.\n *\n * CSS can say `translateX(-100%)` and mean \"the fill's own width\"; RN transforms\n * are absolute dp, which is why the track measures itself with `onLayout` and\n * the travel distances are multiples of the measured fill width.\n */\n\nimport { useEffect, useRef, useState, type FC } from \"react\";\nimport { Animated, Easing, StyleSheet, View, type LayoutChangeEvent, type StyleProp, type ViewStyle } from \"react-native\";\n\nimport { GradientFill, solidColor } from \"../lib/gradient\";\nimport { ringgId } from \"../lib/testing\";\nimport { useWidgetTheme } from \"../lib/widget-theme\";\n\ninterface LoadingBarProps {\n  /** Accessible label (not rendered visually). */\n  ariaLabel?: string;\n  /** Web's `className` slot: layout overrides from the parent. */\n  style?: StyleProp<ViewStyle>;\n}\n\n/** One full sweep — the `1.4s` of the CSS animation shorthand. */\nconst SWEEP_DURATION_MS = 1400;\n\n/** The middle keyframe, where the fill has caught up with the track's left edge. */\nconst MIDPOINT = 0.4;\n\nconst KEYFRAMES = [0, MIDPOINT, 1];\n\n/** `translateX` per keyframe, as a multiple of the fill's own width. */\nconst TRAVEL_RATIOS = [-1, 0, 2.5];\n\n/** `scaleX` per keyframe. */\nconst STRETCH_SCALES = [0.4, 0.6, 0.4];\n\n/** `cubic-bezier(0.65, 0, 0.35, 1)`. */\nconst SEGMENT_EASING = Easing.bezier(0.65, 0, 0.35, 1);\n\n/**\n * A CSS `animation-timing-function` applies to EVERY keyframe interval, so the\n * sweep eases twice: once into the midpoint, once out of it. Expressing that as\n * `Animated.sequence` of two timings would reproduce the curve but hand the\n * seam between them back to the JS thread — `sequence` starts each child from\n * JS, so the bar hitches exactly while the app is busy connecting.\n *\n * Folding both segments into one easing keeps it a single native animation.\n * RN samples the easing into a frame table when the native driver is on, so an\n * arbitrary function like this one costs nothing at run time.\n */\nconst SWEEP_EASING = (t: number): number => (t < MIDPOINT ? MIDPOINT * SEGMENT_EASING(t / MIDPOINT) : MIDPOINT + (1 - MIDPOINT) * SEGMENT_EASING((t - MIDPOINT) / (1 - MIDPOINT)));\n\n/** `w-1/3` of the track. */\nconst FILL_WIDTH_RATIO = 1 / 3;\n\nconst ROW_HEIGHT = 48;\nconst TRACK_HEIGHT = 6;\n\n/** `rounded-full`; RN clamps to half the shorter side, so any large value is a pill. */\nconst PILL_RADIUS = 9999;\n\nconst LoadingBar: FC<LoadingBarProps> = ({ ariaLabel = \"Connecting\", style }) => {\n  const theme = useWidgetTheme();\n  const [trackWidth, setTrackWidth] = useState(0);\n  const progress = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    // One timing, looped: both eased segments live in SWEEP_EASING, so nothing\n    // hands control back to JS between them.\n    const sweep = Animated.loop(Animated.timing(progress, { toValue: 1, duration: SWEEP_DURATION_MS, easing: SWEEP_EASING, useNativeDriver: true }));\n    sweep.start();\n    return () => sweep.stop();\n  }, [progress]);\n\n  const onTrackLayout = (event: LayoutChangeEvent) => setTrackWidth(event.nativeEvent.layout.width);\n\n  // Zero until the first layout lands; the fill is simply invisible for that frame.\n  const fillWidth = trackWidth * FILL_WIDTH_RATIO;\n  const translateX = progress.interpolate({ inputRange: KEYFRAMES, outputRange: TRAVEL_RATIOS.map((ratio) => ratio * fillWidth) });\n  const scaleX = progress.interpolate({ inputRange: KEYFRAMES, outputRange: STRETCH_SCALES });\n\n  return (\n    <View testID={ringgId(\"loading-bar\")} style={[styles.container, style]}>\n      <View\n        testID={ringgId(\"loading-bar-track\")}\n        accessibilityRole=\"progressbar\"\n        accessibilityLabel={ariaLabel}\n        // `aria-busy` — an indeterminate bar has no value to announce.\n        accessibilityState={{ busy: true }}\n        onLayout={onTrackLayout}\n        style={[styles.track, { backgroundColor: solidColor(theme.borderColor) }]}\n      >\n        <Animated.View testID={ringgId(\"loading-bar-fill\")} style={[styles.fill, { width: fillWidth, transform: [{ translateX }, { scaleX }] }]}>\n          <GradientFill color={theme.primaryColor} style={styles.fillSurface} />\n        </Animated.View>\n      </View>\n    </View>\n  );\n};\n\nexport default LoadingBar;\n\nconst styles = StyleSheet.create({\n  container: { height: ROW_HEIGHT, flexDirection: \"row\", alignItems: \"center\", justifyContent: \"center\" },\n  track: { height: TRACK_HEIGHT, width: \"90%\", borderRadius: PILL_RADIUS, overflow: \"hidden\" },\n  fill: { position: \"absolute\", top: 0, bottom: 0, left: 0, borderRadius: PILL_RADIUS },\n  fillSurface: { ...StyleSheet.absoluteFill, borderRadius: PILL_RADIUS },\n});\n","/**\n * Centred status pill inside the transcript — \"Call connected\", \"Agent left\".\n *\n * The dot colours are literal rather than theme tokens because they carry\n * meaning (green = fine, red = failed) that has to survive any brand palette;\n * web hardcodes the same two values.\n */\n\nimport type { FC } from \"react\";\nimport { Platform, StyleSheet, Text, View } from \"react-native\";\n\nimport { solidColor } from \"../lib/gradient\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveFontFamily, useWidgetTheme } from \"../lib/widget-theme\";\n\ntype SystemLogLevel = \"info\" | \"error\";\n\ntype SystemLogProps = {\n  label: string;\n  meta?: string;\n  level?: SystemLogLevel;\n};\n\nconst INFO_DOT_COLOR = \"#22c55e\";\nconst ERROR_DOT_COLOR = \"#ef4444\";\n\n/** The `font-mono` of the meta span; RN needs a real family per platform. */\nconst MONOSPACE_FAMILY = Platform.select({ ios: \"Menlo\", android: \"monospace\" });\n\nconst dotColorFor = (level: SystemLogLevel): string => {\n  switch (level) {\n    case \"error\":\n      return ERROR_DOT_COLOR;\n    case \"info\":\n    default:\n      return INFO_DOT_COLOR;\n  }\n};\n\nconst SystemLog: FC<SystemLogProps> = ({ label, meta, level = \"info\" }) => {\n  const theme = useWidgetTheme();\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  // Web also tags the row with `data-ringg-level`; RN nodes carry a single\n  // testID, so the level stays observable through the dot colour alone.\n  return (\n    <View testID={ringgId(\"system-log\")} style={styles.row}>\n      {/* Web's `role=\"status\"` is a polite live region; RN exposes that on Android\n          only, and the `text` role keeps the pill one announcement on both. */}\n      <View\n        testID={ringgId(\"system-log-pill\")}\n        accessibilityRole=\"text\"\n        accessibilityLiveRegion=\"polite\"\n        style={[styles.pill, { borderColor: solidColor(theme.borderColor), backgroundColor: theme.backgroundColor }]}\n      >\n        <View testID={ringgId(\"system-log-dot\")} style={[styles.dot, { backgroundColor: dotColorFor(level) }]} />\n        <Text testID={ringgId(\"system-log-label\")} numberOfLines={1} style={[styles.label, { color: theme.textColor, fontFamily }]}>\n          {label}\n        </Text>\n        {meta ? (\n          // Web puts the full string in a `title` tooltip for the truncated case.\n          <Text testID={ringgId(\"system-log-meta\")} numberOfLines={1} accessibilityLabel={meta} style={[styles.meta, { color: theme.mutedTextColor }]}>\n            {meta}\n          </Text>\n        ) : null}\n      </View>\n    </View>\n  );\n};\n\nexport default SystemLog;\n\nconst styles = StyleSheet.create({\n  row: { flexDirection: \"row\", justifyContent: \"center\", marginVertical: 4 },\n  pill: {\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    gap: 8,\n    paddingHorizontal: 12,\n    paddingVertical: 4,\n    borderRadius: 9999,\n    borderWidth: 1,\n    // `max-w-full`: the pill may shrink, but never past the transcript width.\n    flexShrink: 1,\n  },\n  dot: { width: 6, height: 6, borderRadius: 3, flexShrink: 0 },\n  label: { fontSize: 11, fontWeight: \"500\", flexShrink: 1 },\n  meta: { fontSize: 11, fontFamily: MONOSPACE_FAMILY, flexShrink: 1 },\n});\n","/**\n * \"Thinking…\" status shown while an agent reply is pending.\n *\n * The web indicator paints the word through a `background-clip: text` gradient\n * that sweeps left→right forever. Reproducing that here would mean rendering\n * the label as SVG text with a gradient fill and animating the gradient's\n * offset — `react-native-svg` can do it, but the offset is an SVG prop, so the\n * sweep would run on the JS thread, and the label would have to be measured\n * by hand to size the gradient. Both costs land on a component that is on\n * screen precisely while the app is busy receiving a reply.\n *\n * So the effect is split in two instead: the COLOUR becomes the tone the sweep\n * averages to (the brand colour blended 45% toward muted — the same\n * `color-mix` ratio the web stops use), and the MOTION moves into the trailing\n * ellipsis, whose three dots bounce in sequence. Word rotation and the\n * enter/exit tween are unchanged, so the status still reads the same.\n */\n\nimport { useEffect, useRef, useState, type FC } from \"react\";\nimport { Animated, StyleSheet, Text, View, processColor } from \"react-native\";\n\nimport { solidColor } from \"../lib/gradient\";\nimport { ringgId } from \"../lib/testing\";\nimport { resolveFontFamily, useWidgetTheme } from \"../lib/widget-theme\";\n\ninterface TypingIndicatorProps {\n  words?: string[];\n}\n\ninterface TypingDotProps {\n  /** Position in the ellipsis, which is also the dot's stagger slot. */\n  index: number;\n  color: string;\n  fontFamily: string | undefined;\n}\n\n// Cycled while an agent reply is pending. Words are overridable via the\n// `typingWords` config.\nexport const DEFAULT_TYPING_WORDS = [\"Thinking\", \"Reasoning\", \"Working on it\", \"Almost there\"];\n\nconst WORD_INTERVAL_MS = 2200;\n\n/**\n * Enter/exit tween of a word swap. `Animated.timing` already defaults to\n * `Easing.inOut(Easing.ease)`, the curve the web tween runs on, so no easing is\n * spelled out anywhere below.\n */\nconst SWAP_MS = 250;\n/** The 2px the word travels: enters from `+2`, leaves toward `-2`. */\nconst SWAP_OFFSET = 2;\n\n/** `color-mix(in srgb, brand 45%, muted)` — the softened shimmer stop. */\nconst WORD_TINT = 0.45;\n\nconst DOT_COUNT = 3;\n/** One full bounce round trip; every dot repeats on this period. */\nconst DOT_CYCLE_MS = 1200;\nconst DOT_STAGGER_MS = 160;\nconst DOT_RISE_MS = 300;\nconst DOT_LIFT = 2;\nconst DOT_DIM_OPACITY = 0.4;\n\nconst DOT_SLOTS = Array.from({ length: DOT_COUNT }, (_, index) => index);\n\n/**\n * `color-mix(in srgb, color <amount>, base)`. `processColor` is RN's own CSS\n * colour parser (hex, `rgb()`, named), so no colour syntax is re-implemented\n * here — it hands back an ARGB int, and unparseable input keeps the base.\n */\nconst mixColors = (color: string, base: string, amount: number): string => {\n  const from = processColor(color);\n  const to = processColor(base);\n  if (typeof from !== \"number\" || typeof to !== \"number\") return base;\n  const channel = (shift: number): number => Math.round(((from >>> shift) & 0xff) * amount + ((to >>> shift) & 0xff) * (1 - amount));\n  return `rgba(${channel(16)}, ${channel(8)}, ${channel(0)}, ${(channel(24) / 0xff).toFixed(3)})`;\n};\n\n/** One half of a word swap — fade and slide move together. */\nconst swapTo = (fade: Animated.Value, lift: Animated.Value, opacity: number, offset: number): Animated.CompositeAnimation =>\n  Animated.parallel([\n    Animated.timing(fade, { toValue: opacity, duration: SWAP_MS, useNativeDriver: true }),\n    Animated.timing(lift, { toValue: offset, duration: SWAP_MS, useNativeDriver: true }),\n  ]);\n\nconst TypingDot: FC<TypingDotProps> = ({ index, color, fontFamily }) => {\n  const bounce = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    // The leading delay staggers this dot behind its neighbours; the trailing\n    // one pads every dot back to the same DOT_CYCLE_MS period, so the three\n    // never drift out of phase however long the reply takes.\n    const loop = Animated.loop(\n      Animated.sequence([\n        Animated.delay(index * DOT_STAGGER_MS),\n        Animated.timing(bounce, { toValue: 1, duration: DOT_RISE_MS, useNativeDriver: true }),\n        Animated.timing(bounce, { toValue: 0, duration: DOT_RISE_MS, useNativeDriver: true }),\n        Animated.delay(DOT_CYCLE_MS - index * DOT_STAGGER_MS - 2 * DOT_RISE_MS),\n      ]),\n    );\n    loop.start();\n    return () => loop.stop();\n  }, [bounce, index]);\n\n  return (\n    <Animated.Text\n      style={[\n        styles.text,\n        {\n          color,\n          fontFamily,\n          opacity: bounce.interpolate({ inputRange: [0, 1], outputRange: [DOT_DIM_OPACITY, 1] }),\n          transform: [{ translateY: bounce.interpolate({ inputRange: [0, 1], outputRange: [0, -DOT_LIFT] }) }],\n        },\n      ]}\n    >\n      .\n    </Animated.Text>\n  );\n};\n\nconst TypingIndicator: FC<TypingIndicatorProps> = ({ words }) => {\n  const theme = useWidgetTheme();\n  const list = words && words.length > 0 ? words : DEFAULT_TYPING_WORDS;\n  const [index, setIndex] = useState(0);\n\n  // Start of the enter pose — the first word animates in on mount, like\n  // AnimatePresence with an initial animation.\n  const fade = useRef(new Animated.Value(0)).current;\n  const lift = useRef(new Animated.Value(SWAP_OFFSET)).current;\n\n  useEffect(() => {\n    const enter = swapTo(fade, lift, 1, 0);\n    enter.start();\n    return () => enter.stop();\n  }, [fade, lift]);\n\n  useEffect(() => {\n    const count = list.length;\n    if (count <= 1) return;\n\n    let swap: Animated.CompositeAnimation | undefined;\n    const id = setInterval(() => {\n      swap = swapTo(fade, lift, 0, -SWAP_OFFSET);\n      swap.start(({ finished }) => {\n        if (!finished) return;\n        setIndex((current) => (current + 1) % count);\n        // The word leaves upward but the next one arrives from below, so the\n        // enter pose is set before it fades back in — never tweened through.\n        lift.setValue(SWAP_OFFSET);\n        swap = swapTo(fade, lift, 1, 0);\n        swap.start();\n      });\n    }, WORD_INTERVAL_MS);\n\n    return () => {\n      clearInterval(id);\n      swap?.stop();\n      // A stopped swap leaves the word mid-fade. Restoring the resting pose\n      // means a word-list change mid-swap snaps to a readable word instead of\n      // stranding a half-transparent one.\n      fade.setValue(1);\n      lift.setValue(0);\n    };\n  }, [fade, lift, list.length]);\n\n  const word = list[index % list.length] ?? \"\";\n  // A gradient primary contributes its first stop, which is what the web\n  // shimmer opens on.\n  const color = mixColors(solidColor(theme.primaryColor), solidColor(theme.mutedTextColor), WORD_TINT);\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n\n  return (\n    // RN has no `role=\"status\"`; an accessible container with a live region is\n    // how both platforms announce a changing status without reading each word.\n    <View testID={ringgId(\"typing-indicator\")} accessible accessibilityLiveRegion=\"polite\" accessibilityLabel=\"Agent is thinking\" style={styles.row}>\n      <Animated.View testID={ringgId(\"typing-indicator-word\")} style={[styles.word, { opacity: fade, transform: [{ translateY: lift }] }]}>\n        <Text style={[styles.text, { color, fontFamily }]}>{word}</Text>\n        {DOT_SLOTS.map((slot) => (\n          <TypingDot key={slot} index={slot} color={color} fontFamily={fontFamily} />\n        ))}\n      </Animated.View>\n    </View>\n  );\n};\n\nexport default TypingIndicator;\n\nconst styles = StyleSheet.create({\n  /** `mr-auto` keeps the indicator hugging the left edge of the transcript. */\n  row: { flexDirection: \"row\", alignItems: \"center\", alignSelf: \"flex-start\", paddingVertical: 8 },\n  word: { flexDirection: \"row\", alignItems: \"center\" },\n  text: { fontSize: 14, lineHeight: 20, fontWeight: \"500\" },\n});\n","/**\n * Voice leaf — the visualizer mount for the `showVoiceAnimation` branch.\n *\n * Web has two leaves here, both gated on LiveKit's `RoomContext`. RN has one,\n * and no context at all:\n *\n *  - the Room arrives as a prop. The widget already holds it (the transport\n *    returns it for exactly these presentational reads), so wrapping the tree\n *    in a second provider just to read two track handles buys nothing. Without\n *    a room the visualizer renders with no tracks, which is its ambient idle\n *    state — the degradation is invisible.\n *  - there is no `MaybeRoomAudioRenderer` counterpart. Remote audio needs no\n *    elements on mobile: subscribed tracks play through the OS audio session,\n *    which `transport/livekit-transport.ts` owns for the life of the call.\n *\n * Track handles are read imperatively rather than through hooks, so they have\n * to be re-read whenever publications change — a call that starts before the\n * agent joins would otherwise animate one side forever.\n */\n\nimport { useEffect, useState, type FC } from \"react\";\nimport { StyleSheet, type StyleProp, type ViewStyle } from \"react-native\";\nimport { RoomEvent, Track, type LocalAudioTrack, type RemoteAudioTrack, type Room } from \"livekit-client\";\n\nimport { isAgentParticipant } from \"../transport/agent\";\nimport DotAudioVisualizer from \"./dot-audio-visualizer\";\n\ninterface VoiceAnimationLeafProps {\n  /** The live Room, when there is one. Absent → ambient idle animation. */\n  room?: Room;\n  style?: StyleProp<ViewStyle>;\n}\n\ninterface MicrophoneTracks {\n  localTrack?: LocalAudioTrack;\n  remoteTrack?: RemoteAudioTrack;\n}\n\n/** Every event after which the microphone publications may differ. */\nconst TRACK_EVENTS = [RoomEvent.TrackSubscribed, RoomEvent.TrackUnsubscribed, RoomEvent.LocalTrackPublished, RoomEvent.LocalTrackUnpublished, RoomEvent.ParticipantConnected] as const;\n\n/**\n * Mic publications on both sides (App.tsx:236-241). The agent is resolved with\n * the shared adapter rule so the visualizer always animates the same\n * participant the transport talks to.\n */\nconst resolveTracks = (room: Room | undefined): MicrophoneTracks => {\n  if (!room) return {};\n  const agent = Array.from(room.remoteParticipants.values()).find(isAgentParticipant);\n  // Casts are safe by construction: a `Track.Source.Microphone` publication is\n  // always an audio track — the same narrowing the web leaf makes.\n  return {\n    localTrack: room.localParticipant.getTrackPublication(Track.Source.Microphone)?.track as LocalAudioTrack | undefined,\n    remoteTrack: agent?.getTrackPublication(Track.Source.Microphone)?.track as RemoteAudioTrack | undefined,\n  };\n};\n\nconst useMicrophoneTracks = (room: Room | undefined): MicrophoneTracks => {\n  const [tracks, setTracks] = useState<MicrophoneTracks>(() => resolveTracks(room));\n\n  useEffect(() => {\n    // Re-read on mount too: a track may have been published between the render\n    // that produced the initial state and this effect running.\n    setTracks(resolveTracks(room));\n    if (!room) return;\n\n    const update = () => setTracks(resolveTracks(room));\n    for (const event of TRACK_EVENTS) room.on(event, update);\n    return () => {\n      for (const event of TRACK_EVENTS) room.off(event, update);\n    };\n  }, [room]);\n\n  return tracks;\n};\n\nexport const VoiceAnimationLeaf: FC<VoiceAnimationLeafProps> = ({ room, style }) => {\n  const { localTrack, remoteTrack } = useMicrophoneTracks(room);\n  return <DotAudioVisualizer localTrack={localTrack} remoteTrack={remoteTrack} style={[styles.fill, style]} />;\n};\n\nconst styles = StyleSheet.create({\n  fill: { flex: 1 },\n});\n","/**\n * Agent participant detection — spec §7.\n *\n * Production (agents-cdn) uses two rules in different places:\n *  - RPC destination / text-stream handlers: `identity?.includes(\"agent\")`\n *  - `useVoiceAssistant` (transcription/audio): `kind === ParticipantKind.AGENT`\n *\n * The adapter uses the combined rule recommended by the spec so both paths\n * resolve the same participant: kind first, identity substring as fallback.\n */\n\nimport { ParticipantKind, type Participant, type RemoteParticipant, type Room } from \"livekit-client\";\n\n/** Production's substring rule (App.tsx text-stream handlers). */\nexport function isAgentIdentity(identity: string | undefined): boolean {\n  return identity?.includes(\"agent\") ?? false;\n}\n\n/** Combined rule: participant kind wins, identity substring as fallback. */\nexport function isAgentParticipant(participant: Participant): boolean {\n  return participant.kind === ParticipantKind.AGENT || isAgentIdentity(participant.identity);\n}\n\n/**\n * Resolve the agent among the room's remote participants. Kind-tagged agents\n * take priority over substring matches so a human named \"agent-tester\" never\n * shadows a real agent.\n */\nexport function findAgentParticipant(room: Room): RemoteParticipant | undefined {\n  const remotes = Array.from(room.remoteParticipants.values());\n  return remotes.find((p) => p.kind === ParticipantKind.AGENT) ?? remotes.find((p) => isAgentIdentity(p.identity));\n}\n","/**\n * The voice call's dot grid: 22 columns whose lit height follows whoever is\n * speaking, and an idle wave when nobody is.\n *\n * Band volumes come from `@livekit/react-native`'s `useMultibandTrackVolume`,\n * the RN counterpart of the web hook — same bands, same 0..1 magnitudes, so\n * the geometry below is the web component's arithmetic unchanged.\n *\n * Two DOM mechanisms have RN equivalents rather than ports: the container's\n * ResizeObserver becomes `onLayout` (RN reports every layout pass anyway), and\n * the ambient wave's rAF loop becomes an interval — see `useAmbientWave`.\n */\n\nimport { memo, useCallback, useEffect, useMemo, useRef, useState, type FC } from \"react\";\nimport { Animated, StyleSheet, View, type LayoutChangeEvent, type StyleProp, type ViewStyle } from \"react-native\";\n\nimport { useMultibandTrackVolume } from \"@livekit/react-native\";\nimport type { LocalAudioTrack, RemoteAudioTrack } from \"livekit-client\";\n\nimport { solidColor } from \"../lib/gradient\";\nimport { ringgId } from \"../lib/testing\";\nimport { useWidgetTheme } from \"../lib/widget-theme\";\n\ninterface DotAudioVisualizerProps {\n  localTrack?: LocalAudioTrack;\n  remoteTrack?: RemoteAudioTrack;\n  style?: StyleProp<ViewStyle>;\n}\n\ninterface DotProps {\n  lit: boolean;\n  color: string;\n}\n\ninterface DotColumnProps {\n  volume: number;\n  color: string;\n  rows: number;\n}\n\nconst BANDS = 22;\nconst MIN_ROWS = 5;\nconst MAX_ROWS = 21;\n// Target vertical spacing per row — keeps density consistent across container heights.\nconst PX_PER_ROW = 22;\n\nconst DOT_SIZE = 8;\nconst UNLIT_OPACITY = 0.15;\nconst UNLIT_SCALE = 0.6;\n\n/** framer's `{ type: \"spring\", stiffness: 220, damping: 22 }`, mass 1 implied. */\nconst DOT_SPRING = { stiffness: 220, damping: 22, mass: 1 };\n\n/**\n * Idle wave, sampled instead of animated: no live track means no audio to\n * follow, so a slow sine stands in. 40ms is the same cadence LiveKit pushes\n * band updates at, which keeps the two sources feeling alike and costs a\n * fraction of the re-renders a frame loop would.\n *\n * The step is scaled to match: web advances 0.04 rad per rAF frame (~60Hz),\n * so the same wave speed at 25Hz needs 0.04 * 60/25. Carrying 0.04 across\n * unchanged would run the idle animation at 40% of the web widget's pace.\n */\nconst AMBIENT_TICK_MS = 40;\nconst WEB_STEP_PER_FRAME = 0.04;\nconst WEB_FRAMES_PER_SECOND = 60;\nconst AMBIENT_STEP = (WEB_STEP_PER_FRAME * WEB_FRAMES_PER_SECOND) / (1000 / AMBIENT_TICK_MS);\nconst AMBIENT_FLOOR = 0.15;\nconst AMBIENT_SWING = 0.25;\n/** Phase offset per band — what makes the wave travel across the columns. */\nconst AMBIENT_PHASE = 0.5;\n\n/** Row count from the measured height: `floor(h / 22)` clamped, forced odd. */\nconst rowsForHeight = (height: number): number => {\n  const raw = Math.max(MIN_ROWS, Math.min(MAX_ROWS, Math.floor(height / PX_PER_ROW)));\n  // Keep odd so there's a clear center row for the volume animation.\n  return raw % 2 === 0 ? raw - 1 : raw;\n};\n\nconst useResponsiveRows = (): { rows: number; onLayout: (event: LayoutChangeEvent) => void } => {\n  const [rows, setRows] = useState(MIN_ROWS);\n\n  const onLayout = useCallback((event: LayoutChangeEvent) => {\n    setRows(rowsForHeight(event.nativeEvent.layout.height));\n  }, []);\n\n  return { rows, onLayout };\n};\n\n/**\n * Only ticks while `enabled` — the wave is invisible during a live call, and\n * an interval nobody reads would still re-render the whole grid 25 times a\n * second.\n */\nconst useAmbientWave = (bands: number, enabled: boolean): number[] => {\n  const [vals, setVals] = useState<number[]>(() => Array.from({ length: bands }, () => AMBIENT_FLOOR));\n\n  useEffect(() => {\n    if (!enabled) return;\n    let t = 0;\n    const id = setInterval(() => {\n      t += AMBIENT_STEP;\n      setVals(Array.from({ length: bands }, (_, i) => AMBIENT_FLOOR + AMBIENT_SWING * Math.abs(Math.sin(t + i * AMBIENT_PHASE))));\n    }, AMBIENT_TICK_MS);\n    return () => clearInterval(id);\n  }, [bands, enabled]);\n\n  return vals;\n};\n\n/**\n * Memoized because the grid is up to 462 dots and every volume tick re-renders\n * all of them; only the handful whose lit state actually flipped should touch\n * the animation driver.\n *\n * `lit` itself is not published anywhere — `testID` carries a name, not a\n * value, so web's `data-ringg-lit` has no counterpart and the state stays\n * visual.\n */\nconst Dot = memo(({ lit, color }: DotProps) => {\n  // Mounts at its target — the first paint is a still frame, not an animation.\n  const progress = useRef(new Animated.Value(lit ? 1 : 0)).current;\n\n  useEffect(() => {\n    const spring = Animated.spring(progress, { toValue: lit ? 1 : 0, ...DOT_SPRING, useNativeDriver: true });\n    spring.start();\n    return () => spring.stop();\n  }, [lit, progress]);\n\n  return (\n    <Animated.View\n      testID={ringgId(\"voice-animation-dot\")}\n      style={[\n        styles.dot,\n        {\n          backgroundColor: color,\n          // Spring overshoot is welcome on scale (it gives the pop) but must\n          // not push opacity past opaque.\n          opacity: progress.interpolate({ inputRange: [0, 1], outputRange: [UNLIT_OPACITY, 1], extrapolate: \"clamp\" }),\n          transform: [{ scale: progress.interpolate({ inputRange: [0, 1], outputRange: [UNLIT_SCALE, 1] }) }],\n        },\n      ]}\n    />\n  );\n});\n\nconst DotColumn: FC<DotColumnProps> = ({ volume, color, rows }) => {\n  const centerIdx = Math.floor(rows / 2);\n  // Perceived loudness curve — boosts low volumes so the column feels responsive.\n  const perceived = Math.pow(Math.min(1, volume), 0.4);\n  const litRadius = perceived * (centerIdx + 1);\n\n  return (\n    <View testID={ringgId(\"voice-animation-column\")} style={styles.column}>\n      {Array.from({ length: rows }, (_, i) => (\n        <Dot key={i} lit={Math.abs(i - centerIdx) <= litRadius} color={color} />\n      ))}\n    </View>\n  );\n};\n\nconst DotAudioVisualizer: FC<DotAudioVisualizerProps> = ({ localTrack, remoteTrack, style }) => {\n  const theme = useWidgetTheme();\n  const dotColor = solidColor(theme.primaryColor);\n\n  const localVols = useMultibandTrackVolume(localTrack, { bands: BANDS });\n  const remoteVols = useMultibandTrackVolume(remoteTrack, { bands: BANDS });\n\n  const hasLiveTrack = Boolean(localTrack || remoteTrack);\n  const ambient = useAmbientWave(BANDS, !hasLiveTrack);\n\n  // Whoever is louder owns the band, so one grid covers both sides of the call.\n  const liveVolumes = useMemo(() => Array.from({ length: BANDS }, (_, i) => Math.max(localVols[i] ?? 0, remoteVols[i] ?? 0)), [localVols, remoteVols]);\n\n  const volumes = hasLiveTrack ? liveVolumes : ambient;\n  const { rows, onLayout } = useResponsiveRows();\n\n  return (\n    // Decorative, so hidden from both screen readers — the web leaf is\n    // `aria-hidden`, which takes one prop per platform here.\n    <View\n      testID={ringgId(\"voice-animation\")}\n      accessibilityElementsHidden\n      importantForAccessibility=\"no-hide-descendants\"\n      onLayout={onLayout}\n      style={[styles.container, style]}\n    >\n      {volumes.map((vol, i) => (\n        <DotColumn key={i} volume={vol} color={dotColor} rows={rows} />\n      ))}\n    </View>\n  );\n};\n\nexport default DotAudioVisualizer;\n\nconst styles = StyleSheet.create({\n  container: { flexDirection: \"row\", width: \"100%\", height: \"100%\", alignItems: \"stretch\", justifyContent: \"space-around\" },\n  column: { flexDirection: \"column\", alignItems: \"center\", justifyContent: \"space-around\" },\n  dot: { width: DOT_SIZE, height: DOT_SIZE, borderRadius: DOT_SIZE / 2 },\n});\n","/**\n * Confirmation dialog — RN counterpart of the web widget's\n * `constrained-alert-dialog.tsx`.\n *\n * The web version exists to CONSTRAIN: it portals the dialog into the widget's\n * own box so an embedded widget never dims the host page. That reasoning\n * carries over exactly — the RN widget is an overlay on someone else's app, and\n * a full-screen scrim would dim their whole UI to ask a question about ours. So\n * this fills the widget panel and nothing beyond it.\n *\n * A `<Modal>` would have been less code and is the usual RN answer, but a Modal\n * cannot be constrained: it always covers the window. The one thing it gave for\n * free — the Android back gesture — is picked up here with `BackHandler`, so\n * back still cancels rather than leaving the dialog stranded.\n *\n * The frosted overlay degrades to a flat tinted scrim. `backdrop-filter` needs\n * a native blur view to exist on RN, and 40% of the widget background — the\n * same mix the web overlay asks `color-mix` for — already reads as \"dimmed, in\n * the widget's colour family\".\n */\n\nimport { useEffect, useRef, type FC } from \"react\";\nimport { Animated, BackHandler, StyleSheet, Text, View } from \"react-native\";\n\nimport { solidColor } from \"../../lib/gradient\";\nimport { ringgId } from \"../../lib/testing\";\nimport { resolveButtonRadius, resolveFontFamily, resolveRadius, useWidgetTheme } from \"../../lib/widget-theme\";\nimport { Button } from \"./button\";\n\ninterface ConfirmDialogProps {\n  open: boolean;\n  title: string;\n  description?: string;\n  confirmLabel: string;\n  cancelLabel: string;\n  onConfirm: () => void;\n  onCancel: () => void;\n}\n\n/** Web mixes the overlay to 40% of the widget background; RN layers it instead. */\nconst SCRIM_OPACITY = 0.4;\n\n/** `max-w-md` — the card stops growing on tablets. */\nconst CARD_MAX_WIDTH = 448;\n\n/** Web hardcodes a 16px card; the theme wins here, with that value as floor. */\nconst CARD_RADIUS_FALLBACK = 16;\n\n/**\n * Web springs the card in from `scale: 0.94, y: 8` on top of the overlay fade\n * (`constrained-alert-dialog.tsx`). The Modal's own fade carries the exit, so\n * only the entrance is driven here — the card would otherwise land flat while\n * web's visibly overshoots.\n */\nconst CARD_SPRING = { stiffness: 420, damping: 30, mass: 1 };\nconst CARD_ENTER_SCALE = 0.94;\nconst CARD_ENTER_OFFSET = 8;\n\nexport const ConfirmDialog: FC<ConfirmDialogProps> = ({ open, title, description, confirmLabel, cancelLabel, onConfirm, onCancel }) => {\n  const theme = useWidgetTheme();\n  const fontFamily = resolveFontFamily(theme.fontFamily);\n  const buttonRadius = resolveButtonRadius(theme.buttonStyle);\n  const enter = useRef(new Animated.Value(0)).current;\n\n  useEffect(() => {\n    // Reset on close so the next open replays the spring rather than starting\n    // from wherever the last one finished.\n    if (!open) {\n      enter.setValue(0);\n      return;\n    }\n    const pop = Animated.spring(enter, { toValue: 1, ...CARD_SPRING, useNativeDriver: true });\n    pop.start();\n    return () => pop.stop();\n  }, [open, enter]);\n\n  useEffect(() => {\n    if (!open) return;\n    // Android's back gesture must resolve the dialog, not fall through to the\n    // host app's navigation while a confirmation is on screen.\n    const subscription = BackHandler.addEventListener(\"hardwareBackPress\", () => {\n      onCancel();\n      return true;\n    });\n    return () => subscription.remove();\n  }, [open, onCancel]);\n\n  if (!open) return null;\n\n  return (\n    <View style={styles.root}>\n        {/* Non-interactive on purpose — the web overlay has no dismiss handler\n            either, so the decision to end a call is never taken by a stray tap. */}\n        <View pointerEvents=\"none\" style={[StyleSheet.absoluteFill, styles.scrim, { backgroundColor: solidColor(theme.backgroundColor) }]} />\n        <Animated.View\n          testID={ringgId(\"end-call-dialog\")}\n          // Hides the rest of the tree from VoiceOver while the dialog is up.\n          accessibilityViewIsModal\n          style={[\n            styles.card,\n            {\n              opacity: enter,\n              transform: [{ scale: enter.interpolate({ inputRange: [0, 1], outputRange: [CARD_ENTER_SCALE, 1] }) }, { translateY: enter.interpolate({ inputRange: [0, 1], outputRange: [CARD_ENTER_OFFSET, 0] }) }],\n              backgroundColor: solidColor(theme.backgroundColor),\n              borderColor: solidColor(theme.borderColor),\n              borderRadius: resolveRadius(theme.borderRadius, CARD_RADIUS_FALLBACK),\n            },\n          ]}\n        >\n          <View testID={ringgId(\"end-call-dialog-header\")} style={styles.header}>\n            <Text testID={ringgId(\"end-call-dialog-title\")} style={[styles.title, { color: theme.textColor, fontFamily }]}>\n              {title}\n            </Text>\n            {description ? (\n              <Text testID={ringgId(\"end-call-dialog-description\")} style={[styles.description, { color: theme.mutedTextColor, fontFamily }]}>\n                {description}\n              </Text>\n            ) : null}\n          </View>\n          <View testID={ringgId(\"end-call-dialog-footer\")} style={styles.footer}>\n            <Button variant=\"outline\" onPress={onCancel} testID={ringgId(\"end-call-cancel\")} style={{ borderRadius: buttonRadius }}>\n              {cancelLabel}\n            </Button>\n            <Button onPress={onConfirm} testID={ringgId(\"end-call-confirm\")} style={{ borderRadius: buttonRadius }}>\n              {confirmLabel}\n            </Button>\n          </View>\n        </Animated.View>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  // Fills the widget panel rather than the window, and sits above the panel's\n  // own chrome (header 10, minimize/close 20) so nothing pokes through it.\n  root: { ...StyleSheet.absoluteFill, zIndex: 30, alignItems: \"center\", justifyContent: \"center\", padding: 16 },\n  scrim: { opacity: SCRIM_OPACITY },\n  card: {\n    width: \"100%\",\n    maxWidth: CARD_MAX_WIDTH,\n    marginHorizontal: 16,\n    padding: 16,\n    borderWidth: 1,\n    gap: 12,\n    // The web card's two stacked shadows collapse into the one elevation each\n    // platform can express.\n    shadowColor: \"#000000\",\n    shadowOpacity: 0.08,\n    shadowRadius: 13,\n    shadowOffset: { width: 0, height: 6 },\n    elevation: 8,\n  },\n  header: { gap: 6 },\n  title: { fontSize: 17, lineHeight: 24, fontWeight: \"500\" },\n  description: { fontSize: 15, lineHeight: 21 },\n  footer: { flexDirection: \"row\", justifyContent: \"flex-end\", gap: 8, paddingTop: 8 },\n});\n","/**\n * Themed button — RN counterpart of the web widget's `ui/button.tsx`.\n *\n * The web version is shadcn/cva over Tailwind classes. That machinery does not\n * survive the crossing (no class strings, no cascade, and `variant` has to\n * resolve to concrete colours rather than semantic tokens), so the variants are\n * re-expressed as style objects resolved against the live widget theme.\n *\n * The variant and size NAMES are kept identical to web on purpose: the call\n * sites are ports of the same tree, and a reviewer comparing the two files\n * should see `variant=\"outline\" size=\"icon\"` in both.\n *\n * A gradient `primaryColor` cannot be a `backgroundColor`, so the default\n * variant paints through <GradientFill> and every other variant — which are\n * flat by definition — takes the cheap path.\n */\n\nimport type { FC, ReactNode } from \"react\";\nimport { StyleSheet, Text, View, type StyleProp, type TextStyle, type ViewStyle } from \"react-native\";\nimport type { ResolvedWidgetTheme } from \"@ringg/core\";\n\nimport { GradientFill, solidColor } from \"../../lib/gradient\";\nimport { resolveFontFamily, useWidgetTheme } from \"../../lib/widget-theme\";\nimport { Touchable } from \"./pressable\";\n\nexport type ButtonVariant = \"default\" | \"outline\" | \"ghost\" | \"destructive\";\nexport type ButtonSize = \"default\" | \"sm\" | \"lg\" | \"icon\";\n\nexport interface ButtonProps {\n  variant?: ButtonVariant;\n  size?: ButtonSize;\n  onPress?: () => void;\n  disabled?: boolean;\n  /** Overrides the resolved variant surface — used for per-config styling. */\n  style?: StyleProp<ViewStyle>;\n  textStyle?: StyleProp<TextStyle>;\n  testID?: string;\n  accessibilityLabel?: string;\n  /** A string renders as themed label text; nodes render as-is. */\n  children?: ReactNode;\n}\n\ninterface VariantSurface {\n  /** May be a gradient string — resolved by the renderer, not here. */\n  background: string;\n  foreground: string;\n  borderColor?: string;\n}\n\nconst SIZES: Record<ButtonSize, ViewStyle> = {\n  default: { height: 36, paddingHorizontal: 16 },\n  sm: { height: 32, paddingHorizontal: 12 },\n  lg: { height: 40, paddingHorizontal: 32 },\n  icon: { height: 36, width: 36 },\n};\n\nconst TEXT_SIZES: Record<ButtonSize, number> = { default: 14, sm: 12, lg: 14, icon: 14 };\n\nconst surfaceFor = (variant: ButtonVariant, theme: ResolvedWidgetTheme): VariantSurface => {\n  switch (variant) {\n    case \"outline\":\n      return { background: theme.surfaceColor, foreground: theme.textColor, borderColor: solidColor(theme.borderColor) };\n    case \"ghost\":\n      // Web's ghost is transparent until hover; RN's press feedback is the\n      // opacity dip on Touchable, so the resting state is simply transparent.\n      return { background: \"transparent\", foreground: theme.mutedTextColor };\n    case \"destructive\":\n      return { background: theme.errorColor, foreground: \"#ffffff\" };\n    case \"default\":\n    default:\n      return { background: theme.primaryColor, foreground: theme.primaryTextColor };\n  }\n};\n\nexport const Button: FC<ButtonProps> = ({ variant = \"default\", size = \"default\", onPress, disabled = false, style, textStyle, testID, accessibilityLabel, children }) => {\n  const theme = useWidgetTheme();\n  const surface = surfaceFor(variant, theme);\n\n  const content =\n    typeof children === \"string\" ? (\n      <Text style={[styles.label, { color: surface.foreground, fontSize: TEXT_SIZES[size], fontFamily: resolveFontFamily(theme.fontFamily) }, textStyle]} numberOfLines={1}>\n        {children}\n      </Text>\n    ) : (\n      children\n    );\n\n  // Every variant but `default` is flat, so it skips the SVG layer entirely.\n  const body =\n    variant === \"default\" ? (\n      <GradientFill color={surface.background} style={[styles.base, SIZES[size], style]}>\n        {content}\n      </GradientFill>\n    ) : (\n      <View style={[styles.base, SIZES[size], { backgroundColor: surface.background }, surface.borderColor ? { borderWidth: StyleSheet.hairlineWidth, borderColor: surface.borderColor } : null, style]}>{content}</View>\n    );\n\n  return (\n    <Touchable onPress={onPress} disabled={disabled} testID={testID} accessibilityLabel={accessibilityLabel}>\n      {body}\n    </Touchable>\n  );\n};\n\nconst styles = StyleSheet.create({\n  base: {\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    gap: 8,\n    borderRadius: 6,\n  },\n  label: { fontWeight: \"500\" },\n});\n","/**\n * Live microphone state for the mute button.\n *\n * Mute is a purely room-local toggle — no core round trip, no confirmation.\n * The track stays published; muting only stops the frames, which is why the\n * visualizer's local band drops to ~0 rather than disappearing.\n *\n * Web reads this through LiveKit's React context, which costs a\n * `RoomContext.Provider` around the whole tree. The RN widget already holds\n * the Room (the transport hands it back), so it subscribes directly — one\n * fewer provider for integrators to wire, and one fewer way to wire it wrong.\n */\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { RoomEvent, type Room } from \"livekit-client\";\n\nexport interface MicrophoneControl {\n  enabled: boolean;\n  toggle: () => void;\n}\n\n/**\n * Every event after which `isMicrophoneEnabled` may have changed. Muting fires\n * TrackMuted/TrackUnmuted; publishing and unpublishing (call start, call end)\n * fire the local-track pair; a reconnect can republish, which surfaces as a\n * connection-state change.\n */\nconst MIC_EVENTS = [RoomEvent.TrackMuted, RoomEvent.TrackUnmuted, RoomEvent.LocalTrackPublished, RoomEvent.LocalTrackUnpublished, RoomEvent.ConnectionStateChanged] as const;\n\n/** Returns undefined without a Room — callers hide the control rather than showing a dead one. */\nexport const useMicrophone = (room: Room | undefined): MicrophoneControl | undefined => {\n  const [enabled, setEnabled] = useState(() => room?.localParticipant.isMicrophoneEnabled ?? false);\n\n  useEffect(() => {\n    if (!room) return;\n\n    const sync = (): void => setEnabled(room.localParticipant.isMicrophoneEnabled);\n    // The mic may already be live when this mounts (the widget re-renders into\n    // an ongoing call), so read once before subscribing.\n    sync();\n\n    MIC_EVENTS.forEach((event) => room.on(event, sync));\n    return () => {\n      MIC_EVENTS.forEach((event) => room.off(event, sync));\n    };\n  }, [room]);\n\n  const toggle = useCallback(() => {\n    if (!room) return;\n    // Optimistic: LiveKit's mute round-trips through the native layer, and a\n    // button that waits for it feels broken. The event listeners above correct\n    // the state if the flip is rejected.\n    const next = !room.localParticipant.isMicrophoneEnabled;\n    setEnabled(next);\n    void room.localParticipant.setMicrophoneEnabled(next).catch(() => setEnabled(!next));\n  }, [room]);\n\n  return room ? { enabled, toggle } : undefined;\n};\n","/**\n * Deferred unmount — React Native's missing `<AnimatePresence>`.\n *\n * On web, framer-motion keeps an exiting subtree mounted until its exit\n * animation finishes, then removes it. React has no such thing on its own: the\n * moment a condition flips false, `{visible ? <View/> : null}` unmounts in that\n * same commit. Any exit animation started afterwards drives a value nothing is\n * attached to, so it runs invisibly and the element simply vanishes.\n *\n * This hook inverts the control: it owns a `mounted` flag that turns true\n * immediately on show, and false only in the animation's completion callback.\n * Callers gate rendering on `mounted` rather than on `visible`, and bind\n * `progress` to opacity/transform.\n *\n *   const { mounted, progress } = usePresence(isOpen, ENTER_SPRING);\n *   if (!mounted) return null;\n *   <Animated.View style={{ opacity: progress }} />\n *\n * Springs, not durations: the web widget's shells are springs, and a spring is\n * the one curve a fixed-duration `timing` cannot imitate — it settles with a\n * small overshoot rather than landing flat.\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Animated } from \"react-native\";\n\nexport interface PresenceSpring {\n  /** framer-motion's `stiffness`; RN's Animated.spring takes the same units. */\n  stiffness: number;\n  damping: number;\n  mass?: number;\n}\n\nexport interface Presence {\n  /** Render while true — stays true through the exit animation. */\n  mounted: boolean;\n  /** 0 while hidden, 1 while shown. Drive opacity and transform with it. */\n  progress: Animated.Value;\n}\n\nconst DEFAULT_MASS = 1;\n\nexport const usePresence = (visible: boolean, spring: PresenceSpring): Presence => {\n  const progress = useRef(new Animated.Value(0)).current;\n  // Seeded false even when `visible` starts true, so a widget configured to\n  // open on mount still animates in rather than appearing fully formed.\n  const [mounted, setMounted] = useState(false);\n\n  useEffect(() => {\n    if (visible) setMounted(true);\n\n    const animation = Animated.spring(progress, {\n      toValue: visible ? 1 : 0,\n      stiffness: spring.stiffness,\n      damping: spring.damping,\n      mass: spring.mass ?? DEFAULT_MASS,\n      useNativeDriver: true,\n    });\n\n    animation.start(({ finished }) => {\n      // Only a finished exit may unmount. An interrupted one means `visible`\n      // flipped back mid-flight and a new animation already owns the value.\n      if (finished && !visible) setMounted(false);\n    });\n\n    return () => animation.stop();\n  }, [visible, progress, spring.stiffness, spring.damping, spring.mass]);\n\n  return { mounted, progress };\n};\n","/**\n * Inline link rendering for the legal disclaimer — RN port of the web\n * widget's `lib/text-helpers.tsx`.\n *\n * Same matching rules (word-boundary, escaped, one pass per configured link)\n * so the same disclaimer config highlights the same words on both platforms.\n * Only the leaf differs: `<a href>` becomes a `<Text onPress>` that hands the\n * URL to `Linking`, which is RN's \"open in the system browser\" — the closest\n * equivalent of `target=\"_blank\"`.\n */\n\nimport { Fragment, type ReactNode } from \"react\";\nimport { Linking, Text, type TextStyle } from \"react-native\";\n\n/** Tailwind's `text-blue-500`, the colour the web disclaimer links use. */\nconst LINK_COLOR = \"#3b82f6\";\n\nconst escapeForRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\nconst openUrl = (url: string): void => {\n  // Best-effort: a malformed or unhandled scheme must not crash the widget.\n  void Linking.openURL(url).catch(() => {});\n};\n\n/**\n * Splits `text` on each configured link word and returns a node list ready to\n * drop inside a `<Text>`. Callers own the surrounding typography; only the\n * link colour is applied here.\n */\nexport const renderTextWithLinks = (text: string, links?: Record<string, string>, linkStyle?: TextStyle): ReactNode => {\n  if (!links) return text;\n\n  let parts: ReactNode[] = [text];\n\n  Object.entries(links).forEach(([word, url]) => {\n    parts = parts.flatMap((part, partIndex) => {\n      if (typeof part !== \"string\") return part;\n\n      const pattern = new RegExp(`\\\\b(${escapeForRegExp(word)})\\\\b`, \"g\");\n\n      return part.split(pattern).map((segment, segmentIndex) =>\n        segment === word ? (\n          <Text key={`${partIndex}-${segmentIndex}`} style={[{ color: LINK_COLOR }, linkStyle]} onPress={() => openUrl(url)}>\n            {word}\n          </Text>\n        ) : (\n          <Fragment key={`${partIndex}-${segmentIndex}`}>{segment}</Fragment>\n        ),\n      );\n    });\n  });\n\n  return parts;\n};\n","/**\n * LiveKit React Native transport — the real `TransportAdapter` over\n * `@livekit/react-native`, behavior-matched to the web adapter (which is\n * itself matched to production, @desivocal/agents-cdn).\n *\n * The wire behavior is deliberately identical to `web/src/transport/\n * livekit-transport.ts` — same Room options, same double-send chat, same\n * agent-classification and session-ended rules — because both talk to the same\n * backend and core drives them through the same port. Read that file's parity\n * notes; they apply here verbatim.\n *\n * Only what the platform forces differs:\n *  - remote audio needs no elements. Mobile plays subscribed audio through the\n *    OS, so `<RoomAudioRenderer />`'s job becomes owning an audio SESSION\n *    (see platform/audio-session.ts) rather than attaching media elements;\n *  - `registerGlobals()` must run before a Room is constructed — the adapter\n *    does it so a missing app-entry call is not a mysterious runtime failure;\n *  - autoplay policy has no mobile equivalent, so the web adapter's\n *    `startAudio()` recovery has no counterpart.\n */\n\nimport { registerGlobals } from \"@livekit/react-native\";\nimport {\n  ConnectionState as LKConnectionState,\n  Room,\n  RoomEvent,\n  type DataPacket_Kind,\n  type Participant,\n  type RemoteParticipant,\n  type RoomOptions,\n  type RpcInvocationData,\n  type TextStreamHandler,\n  type TranscriptionSegment as LKTranscriptionSegment,\n} from \"livekit-client\";\n\nimport type { ConnectionState, IncomingChatMessage, IncomingTextStream, RpcInvocation, TranscriptionSegment, TransportAdapter } from \"@ringg/core\";\n\nimport { createAudioSession, type AudioSessionPort } from \"../platform/audio-session\";\nimport { findAgentParticipant, isAgentParticipant } from \"./agent\";\nimport { CHAT_TOPIC, LEGACY_CHAT_TOPIC, decodeLegacyChatMessage, encodeLegacyChatMessage, serverSupportsDataStreams } from \"./legacy-chat\";\n\nexport interface LiveKitTransportOptions {\n  /**\n   * Extra LiveKit `RoomOptions` merged over the parity defaults\n   * (`dynacast: true, adaptiveStream: true`). Rarely needed.\n   */\n  roomOptions?: RoomOptions;\n  /**\n   * Own the native audio session for the duration of a call — the mobile\n   * equivalent of production's `<RoomAudioRenderer />`. Default true; disable\n   * when the host app already manages an audio session (an in-app player, a\n   * CallKit/ConnectionService integration).\n   */\n  manageAudioSession?: boolean;\n  /**\n   * Call `registerGlobals()` before constructing the Room. Default true.\n   * Set false when the app already calls it at its entry point — it is\n   * idempotent, so this is a formality rather than a correctness switch.\n   */\n  registerGlobals?: boolean;\n}\n\nexport interface LiveKitTransport {\n  transport: TransportAdapter;\n  /**\n   * The underlying Room, for presentational concerns the port cannot express\n   * (visualizer track handles, `isMicrophoneEnabled` readback — spec §11).\n   * State-changing calls must keep going through the transport/core.\n   */\n  room: Room;\n  /** Tears down listeners, handlers and the audio session; disconnects the room. */\n  dispose(): void;\n}\n\n/** Production buffers 100 transcription segments; keep headroom past that. */\nconst FIRST_SEEN_LIMIT = 200;\n\nexport const createLiveKitTransport = (options: LiveKitTransportOptions = {}): LiveKitTransport => {\n  // Must precede `new Room()`: livekit-client resolves the WebRTC globals at\n  // construction time, and RN has none until this runs.\n  if (options.registerGlobals !== false) registerGlobals();\n\n  // Same construction as production (AppWrapper.tsx): one Room per widget\n  // lifetime, never recreated between calls.\n  const room = new Room({ dynacast: true, adaptiveStream: true, ...options.roomOptions });\n\n  const audioSession: AudioSessionPort | undefined = options.manageAudioSession === false ? undefined : createAudioSession();\n\n  const chatHandlers = new Set<(message: IncomingChatMessage) => void>();\n  const registeredRpcMethods = new Set<string>();\n  const registeredTextStreamTopics = new Set<string>();\n\n  // ─── Transcription first-seen timestamps ──────────────────────────────────\n  // The same segment id streams in repeatedly as STT refines; `receivedAt`\n  // must stay stable across refinements (production stamps wall-clock at\n  // first receipt and reuses it — segmentToChatMessage keeps the original\n  // timestamp). Bounded so a long call can't grow the map forever.\n  const firstSeenAt = new Map<string, number>();\n  const firstSeen = (id: string): number => {\n    const existing = firstSeenAt.get(id);\n    if (existing !== undefined) return existing;\n    const now = Date.now();\n    firstSeenAt.set(id, now);\n    if (firstSeenAt.size > FIRST_SEEN_LIMIT) {\n      const oldest = firstSeenAt.keys().next();\n      if (!oldest.done) firstSeenAt.delete(oldest.value);\n    }\n    return now;\n  };\n\n  // ─── Helpers ──────────────────────────────────────────────────────────────\n\n  /**\n   * livekit-client throws when a topic already has a handler — production\n   * re-registers across renders without hitting this because the hooks\n   * unregister on cleanup. The adapter makes registration idempotent instead.\n   */\n  const setTextStreamHandler = (topic: string, handler: TextStreamHandler): void => {\n    if (registeredTextStreamTopics.has(topic)) room.unregisterTextStreamHandler(topic);\n    room.registerTextStreamHandler(topic, handler);\n    registeredTextStreamTopics.add(topic);\n  };\n\n  const emitChat = (message: IncomingChatMessage): void => {\n    chatHandlers.forEach((handler) => handler(message));\n  };\n\n  /**\n   * Chat classification (App.tsx:1187–1191): identity match against the\n   * resolved agent; a non-self sender defaults to the agent while no agent\n   * participant is resolvable (production's `!isSelf` fallback).\n   */\n  const classifyRemoteAsAgent = (identity: string): boolean => {\n    const participant = room.getParticipantByIdentity(identity);\n    return participant ? isAgentParticipant(participant) : true;\n  };\n\n  const mapConnectionState = (state: LKConnectionState): ConnectionState => {\n    switch (state) {\n      case LKConnectionState.Connecting:\n        return \"connecting\";\n      case LKConnectionState.Connected:\n        return \"connected\";\n      case LKConnectionState.Reconnecting:\n      case LKConnectionState.SignalReconnecting:\n        // Core's union has no signal-reconnect notion — coerce (spec §9).\n        return \"reconnecting\";\n      case LKConnectionState.Disconnected:\n        return \"disconnected\";\n    }\n  };\n\n  // ─── Incoming chat (both channels, merged — components-core `setupChat`) ──\n\n  // Primary channel: `lk.chat` text streams. The server never loops a\n  // participant's own `sendText` back to them, and core commits the local\n  // echo itself, so only remote messages are surfaced (identity-guarded\n  // anyway for belt and braces). Emitting once per completed stream is the\n  // spec-sanctioned simplification of setupChat's chunked replace-by-id.\n  setTextStreamHandler(CHAT_TOPIC, (reader, participantInfo) => {\n    void (async () => {\n      let message: string;\n      try {\n        message = await reader.readAll();\n      } catch {\n        return; // stream aborted mid-flight — nothing to surface\n      }\n      const identity = participantInfo.identity;\n      if (identity === room.localParticipant.identity) return;\n      emitChat({\n        message,\n        isSelf: false,\n        isAgent: classifyRemoteAsAgent(identity),\n        senderName: room.getParticipantByIdentity(identity)?.name,\n        timestamp: reader.info.timestamp,\n      });\n    })();\n  });\n\n  // Legacy channel: `lk-chat-topic` data packets from old servers. Messages\n  // flagged `ignoreLegacy` were also sent as a text stream and are dropped\n  // here — that flag is the dedup between the two channels.\n  const handleDataReceived = (payload: Uint8Array, participant?: RemoteParticipant, _kind?: DataPacket_Kind, topic?: string): void => {\n    if (topic !== LEGACY_CHAT_TOPIC) return;\n    const legacy = decodeLegacyChatMessage(payload);\n    if (!legacy || legacy.ignoreLegacy) return;\n    // DataReceived only fires for remote senders; guard against echoes anyway.\n    if (participant && participant.identity === room.localParticipant.identity) return;\n    emitChat({\n      message: legacy.message,\n      isSelf: false,\n      isAgent: participant ? isAgentParticipant(participant) : true,\n      senderName: participant?.name,\n      timestamp: legacy.timestamp,\n    });\n  };\n  room.on(RoomEvent.DataReceived, handleDataReceived);\n\n  // Segment ids never survive a session; drop the timestamp cache with them,\n  // and hand the audio session back to the OS the moment the room drops —\n  // `destroy()` releasing the mic immediately is a release-blocking invariant.\n  const handleRoomDisconnected = (): void => {\n    firstSeenAt.clear();\n    void audioSession?.stop();\n  };\n  room.on(RoomEvent.Disconnected, handleRoomDisconnected);\n\n  // ─── TransportAdapter ─────────────────────────────────────────────────────\n\n  const transport: TransportAdapter = {\n    async connect(url: string, token: string): Promise<void> {\n      // The session is activated BEFORE connecting: acquiring it afterwards\n      // races the first inbound audio frame and clips the agent's greeting.\n      await audioSession?.start();\n      try {\n        // Default ConnectOptions, like production (autoSubscribe: true).\n        // Failures propagate — core rolls back its optimistic session phase.\n        await room.connect(url, token);\n      } catch (error) {\n        // Never leave the session held open by a connect that never landed.\n        await audioSession?.stop();\n        throw error;\n      }\n    },\n\n    async disconnect(): Promise<void> {\n      // Safe in every state: livekit no-ops when already disconnected, which\n      // covers the onSessionEnded → endCall() → disconnect() re-entry after\n      // a remote hangup (spec §11.8). `handleRoomDisconnected` releases the\n      // audio session on the way out.\n      await room.disconnect();\n    },\n\n    async prepareConnection(url: string): Promise<void> {\n      // Best-effort prewarm (App.tsx: `.catch(() => {})`) — a failure must\n      // never surface or block the later connect.\n      try {\n        await room.prepareConnection(url);\n      } catch {\n        /* best-effort only */\n      }\n    },\n\n    async setMicrophoneEnabled(enabled: boolean): Promise<void> {\n      // Handles track acquisition + publication; room.disconnect() tears the\n      // track down — no manual publish/unpublish anywhere (spec §2).\n      await room.localParticipant.setMicrophoneEnabled(enabled);\n    },\n\n    async sendChatMessage(text: string): Promise<void> {\n      // 1:1 with components-core `setupChat.send` — both sends, same order.\n      // Core commits the local echo; nothing is emitted via onChatMessage.\n      const info = await room.localParticipant.sendText(text, { topic: CHAT_TOPIC });\n      await room.localParticipant.publishData(\n        encodeLegacyChatMessage({\n          id: info.id,\n          timestamp: Date.now(),\n          message: text,\n          ignoreLegacy: serverSupportsDataStreams(room),\n        }),\n        { reliable: true, topic: LEGACY_CHAT_TOPIC },\n      );\n    },\n\n    async performRpcToAgent(method: string, payload: string): Promise<string> {\n      const agent = findAgentParticipant(room);\n      if (!agent) {\n        // Port contract: reject when no agent is present — core catches per\n        // call-site (production warns + skips there).\n        throw new Error(`Cannot perform RPC \"${method}\": no agent participant in the room`);\n      }\n      return room.localParticipant.performRpc({\n        destinationIdentity: agent.identity,\n        method,\n        payload,\n      });\n    },\n\n    registerRpcMethod(method: string, handler: (invocation: RpcInvocation) => Promise<string>): void {\n      // livekit throws on duplicate registration — keep it idempotent.\n      if (registeredRpcMethods.has(method)) room.unregisterRpcMethod(method);\n      room.registerRpcMethod(method, (data: RpcInvocationData) =>\n        // Handler rejections must propagate: livekit surfaces non-RpcError\n        // throws to the caller as RPC application error 1500 (spec §4).\n        handler({ method, payload: data.payload, callerIdentity: data.callerIdentity }),\n      );\n      registeredRpcMethods.add(method);\n    },\n\n    unregisterRpcMethod(method: string): void {\n      room.unregisterRpcMethod(method);\n      registeredRpcMethods.delete(method);\n    },\n\n    registerTextStreamHandler(topic: string, handler: (stream: IncomingTextStream) => void): void {\n      // Callable pre-connect (required: late `lk.transcription` registration\n      // drops the agent greeting). Note: registering `lk.chat` here replaces\n      // the adapter's internal chat wiring — core never does.\n      setTextStreamHandler(topic, (reader, participantInfo) => {\n        handler({\n          readAll: () => reader.readAll(),\n          participantIdentity: participantInfo.identity,\n          isAgent: classifyRemoteAsAgent(participantInfo.identity),\n        });\n      });\n    },\n\n    unregisterTextStreamHandler(topic: string): void {\n      room.unregisterTextStreamHandler(topic);\n      registeredTextStreamTopics.delete(topic);\n    },\n\n    onConnectionStateChange(handler: (state: ConnectionState) => void): () => void {\n      const listener = (state: LKConnectionState): void => {\n        handler(mapConnectionState(state));\n      };\n      room.on(RoomEvent.ConnectionStateChanged, listener);\n      return () => {\n        room.off(RoomEvent.ConnectionStateChanged, listener);\n      };\n    },\n\n    onSessionEnded(handler: () => void): () => void {\n      // Production registers BOTH and never checks identity/kind: any remote\n      // participant leaving ends the call (only the agent is ever remote),\n      // and so does the room dropping (spec §1.4). Consumers guard their own\n      // idempotency (core: `if (session.isSessionLive)`).\n      const handleParticipantDisconnected = (_participant: RemoteParticipant): void => {\n        handler();\n      };\n      const handleDisconnected = (): void => {\n        handler();\n      };\n      room.on(RoomEvent.ParticipantDisconnected, handleParticipantDisconnected);\n      room.on(RoomEvent.Disconnected, handleDisconnected);\n      return () => {\n        room.off(RoomEvent.ParticipantDisconnected, handleParticipantDisconnected);\n        room.off(RoomEvent.Disconnected, handleDisconnected);\n      };\n    },\n\n    onTranscription(handler: (segment: TranscriptionSegment) => void): () => void {\n      const listener = (segments: LKTranscriptionSegment[], participant?: Participant): void => {\n        if (!participant) return;\n        const isLocal = participant.isLocal;\n        // Production only renders local + agent transcription (spec §8).\n        if (!isLocal && !isAgentParticipant(participant)) return;\n        for (const segment of segments) {\n          handler({\n            id: segment.id,\n            text: segment.text,\n            final: segment.final,\n            isLocal,\n            participantName: participant.name,\n            receivedAt: firstSeen(segment.id),\n          });\n        }\n      };\n      room.on(RoomEvent.TranscriptionReceived, listener);\n      return () => {\n        room.off(RoomEvent.TranscriptionReceived, listener);\n      };\n    },\n\n    onChatMessage(handler: (message: IncomingChatMessage) => void): () => void {\n      chatHandlers.add(handler);\n      return () => {\n        chatHandlers.delete(handler);\n      };\n    },\n\n    onMediaDevicesError(handler: () => void): () => void {\n      // Production's use-microphone-permission.ts listens for this to surface\n      // the \"Error acquiring microphone permission...\" message; core's session\n      // store owns that copy now.\n      const listener = (): void => {\n        handler();\n      };\n      room.on(RoomEvent.MediaDevicesError, listener);\n      return () => {\n        room.off(RoomEvent.MediaDevicesError, listener);\n      };\n    },\n  };\n\n  const dispose = (): void => {\n    room.off(RoomEvent.DataReceived, handleDataReceived);\n    room.off(RoomEvent.Disconnected, handleRoomDisconnected);\n    for (const topic of Array.from(registeredTextStreamTopics)) {\n      room.unregisterTextStreamHandler(topic);\n    }\n    registeredTextStreamTopics.clear();\n    for (const method of Array.from(registeredRpcMethods)) {\n      room.unregisterRpcMethod(method);\n    }\n    registeredRpcMethods.clear();\n    chatHandlers.clear();\n    firstSeenAt.clear();\n    // Disconnect first so the mic track is torn down before the OS session is\n    // released — the reverse order leaves the recording indicator lit.\n    void room.disconnect().finally(() => audioSession?.stop());\n  };\n\n  return { transport, room, dispose };\n};\n","/**\n * Native audio session — React Native's replacement for the web adapter's\n * hidden `<audio>` elements.\n *\n * On web, remote audio needs a DOM element to play into. On mobile it needs\n * the opposite: nothing to attach, but an OS-level audio session that has to\n * be configured and activated before the call and released after it, or the\n * mic indicator stays lit and the app keeps ducking other audio.\n *\n * The configuration encodes the mobile audio invariants (AGENTS.md rule 10):\n * communication mode so the call survives backgrounding and routes through the\n * earpiece/bluetooth stack rather than the media stream, and a preferred\n * output list that follows a headset or bluetooth device when one appears.\n *\n * Every call is best-effort. A device that refuses to hand over the audio\n * session must not take the call down with it — the user still gets a\n * (possibly routed-oddly) conversation, which beats a hard failure.\n */\n\nimport { AndroidAudioTypePresets, AudioSession } from \"@livekit/react-native\";\n\nexport interface AudioSessionPort {\n  /** Configure + activate. Safe to call repeatedly; only the first wins. */\n  start(): Promise<void>;\n  /** Release the session. Safe to call when never started. */\n  stop(): Promise<void>;\n}\n\n/**\n * Routing preference, most to least specific. Bluetooth and wired headsets\n * win when present; speaker is the fallback for a voice widget the user is\n * holding at arm's length, and the earpiece is last.\n */\nconst PREFERRED_OUTPUTS = [\"bluetooth\", \"headset\", \"speaker\", \"earpiece\"] as const;\n\nexport const createAudioSession = (): AudioSessionPort => {\n  let active = false;\n\n  const start = async (): Promise<void> => {\n    if (active) return;\n    // Optimistic: mark active before awaiting so two overlapping connects\n    // cannot both configure the session (the second would fight the first).\n    active = true;\n    try {\n      await AudioSession.configureAudio({\n        android: {\n          audioTypeOptions: AndroidAudioTypePresets.communication,\n          preferredOutputList: [...PREFERRED_OUTPUTS],\n        },\n        ios: { defaultOutput: \"speaker\" },\n      });\n      await AudioSession.startAudioSession();\n    } catch {\n      // Session refused — the call still connects; routing falls back to\n      // whatever the OS had configured.\n    }\n  };\n\n  const stop = async (): Promise<void> => {\n    if (!active) return;\n    active = false;\n    try {\n      await AudioSession.stopAudioSession();\n    } catch {\n      /* nothing left to release */\n    }\n  };\n\n  return { start, stop };\n};\n","/**\n * Legacy chat wire format — the `lk-chat-topic` data channel that predates\n * LiveKit text streams. Mirrors `setupChat` in @livekit/components-core\n * 0.12.2 (agents-cdn's pinned `useChat` internals), byte-identical to the web\n * adapter's copy in `web/src/transport/legacy-chat.ts`:\n *\n *  - every send goes out twice — once as a text stream on `lk.chat`, once as\n *    a reliable data packet on `lk-chat-topic` for old servers;\n *  - `ignoreLegacy` is the dedup: when the server supports data streams the\n *    legacy copy is stamped `ignoreLegacy: true` and receivers on the legacy\n *    channel drop it, so nobody sees the message twice.\n *\n * The wire shape is duplicated rather than shared because `@ringg/core` may\n * never import a LiveKit SDK (AGENTS.md rule 2) — the same reason the Dart\n * port carries its own copy. Only the codec differs from web: RN has no\n * ambient TextEncoder, so it goes through `lib/utf8`.\n */\n\nimport { compareVersions, type Room } from \"livekit-client\";\n\nimport { decodeUtf8, encodeUtf8 } from \"../lib/utf8\";\n\n/** Text-stream chat topic (`DataTopic.CHAT` in components-core). */\nexport const CHAT_TOPIC = \"lk.chat\";\n\n/** Legacy data-channel chat topic (`LegacyDataTopic.CHAT`). */\nexport const LEGACY_CHAT_TOPIC = \"lk-chat-topic\";\n\nexport interface LegacyChatMessage {\n  id: string;\n  timestamp: number;\n  message: string;\n  /** True when the sender also sent the message as a text stream. */\n  ignoreLegacy?: boolean;\n}\n\n/**\n * `serverSupportsDataStreams` from components-core: LiveKit Cloud\n * (`edition === 1`) or self-hosted newer than 1.8.2 delivers text streams,\n * so the legacy copy can be flagged for receivers to ignore.\n */\nexport const serverSupportsDataStreams = (room: Room): boolean => room.serverInfo?.edition === 1 || (!!room.serverInfo?.version && compareVersions(room.serverInfo.version, \"1.8.2\") > 0);\n\nexport const encodeLegacyChatMessage = (message: LegacyChatMessage): Uint8Array<ArrayBuffer> => encodeUtf8(JSON.stringify(message));\n\n/** Returns `undefined` for payloads that aren't legacy chat messages. */\nexport const decodeLegacyChatMessage = (payload: Uint8Array): LegacyChatMessage | undefined => {\n  try {\n    // Wire boundary: the payload is attacker-influenced JSON, so every field\n    // is re-checked below before it becomes a LegacyChatMessage.\n    const parsed: unknown = JSON.parse(decodeUtf8(payload));\n    if (typeof parsed !== \"object\" || parsed === null) return undefined;\n    const candidate = parsed as Partial<LegacyChatMessage>;\n    if (typeof candidate.message !== \"string\") return undefined;\n    return {\n      id: typeof candidate.id === \"string\" ? candidate.id : \"\",\n      timestamp: typeof candidate.timestamp === \"number\" ? candidate.timestamp : Date.now(),\n      message: candidate.message,\n      ignoreLegacy: candidate.ignoreLegacy === true,\n    };\n  } catch {\n    return undefined;\n  }\n};\n","/**\n * UTF-8 codec for the data-channel wire.\n *\n * The web transport uses the ambient `TextEncoder`/`TextDecoder`. On React\n * Native those are not engine globals — they arrive as a polyfill imported by\n * `@livekit/react-native`, so they exist at runtime in a correctly-wired app\n * but cannot be relied on at the type level, and are absent entirely in unit\n * tests that never touch the SDK.\n *\n * So: use the platform's codec when it is there (it is faster and battle-\n * tested) and fall back to an explicit implementation otherwise. Chat payloads\n * carry real user text — emoji, Indic scripts, CJK — so a Latin-1 shortcut\n * would corrupt messages rather than merely slow them down.\n */\n\n// `Uint8Array<ArrayBuffer>` rather than the default `ArrayBufferLike`: livekit's\n// `publishData` will not accept a possibly-shared buffer.\ntype Utf8Encoder = { encode(input: string): Uint8Array<ArrayBuffer> };\ntype Utf8Decoder = { decode(input: Uint8Array): string };\n\n// Reading optional globals off globalThis is the whole point of this module;\n// the shapes are checked before use, which is why the casts are safe.\nconst globalEncoder = (globalThis as { TextEncoder?: new () => Utf8Encoder }).TextEncoder;\nconst globalDecoder = (globalThis as { TextDecoder?: new () => Utf8Decoder }).TextDecoder;\n\nconst CONTINUATION = 0b1000_0000;\n\nconst encodeCodePoint = (code: number, out: number[]): void => {\n  if (code < 0x80) {\n    out.push(code);\n    return;\n  }\n  if (code < 0x800) {\n    out.push(0xc0 | (code >> 6), CONTINUATION | (code & 0x3f));\n    return;\n  }\n  if (code < 0x10000) {\n    out.push(0xe0 | (code >> 12), CONTINUATION | ((code >> 6) & 0x3f), CONTINUATION | (code & 0x3f));\n    return;\n  }\n  out.push(0xf0 | (code >> 18), CONTINUATION | ((code >> 12) & 0x3f), CONTINUATION | ((code >> 6) & 0x3f), CONTINUATION | (code & 0x3f));\n};\n\n/** `for...of` walks code points, so surrogate pairs survive as one character. */\nconst encodeFallback = (value: string): Uint8Array<ArrayBuffer> => {\n  const bytes: number[] = [];\n  for (const character of value) {\n    encodeCodePoint(character.codePointAt(0) ?? 0, bytes);\n  }\n  return Uint8Array.from(bytes);\n};\n\n/** Byte length of the sequence a lead byte opens; 1 for anything malformed. */\nconst sequenceLength = (lead: number): number => {\n  if (lead < 0x80) return 1;\n  if (lead >= 0xf0) return 4;\n  if (lead >= 0xe0) return 3;\n  if (lead >= 0xc0) return 2;\n  return 1;\n};\n\nconst LEAD_MASKS = [0, 0x7f, 0x1f, 0x0f, 0x07] as const;\n\nconst decodeFallback = (bytes: Uint8Array): string => {\n  let result = \"\";\n  let index = 0;\n  while (index < bytes.length) {\n    const lead = bytes[index] ?? 0;\n    const length = Math.min(sequenceLength(lead), bytes.length - index);\n    let code = lead & (LEAD_MASKS[length] ?? 0x7f);\n    for (let offset = 1; offset < length; offset++) {\n      code = (code << 6) | ((bytes[index + offset] ?? 0) & 0x3f);\n    }\n    result += String.fromCodePoint(code);\n    index += length;\n  }\n  return result;\n};\n\nexport const encodeUtf8 = (value: string): Uint8Array<ArrayBuffer> => (globalEncoder ? new globalEncoder().encode(value) : encodeFallback(value));\n\nexport const decodeUtf8 = (bytes: Uint8Array): string => (globalDecoder ? new globalDecoder().decode(bytes) : decodeFallback(bytes));\n","/**\n * React Native `MicPermissionPort`.\n *\n * Core's session store drives this on audio start: `isGranted()` first, then\n * `request()`, aborting the call on denial — identical to web. What differs is\n * how the answer is obtained, and the two platforms genuinely differ:\n *\n *  - Android exposes a real permission API, so the state can be READ without\n *    prompting. That matters: `isGranted()` must never show a dialog, or the\n *    user gets prompted before they have pressed anything.\n *  - iOS has no readable pre-check from JS. The only probe is `getUserMedia`,\n *    which prompts on first use — the same fallback the web port uses for\n *    browsers without the Permissions API. Once answered, iOS resolves the\n *    probe from its own record without prompting again.\n *\n * The probe must never keep the microphone: every track it opens is stopped\n * before returning, or the OS recording indicator stays lit before the call\n * has even started.\n */\n\nimport { PermissionsAndroid, Platform } from \"react-native\";\nimport { mediaDevices } from \"@livekit/react-native-webrtc\";\nimport type { MicPermissionPort } from \"@ringg/core\";\n\n/** Minimal shape of what `getUserMedia` hands back — enough to release it. */\ninterface ProbeStream {\n  getTracks(): { stop(): void }[];\n}\n\nconst stopTracks = (stream: ProbeStream): void => {\n  stream.getTracks().forEach((track) => track.stop());\n};\n\n/** Opens and immediately releases an audio track. True when it was allowed. */\nconst probeMicrophone = async (): Promise<boolean> => {\n  try {\n    const stream = (await mediaDevices.getUserMedia({ audio: true })) as unknown as ProbeStream;\n    stopTracks(stream);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\n/**\n * Android's rationale copy. Shown only when the user has denied once before —\n * Android decides, not us.\n */\nconst ANDROID_RATIONALE = {\n  title: \"Microphone access\",\n  message: \"Voice calls need the microphone to hear you.\",\n  buttonPositive: \"Allow\",\n  buttonNegative: \"Not now\",\n} as const;\n\nexport const createNativeMicPermission = (): MicPermissionPort => ({\n  async isGranted(): Promise<boolean> {\n    if (Platform.OS === \"android\") {\n      // `check` is a pure read — no dialog, which is the whole point.\n      return PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO);\n    }\n    // iOS/others: no readable state, so this doubles as the request. Core\n    // calls `request()` right after a false, which is then a cheap no-op.\n    return probeMicrophone();\n  },\n\n  async request(): Promise<boolean> {\n    if (Platform.OS === \"android\") {\n      const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, ANDROID_RATIONALE);\n      // `never_ask_again` is a denial as far as this call goes; core surfaces\n      // the start-screen error and the user has to fix it in Settings.\n      return result === PermissionsAndroid.RESULTS.GRANTED;\n    }\n    return probeMicrophone();\n  },\n});\n","/**\n * App identity for the backend's caller allow-list.\n *\n * The Ringg backend allow-lists an agent's callers by `Origin`. A browser\n * attaches it automatically; a native app sends nothing, so it has to present\n * its own identity — by convention `<platform>://<bundleId>`, the scheme the\n * backend accepts for app clients. Without it the webcall request is rejected\n * before authentication even matters (`400 Origin header is required`).\n *\n * The bundle id is the INTEGRATOR's, not ours, so the value allow-listed in\n * the dashboard is their app. React Native cannot read it without a native\n * module, and this package refuses to grow one for a single string — so the id\n * is a parameter. Expo apps have it in `expo-application`'s `applicationId`;\n * bare apps already know their own.\n *\n * Mirrors `flutter/lib/src/platform/app_origin.dart`, which derives the same\n * string from `package_info_plus`.\n */\n\nimport { Platform } from \"react-native\";\n\n/** Schemes the backend accepts, keyed by `Platform.OS`. */\nconst SCHEMES: Partial<Record<typeof Platform.OS, string>> = {\n  android: \"android\",\n  ios: \"ios\",\n  macos: \"macos\",\n  windows: \"windows\",\n};\n\n/**\n * `<platform>://<bundleId>` for the running app — e.g. `android://com.acme.app`.\n *\n * Returns undefined on a platform the backend has no scheme for, which\n * includes react-native-web: there the browser sends a real `Origin` and\n * setting one from JavaScript is forbidden anyway.\n */\nexport const appOrigin = (bundleId: string): string | undefined => {\n  const scheme = SCHEMES[Platform.OS];\n  if (!scheme || !bundleId) return undefined;\n  return `${scheme}://${bundleId}`;\n};\n","/**\n * React Native `NotificationPlayer`.\n *\n * Core decides WHEN to play (an agent reply or component landing while the\n * widget is closed); the port only owns the how. On web that is one line —\n * `new Audio(url)`. RN has no audio playback in the platform at all: every\n * option (expo-audio, react-native-sound, react-native-video) is a native\n * module, and forcing one on integrators would mean an extra pod/gradle\n * dependency and an Expo config plugin for a notification chime.\n *\n * So the decision is inverted: the widget ships silent by default and the\n * integrator opts in with three lines against whichever player their app\n * already has. `notificationTuneUrl` from the config is handed to that player,\n * so the URL stays a config concern on every platform.\n */\n\nimport type { NotificationPlayer } from \"@ringg/core\";\n\n/** What an integrator's audio library has to be able to do. */\nexport type PlayTune = (tuneUrl: string) => void;\n\n/**\n * The default. Silent, and deliberately so — a widget that cannot find an\n * audio library should be quiet, not noisy about it on every reply.\n */\nexport const createSilentNotificationPlayer = (): NotificationPlayer => ({\n  play() {\n    /* no audio backend wired — see createNotificationPlayer */\n  },\n});\n\n/**\n * Bridges the config's tune URL to a host-provided player.\n *\n * ```ts\n * import { createAudioPlayer } from \"expo-audio\";\n * const notifications = createNotificationPlayer(DEFAULT_CONFIG.notificationTuneUrl, (url) => createAudioPlayer(url).play());\n * ```\n *\n * Playback failures are swallowed: a chime is best-effort by contract, and a\n * rejected promise here must never surface mid-conversation.\n */\nexport const createNotificationPlayer = (tuneUrl: string, playTune: PlayTune): NotificationPlayer => ({\n  play() {\n    try {\n      playTune(tuneUrl);\n    } catch {\n      /* best-effort by contract */\n    }\n  },\n});\n","/**\n * Host action dispatcher — the React Native counterpart of the web widget's\n * `executeDomAction`.\n *\n * Core normalises the `execute_dom_action` RPC into a `DomAction` and hands it\n * to the `onDomAction` port. On web that ends in `window.dispatchEvent`, which\n * works because the host page is already an event bus. RN has no such ambient\n * bus, so the integrator supplies the handler and gets the event name plus the\n * payload the agent sent — the same `{...default_payload, action_id}` detail\n * the web CustomEvent carries, so a shared backend config drives both.\n *\n * Validation, logging and the \"unknown kind\" path stay identical to web: those\n * are contract behaviour, not platform detail.\n */\n\nimport type { DomAction, DomActionLogEntry, DomActionLogger } from \"@ringg/core\";\n\n/** What the host receives — the web CustomEvent, minus the DOM. */\nexport interface HostAction {\n  /** The agent-configured event name (`CustomEvent.type` on web). */\n  name: string;\n  /** `default_payload` with the action id folded in (`CustomEvent.detail`). */\n  payload: Record<string, unknown>;\n}\n\nexport type HostActionHandler = (action: HostAction) => void;\n\nconst warn = (...args: unknown[]): void => {\n  console.warn(\"[HOST_ACTION]\", ...args);\n};\n\n/**\n * Builds the `onDomAction` port. `onAction` runs in the caller's context and\n * is allowed to throw — a broken host handler is reported, never fatal.\n */\nexport const createHostActionDispatcher =\n  (onAction: HostActionHandler) =>\n  (action: DomAction | undefined | null, onLog?: DomActionLogger): void => {\n    const emit = (entry: DomActionLogEntry): void => {\n      try {\n        onLog?.(entry);\n      } catch (error) {\n        warn(\"logger threw\", error);\n      }\n    };\n\n    if (!action || typeof action !== \"object\") {\n      warn(\"Missing or invalid action config\");\n      emit({ label: \"Invalid action\", level: \"error\" });\n      return;\n    }\n\n    const { id, kind } = action;\n\n    if (kind !== \"trigger_event\") {\n      warn(`[${id}] unknown kind`, kind);\n      emit({ id, label: \"Unknown kind\", meta: String(kind), level: \"error\" });\n      return;\n    }\n\n    if (!action.event_name) {\n      warn(`[${id}] trigger_event missing event_name`);\n      emit({ id, label: \"Event missing name\", level: \"error\" });\n      return;\n    }\n\n    try {\n      onAction({ name: action.event_name, payload: { ...(action.default_payload ?? {}), action_id: id } });\n      emit({ id, label: \"Triggered\", meta: action.event_name, level: \"info\" });\n    } catch (error) {\n      warn(`[${id}] execution failed`, error);\n      emit({ id, label: \"Action failed\", level: \"error\" });\n    }\n  };\n"],"mappings":"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","names":["Fragment","useEffect","useMemo","useRef","useState","Animated","Image","KeyboardAvoidingView","Platform","ScrollView","StyleSheet","Text","View","StyleSheet","Svg","jsx","jsxs","jsx","Svg","jsxs","Svg","jsx","styles","jsx","StyleSheet","jsx","styles","jsx","jsxs","styles","StyleSheet","useState","StyleSheet","View","useMemo","StyleSheet","View","StyleSheet","Text","View","jsx","jsxs","View","styles","Text","StyleSheet","jsx","jsxs","PILL_RADIUS","useMemo","View","styles","StyleSheet","jsx","jsxs","ICON_SIZE","View","styles","useState","StyleSheet","useMemo","useRef","useState","Animated","KeyboardAvoidingView","Platform","ScrollView","StyleSheet","Text","TextInput","View","Svg","Path","StyleSheet","Text","View","jsx","jsxs","View","styles","Text","StyleSheet","useCallback","useEffect","useMemo","useRef","useState","Animated","StyleSheet","Text","View","Check","PILL_RADIUS","toNumber","getButtonRadius","useEffect","useMemo","useRef","useState","Animated","Easing","StyleSheet","Text","View","jsx","jsxs","useRef","Animated","useEffect","Easing","useMemo","useState","Text","styles","View","StyleSheet","useEffect","useMemo","useRef","useState","Animated","Easing","StyleSheet","Text","View","LoaderCircle","Fragment","jsx","jsxs","SPIN_DURATION_MS","useMemo","Spinner","useRef","Animated","useEffect","Easing","LoaderCircle","getButtonRadius","useState","View","styles","Text","StyleSheet","useEffect","useRef","Animated","StyleSheet","Text","View","Calendar","Clock","jsx","jsxs","useRef","Animated","useEffect","Calendar","Clock","styles","View","StyleSheet","Text","useEffect","useMemo","useRef","useState","Animated","Easing","ScrollView","StyleSheet","Text","TextInput","View","Calendar","Check","LoaderCircle","Mail","Fragment","jsx","jsxs","SPIN_DURATION_MS","Mail","Calendar","useStepTheme","useMemo","toNumber","Spinner","useRef","Animated","useEffect","Easing","LoaderCircle","styles","Check","Text","useState","View","TextInput","getButtonRadius","ScrollView","StyleSheet","useEffect","useRef","useState","Animated","Easing","jsx","jsx","jsxs","ENTER_DURATION_MS","useRef","Animated","useEffect","useMemo","useState","useCallback","styles","toNumber","View","StyleSheet","Check","Text","Linking","StyleSheet","Text","View","Fragment","useMemo","Linking","Platform","StyleSheet","Text","View","jsx","jsxs","styles","jsx","jsxs","LINE_HEIGHT_RATIO","View","Text","styles","StyleSheet","Linking","Calendar","Check","ChevronDown","Clock","createContext","useContext","useEffect","useMemo","useRef","useState","Animated","Image","Linking","ScrollView","StyleSheet","Text","TextInput","View","Svg","Path","Fragment","jsx","jsxs","PULSE_HALF_CYCLE_MS","PULSE_MIN_OPACITY","createContext","useContext","useMemo","openExternalUrl","Linking","View","styles","Svg","Path","Text","useState","ChevronDown","toNumber","Check","useRef","Animated","useEffect","Image","StyleSheet","TextInput","Calendar","Clock","ScrollView","jsx","jsxs","useRef","Animated","styles","Svg","Path","useState","useMemo","View","ScrollView","Text","KeyboardAvoidingView","Platform","TextInput","StyleSheet","useEffect","useRef","useState","Animated","Easing","StyleSheet","View","jsx","Easing","PILL_RADIUS","useState","useRef","Animated","useEffect","View","styles","StyleSheet","Platform","StyleSheet","Text","View","jsx","jsxs","Platform","View","styles","Text","StyleSheet","useEffect","useRef","useState","Animated","StyleSheet","Text","View","jsx","jsxs","Animated","useRef","useEffect","styles","useState","View","Text","StyleSheet","useEffect","useState","StyleSheet","useCallback","useEffect","useMemo","useRef","useState","Animated","StyleSheet","View","jsx","useState","useCallback","useEffect","useRef","Animated","styles","View","useMemo","StyleSheet","jsx","useState","useEffect","styles","StyleSheet","useEffect","useRef","Animated","StyleSheet","Text","View","StyleSheet","Text","View","jsx","Text","styles","View","StyleSheet","jsx","jsxs","SCRIM_OPACITY","CARD_ENTER_OFFSET","useRef","Animated","useEffect","View","styles","StyleSheet","Text","useCallback","useEffect","useState","RoomEvent","useEffect","useRef","useState","Animated","Fragment","Linking","Text","jsx","openUrl","Fragment","jsx","jsxs","useState","useMemo","useRef","useEffect","styles","ScrollView","View","Text","StyleSheet","KeyboardAvoidingView","Platform","Animated","Image","RoomEvent","RoomEvent","Platform","Platform"]}