(function (deckyFrontendLib, React) {
    'use strict';

    function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

    var React__default = /*#__PURE__*/_interopDefaultLegacy(React);

    var _manifest = {"name":"Decktation","version":"0.3.10","author":"silverfoxy","flags":["_root"],"api_version":1,"publish":{"tags":["voice","dictation","speech-to-text","input","chat","gaming","accessibility"],"description":"Push-to-talk dictation for Steam Deck. Context-aware speech-to-text using faster-whisper.","image":"https://raw.githubusercontent.com/silverfoxy/decktation/master/logo.png"}};

    const manifest = _manifest;
    const API_VERSION = 2;
    if (!manifest?.name) {
        throw new Error('[@decky/api]: Failed to find plugin manifest.');
    }
    const internalAPIConnection = window.__DECKY_SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED_deckyLoaderAPIInit;
    if (!internalAPIConnection) {
        throw new Error('[@decky/api]: Failed to connect to the loader as as the loader API was not initialized. This is likely a bug in Decky Loader.');
    }
    let api;
    try {
        api = internalAPIConnection.connect(API_VERSION, manifest.name);
    }
    catch {
        api = internalAPIConnection.connect(1, manifest.name);
        console.warn(`[@decky/api] Requested API version ${API_VERSION} but the running loader only supports version 1. Some features may not work.`);
    }
    if (api._version != API_VERSION) {
        console.warn(`[@decky/api] Requested API version ${API_VERSION} but the running loader only supports version ${api._version}. Some features may not work.`);
    }
    api.call;
    const callable = api.callable;
    api.addEventListener;
    api.removeEventListener;
    api.routerHook;
    const toaster = api.toaster;
    api.openFilePicker;
    api.executeInTab;
    api.injectCssIntoTab;
    api.removeCssFromTab;
    api.fetchNoCors;
    api.getExternalResourceURL;
    api.useQuickAccessVisible;

    var DefaultContext = {
      color: undefined,
      size: undefined,
      className: undefined,
      style: undefined,
      attr: undefined
    };
    var IconContext = React__default["default"].createContext && React__default["default"].createContext(DefaultContext);

    var __assign = window && window.__assign || function () {
      __assign = Object.assign || function (t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
          s = arguments[i];
          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
        }
        return t;
      };
      return __assign.apply(this, arguments);
    };
    var __rest = window && window.__rest || function (s, e) {
      var t = {};
      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
      if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
        if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
      }
      return t;
    };
    function Tree2Element(tree) {
      return tree && tree.map(function (node, i) {
        return React__default["default"].createElement(node.tag, __assign({
          key: i
        }, node.attr), Tree2Element(node.child));
      });
    }
    function GenIcon(data) {
      // eslint-disable-next-line react/display-name
      return function (props) {
        return React__default["default"].createElement(IconBase, __assign({
          attr: __assign({}, data.attr)
        }, props), Tree2Element(data.child));
      };
    }
    function IconBase(props) {
      var elem = function (conf) {
        var attr = props.attr,
          size = props.size,
          title = props.title,
          svgProps = __rest(props, ["attr", "size", "title"]);
        var computedSize = size || conf.size || "1em";
        var className;
        if (conf.className) className = conf.className;
        if (props.className) className = (className ? className + " " : "") + props.className;
        return React__default["default"].createElement("svg", __assign({
          stroke: "currentColor",
          fill: "currentColor",
          strokeWidth: "0"
        }, conf.attr, attr, svgProps, {
          className: className,
          style: __assign(__assign({
            color: props.color || conf.color
          }, conf.style), props.style),
          height: computedSize,
          width: computedSize,
          xmlns: "http://www.w3.org/2000/svg"
        }), title && React__default["default"].createElement("title", null, title), props.children);
      };
      return IconContext !== undefined ? React__default["default"].createElement(IconContext.Consumer, null, function (conf) {
        return elem(conf);
      }) : elem(DefaultContext);
    }

    // THIS FILE IS AUTO GENERATED
    function FaCircle (props) {
      return GenIcon({"tag":"svg","attr":{"viewBox":"0 0 512 512"},"child":[{"tag":"path","attr":{"d":"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z"}}]})(props);
    }function FaMicrophone (props) {
      return GenIcon({"tag":"svg","attr":{"viewBox":"0 0 352 512"},"child":[{"tag":"path","attr":{"d":"M176 352c53.02 0 96-42.98 96-96V96c0-53.02-42.98-96-96-96S80 42.98 80 96v160c0 53.02 42.98 96 96 96zm160-160h-16c-8.84 0-16 7.16-16 16v48c0 74.8-64.49 134.82-140.79 127.38C96.71 376.89 48 317.11 48 250.3V208c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v40.16c0 89.64 63.97 169.55 152 181.69V464H96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16h-56v-33.77C285.71 418.47 352 344.9 352 256v-48c0-8.84-7.16-16-16-16z"}}]})(props);
    }function FaTrash (props) {
      return GenIcon({"tag":"svg","attr":{"viewBox":"0 0 448 512"},"child":[{"tag":"path","attr":{"d":"M432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zM53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32z"}}]})(props);
    }

    const getStatus = callable("get_status");
    const getButtonConfig = callable("get_button_config");
    const getPresets = callable("get_presets");
    const setEnabledRpc = callable("set_enabled");
    const loadModel = callable("load_model");
    const startRecording = callable("start_recording");
    const stopRecording = callable("stop_recording");
    const getLastTranscription = callable("get_last_transcription");
    const setConfirmModeRpc = callable("set_confirm_mode");
    const setManualSendRpc = callable("set_manual_send");
    const setShareDiagnosticsRpc = callable("set_share_diagnostics");
    const setActivePresetRpc = callable("set_active_preset");
    const setModelSizeRpc = callable("set_model_size");
    const setTranscriptionOptionsRpc = callable("set_transcription_options");
    const setButtonConfig = callable("set_button_config");
    // Button IDs emitted by SteamClient.Input.RegisterForControllerInputMessages.
    // These match Steam's ControllerInputGamepadButton enum as observed by the
    // button-test callback. Keep the rear buttons in physical left-to-right order.
    const CONTROLLER_BUTTON_NAMES = {
        0: "A",
        1: "B",
        2: "X",
        3: "Y",
        26: "L2",
        27: "R2",
        28: "L2",
        29: "R2",
        30: "L1",
        31: "R1",
        32: "L5",
        33: "R5",
        44: "L4",
        45: "R4",
    };
    // L5 = bit 15, R5 = bit 16 in ulButtons (same as antiquitte/decky-dictation)
    const L5_MASK = 1 << 15;
    class DecktationLogic {
        constructor() {
            this.enabled = false;
            this.recording = false;
            this.lastButtonState = "None";
            this.inputRegistered = false;
            this.inputError = "";
            this.onButtonChange = null;
            this.l5Held = false;
            this.showNotifications = true;
            this.prevRecordingStartCount = 0;
            this.prevPendingText = "";
            this.lastPendingToastId = -1;
            this.notify = async (message, duration = 2000, body = "") => {
                if (!body) {
                    body = message;
                }
                const toast = {
                    title: message,
                    body: body,
                    duration: duration,
                    critical: false,
                };
                const id = window.NotificationStore ? window.NotificationStore.m_nNextTestNotificationID++ : 0;
                const toastData = {
                    nNotificationID: id,
                    bNewIndicator: false,
                    rtCreated: Date.now(),
                    eType: 43,
                    eSource: 1,
                    nToastDurationMS: duration,
                    data: toast,
                    decky: true,
                };
                const info = {
                    showToast: true,
                    sound: 6,
                    playSound: false,
                    eFeature: 0,
                    toastDurationMS: duration,
                    bCritical: false,
                    fnTray: (_t, tray) => { tray.unshift({ eType: 31, notifications: [toastData] }); },
                };
                try {
                    window.NotificationStore.ProcessNotification(info, toastData, 0);
                }
                catch (_e) {
                    // fallback to standard toaster if direct call fails
                    toaster.toast({ title: message, body: toast.body, duration: duration, critical: false });
                }
                return id;
            };
            this.dismissNotification = (id) => {
                // Force-expire the toast by reprocessing it with a 1ms duration
                try {
                    const toastData = {
                        nNotificationID: id,
                        bNewIndicator: false,
                        rtCreated: Date.now(),
                        eType: 43,
                        eSource: 1,
                        nToastDurationMS: 1,
                        data: { title: "", body: "", duration: 1, critical: false },
                        decky: true,
                    };
                    const info = {
                        showToast: true,
                        sound: 6,
                        playSound: false,
                        eFeature: 0,
                        toastDurationMS: 1,
                        bCritical: false,
                        fnTray: (_t, tray) => { tray.unshift({ eType: 31, notifications: [toastData] }); },
                    };
                    window.NotificationStore.ProcessNotification(info, toastData, 0);
                }
                catch (_e) { }
            };
            // Handler for RegisterForControllerStateChanges (antiquitte style)
            this.handleControllerState = (val) => {
                if (!val || val.length === 0)
                    return;
                const inputs = val[0];
                if (!inputs)
                    return;
                const ulButtons = inputs.ulButtons || 0;
                const l5Pressed = (ulButtons & L5_MASK) !== 0;
                // Debug: show button state
                this.lastButtonState = l5Pressed ? "L5" : "None";
                if (this.onButtonChange)
                    this.onButtonChange();
                if (!this.enabled) {
                    return;
                }
                // Push-to-talk: L5 held = recording
                if (l5Pressed && !this.l5Held) {
                    this.l5Held = true;
                    this.recording = true;
                    // Disable system buttons temporarily
                    deckyFrontendLib.Router.DisableHomeAndQuickAccessButtons();
                    setTimeout(() => {
                        deckyFrontendLib.Router.EnableHomeAndQuickAccessButtons();
                    }, 1000);
                    startRecording();
                    this.notify("Decktation", 1500, "Recording...");
                }
                else if (!l5Pressed && this.l5Held) {
                    this.l5Held = false;
                    this.recording = false;
                    stopRecording();
                    this.notify("Decktation", 1500, "Transcribing...");
                }
            };
            this.updateButtonPreview = (gamepadButton, isButtonPressed) => {
                const buttonName = CONTROLLER_BUTTON_NAMES[gamepadButton] || `Button ${gamepadButton}`;
                this.lastButtonState = isButtonPressed ? buttonName : "None";
                if (this.onButtonChange)
                    this.onButtonChange();
            };
            // Steam has shipped both a positional callback and a batched message callback.
            // Support both so the preview keeps working across Steam client versions.
            this.handleButtonInput = (...args) => {
                if (Array.isArray(args[0])) {
                    for (const message of args[0]) {
                        if (message && typeof message.nA === "number") {
                            this.updateButtonPreview(message.nA, Boolean(message.bS));
                        }
                    }
                    return;
                }
                const gamepadButton = args[1];
                const isButtonPressed = args[2];
                if (typeof gamepadButton === "number") {
                    this.updateButtonPreview(gamepadButton, Boolean(isButtonPressed));
                }
            };
            this.testRecording = async (onComplete) => {
                this.notify("Decktation", 1000, "Recording for 3 seconds...");
                await startRecording();
                // Wait 3 seconds
                await new Promise(resolve => setTimeout(resolve, 3000));
                // Test recordings display their result in the panel but must never type
                // into the active application. Change the UI state at exactly 3 seconds,
                // then wait only for transcription to finish.
                const transcription = stopRecording(false);
                this.notify("Decktation", 1500, "Transcribing...");
                await transcription;
                if (onComplete) {
                    const transcriptionResult = await getLastTranscription();
                    if (transcriptionResult.success && transcriptionResult.transcription) {
                        const data = transcriptionResult.transcription;
                        const text = data.text || "";
                        const time = data.timestamp ? new Date(data.timestamp * 1000).toLocaleTimeString() : "";
                        onComplete(text, time);
                    }
                }
            };
        }
    }
    // Available button options
    const BUTTON_OPTIONS = [
        { data: "L1", label: "L1 Bumper" },
        { data: "R1", label: "R1 Bumper" },
        { data: "L2", label: "L2 Trigger" },
        { data: "R2", label: "R2 Trigger" },
        { data: "L4", label: "L4 Grip" },
        { data: "R4", label: "R4 Grip" },
        { data: "L5", label: "L5 Grip" },
        { data: "R5", label: "R5 Grip" },
        { data: "A", label: "A" },
        { data: "B", label: "B" },
        { data: "X", label: "X" },
        { data: "Y", label: "Y" },
    ];
    const WHISPER_LANGUAGE_OPTIONS = [
        { data: "auto", label: "Auto Detect" },
        { data: "af", label: "Afrikaans" },
        { data: "am", label: "Amharic" },
        { data: "ar", label: "Arabic" },
        { data: "as", label: "Assamese" },
        { data: "az", label: "Azerbaijani" },
        { data: "ba", label: "Bashkir" },
        { data: "be", label: "Belarusian" },
        { data: "bg", label: "Bulgarian" },
        { data: "bn", label: "Bengali" },
        { data: "bo", label: "Tibetan" },
        { data: "br", label: "Breton" },
        { data: "bs", label: "Bosnian" },
        { data: "ca", label: "Catalan" },
        { data: "cs", label: "Czech" },
        { data: "cy", label: "Welsh" },
        { data: "da", label: "Danish" },
        { data: "de", label: "German" },
        { data: "el", label: "Greek" },
        { data: "en", label: "English" },
        { data: "es", label: "Spanish" },
        { data: "et", label: "Estonian" },
        { data: "eu", label: "Basque" },
        { data: "fa", label: "Persian" },
        { data: "fi", label: "Finnish" },
        { data: "fo", label: "Faroese" },
        { data: "fr", label: "French" },
        { data: "gl", label: "Galician" },
        { data: "gu", label: "Gujarati" },
        { data: "ha", label: "Hausa" },
        { data: "haw", label: "Hawaiian" },
        { data: "he", label: "Hebrew" },
        { data: "hi", label: "Hindi" },
        { data: "hr", label: "Croatian" },
        { data: "ht", label: "Haitian Creole" },
        { data: "hu", label: "Hungarian" },
        { data: "hy", label: "Armenian" },
        { data: "id", label: "Indonesian" },
        { data: "is", label: "Icelandic" },
        { data: "it", label: "Italian" },
        { data: "ja", label: "Japanese" },
        { data: "jw", label: "Javanese" },
        { data: "ka", label: "Georgian" },
        { data: "kk", label: "Kazakh" },
        { data: "km", label: "Khmer" },
        { data: "kn", label: "Kannada" },
        { data: "ko", label: "Korean" },
        { data: "la", label: "Latin" },
        { data: "lb", label: "Luxembourgish" },
        { data: "ln", label: "Lingala" },
        { data: "lo", label: "Lao" },
        { data: "lt", label: "Lithuanian" },
        { data: "lv", label: "Latvian" },
        { data: "mg", label: "Malagasy" },
        { data: "mi", label: "Maori" },
        { data: "mk", label: "Macedonian" },
        { data: "ml", label: "Malayalam" },
        { data: "mn", label: "Mongolian" },
        { data: "mr", label: "Marathi" },
        { data: "ms", label: "Malay" },
        { data: "mt", label: "Maltese" },
        { data: "my", label: "Myanmar" },
        { data: "ne", label: "Nepali" },
        { data: "nl", label: "Dutch" },
        { data: "nn", label: "Norwegian Nynorsk" },
        { data: "no", label: "Norwegian" },
        { data: "oc", label: "Occitan" },
        { data: "pa", label: "Punjabi" },
        { data: "pl", label: "Polish" },
        { data: "ps", label: "Pashto" },
        { data: "pt", label: "Portuguese" },
        { data: "ro", label: "Romanian" },
        { data: "ru", label: "Russian" },
        { data: "sa", label: "Sanskrit" },
        { data: "sd", label: "Sindhi" },
        { data: "si", label: "Sinhala" },
        { data: "sk", label: "Slovak" },
        { data: "sl", label: "Slovenian" },
        { data: "sn", label: "Shona" },
        { data: "so", label: "Somali" },
        { data: "sq", label: "Albanian" },
        { data: "sr", label: "Serbian" },
        { data: "su", label: "Sundanese" },
        { data: "sv", label: "Swedish" },
        { data: "sw", label: "Swahili" },
        { data: "ta", label: "Tamil" },
        { data: "te", label: "Telugu" },
        { data: "tg", label: "Tajik" },
        { data: "th", label: "Thai" },
        { data: "tk", label: "Turkmen" },
        { data: "tl", label: "Tagalog" },
        { data: "tr", label: "Turkish" },
        { data: "tt", label: "Tatar" },
        { data: "uk", label: "Ukrainian" },
        { data: "ur", label: "Urdu" },
        { data: "uz", label: "Uzbek" },
        { data: "vi", label: "Vietnamese" },
        { data: "yi", label: "Yiddish" },
        { data: "yo", label: "Yoruba" },
        { data: "yue", label: "Cantonese" },
        { data: "zh", label: "Chinese" },
    ];
    const MODEL_SIZE_OPTIONS = [
        { data: "base", label: "Base" },
        { data: "small", label: "Small" },
        { data: "medium", label: "Medium" },
    ];
    const PRESET_DISPLAY_NAMES = {
        wow: "WoW",
        guildwars2: "GW2",
        generic: "Generic",
    };
    const DecktationPanel = ({ logic }) => {
        const [enabled, setEnabled] = React.useState(false);
        const [recording, setRecording] = React.useState(false);
        const [serviceReady, setServiceReady] = React.useState(false);
        const [modelReady, setModelReady] = React.useState(false);
        const [modelLoading, setModelLoading] = React.useState(false);
        const [inputReady, setInputReady] = React.useState(true);
        const [buttonState, setButtonState] = React.useState("None");
        const [buttons, setButtons] = React.useState(["L1", "R1"]);
        const [showNotifications, setShowNotifications] = React.useState(true);
        const [activePreset, setActivePreset] = React.useState("wow");
        const [presets, setPresets] = React.useState([]);
        const [confirmMode, setConfirmMode] = React.useState(false);
        const [manualSend, setManualSend] = React.useState(false);
        const [shareDiagnostics, setShareDiagnostics] = React.useState(false);
        const [modelSize, setModelSize] = React.useState("base");
        const [transcriptionLanguage, setTranscriptionLanguage] = React.useState("auto");
        const [lastTranscription, setLastTranscription] = React.useState("");
        const [lastTranscriptionTime, setLastTranscriptionTime] = React.useState("");
        const [rpcError, setRpcError] = React.useState("");
        React.useEffect(() => {
            setEnabled(logic.enabled);
            setRecording(logic.recording);
            logic.onButtonChange = () => {
                setButtonState(logic.lastButtonState);
            };
            // Load button configuration, settings, and active game preset
            getButtonConfig().then((result) => {
                if (result.success) {
                    const config = result.config;
                    if (config) {
                        if (config.buttons) {
                            setButtons(config.buttons);
                        }
                        if (config.showNotifications !== undefined) {
                            setShowNotifications(config.showNotifications);
                            logic.showNotifications = config.showNotifications;
                        }
                        if (config.game) {
                            setActivePreset(config.game);
                        }
                        if (config.confirmMode !== undefined) {
                            setConfirmMode(config.confirmMode);
                        }
                        if (config.manualSend !== undefined) {
                            setManualSend(config.manualSend);
                        }
                        if (config.shareDiagnostics !== undefined) {
                            setShareDiagnostics(config.shareDiagnostics);
                        }
                        if (config.modelSize) {
                            setModelSize(config.modelSize);
                        }
                        if (config.transcriptionLanguage) {
                            setTranscriptionLanguage(config.transcriptionLanguage);
                        }
                        // Restore enabled state
                        if (config.enabled) {
                            setEnabled(true);
                            logic.enabled = true;
                            setModelLoading(true);
                            void loadModel();
                        }
                    }
                }
            }).catch((error) => setRpcError(String(error)));
            // Load available game presets
            getPresets().then((result) => {
                if (result.success) {
                    const opts = result.presets.map((p) => ({
                        data: p.id,
                        label: PRESET_DISPLAY_NAMES[p.id] || p.name,
                    }));
                    setPresets(opts);
                }
            }).catch((error) => setRpcError(String(error)));
            return () => {
                logic.onButtonChange = null;
            };
        }, []);
        React.useEffect(() => {
            let cancelled = false;
            let timeout;
            const poll = async () => {
                try {
                    const result = await getStatus();
                    if (result.success) {
                        setRpcError("");
                        setServiceReady(result.service_ready);
                        setModelReady(result.model_ready);
                        setModelLoading(result.model_loading);
                        setInputReady(result.input_ready !== false);
                        if (logic.enabled) {
                            setRecording(result.recording);
                        }
                    }
                    else {
                        setRpcError(result.error || "Backend status request failed");
                    }
                }
                catch (error) {
                    setRpcError(String(error));
                }
                finally {
                    if (!cancelled)
                        timeout = setTimeout(poll, 1000);
                }
            };
            void poll();
            return () => {
                cancelled = true;
                if (timeout)
                    clearTimeout(timeout);
            };
        }, [logic.enabled]);
        return (React__default["default"].createElement("div", null,
            React__default["default"].createElement(deckyFrontendLib.PanelSection, { title: "Status" },
                !serviceReady && (React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: {
                            padding: '10px',
                            backgroundColor: '#2196f3',
                            borderRadius: '8px',
                            textAlign: 'center',
                            fontWeight: 'bold'
                        } }, rpcError ? `Backend connection failed: ${rpcError}` : "Initializing service..."))),
                serviceReady && modelLoading && (React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: {
                            padding: '10px',
                            backgroundColor: '#2196f3',
                            borderRadius: '8px',
                            textAlign: 'center',
                            fontWeight: 'bold'
                        } }, "Loading Whisper model..."))),
                serviceReady && !inputReady && (React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: {
                            padding: '10px',
                            backgroundColor: '#8b2d2d',
                            borderRadius: '8px',
                            textAlign: 'center',
                            fontWeight: 'bold'
                        } }, "Keyboard helper unavailable. Reload the plugin or reinstall Decktation."))),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.ToggleField, { label: "Enable", checked: enabled, disabled: !serviceReady || modelLoading, onChange: async (e) => {
                            setEnabled(e);
                            logic.enabled = e;
                            await setEnabledRpc(e);
                            if (e && !modelReady) {
                                setModelLoading(true);
                                await loadModel();
                            }
                            if (!e && logic.recording) {
                                void stopRecording();
                                logic.recording = false;
                                setRecording(false);
                            }
                        } })),
                enabled && modelReady && (React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: {
                            padding: '12px',
                            backgroundColor: recording ? '#4ade80' : '#3b4252',
                            borderRadius: '8px',
                            textAlign: 'center',
                            fontWeight: 'bold',
                            fontSize: '14px',
                            border: recording ? '2px solid #22c55e' : '2px solid #4c566a',
                            transition: 'all 0.3s ease'
                        } }, recording ? '🎤 Recording...' : '✓ Ready'))),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: { marginTop: '4px', marginBottom: '8px' } },
                        React__default["default"].createElement(deckyFrontendLib.ButtonItem, { layout: "below", onClick: () => logic.testRecording((text, time) => {
                                setLastTranscription(text);
                                setLastTranscriptionTime(time);
                            }), disabled: !enabled || !modelReady || modelLoading || recording },
                            React__default["default"].createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' } },
                                React__default["default"].createElement("span", { style: { position: 'relative', display: 'inline-flex' } },
                                    React__default["default"].createElement(FaMicrophone, { size: 14 }),
                                    React__default["default"].createElement(FaCircle, { size: 6, style: { position: 'absolute', bottom: '-1px', right: '-3px', color: '#e05f5f' } })),
                                React__default["default"].createElement("span", null, "Test Recording (3s)"))))),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.Focusable, { tabIndex: 0, role: "textbox", "aria-label": "Last transcription", "aria-readonly": "true", onActivate: () => { }, focusWithinClassName: "gpfocuswithin", style: {
                            padding: '12px',
                            backgroundColor: '#1a2f1a',
                            borderRadius: '8px',
                            marginTop: '12px',
                            border: '1px solid #2d5a2d'
                        } },
                        React__default["default"].createElement("div", { style: {
                                fontWeight: 'bold',
                                marginBottom: '8px',
                                color: '#4ade80',
                                fontSize: '14px'
                            } }, "Last Transcription:"),
                        React__default["default"].createElement("div", { style: {
                                backgroundColor: '#0f1f0f',
                                padding: '10px',
                                borderRadius: '6px',
                                fontFamily: 'monospace',
                                fontSize: '13px',
                                wordWrap: 'break-word',
                                minHeight: '40px',
                                lineHeight: '1.4',
                                border: '1px solid #1a3a1a'
                            } }, lastTranscription || React__default["default"].createElement("span", { style: { color: '#666', fontStyle: 'italic' } }, "No transcription yet")),
                        lastTranscriptionTime && (React__default["default"].createElement("div", { style: {
                                fontSize: '11px',
                                marginTop: '8px',
                                color: '#888',
                                textAlign: 'right'
                            } }, lastTranscriptionTime))))),
            React__default["default"].createElement(deckyFrontendLib.PanelSection, { title: "Transcription" },
                presets.length > 0 && (React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.DropdownItem, { label: "Game", menuLabel: "Game", rgOptions: presets, selectedOption: activePreset, onChange: async (option) => {
                            const game = option.data;
                            setActivePreset(game);
                            await setActivePresetRpc(game);
                        } }))),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.DropdownItem, { label: "Model", menuLabel: "Model", rgOptions: MODEL_SIZE_OPTIONS, selectedOption: modelSize, onChange: async (option) => {
                            const nextModelSize = option.data;
                            const previousModelSize = modelSize;
                            setModelSize(nextModelSize);
                            if (enabled && modelReady) {
                                setModelLoading(true);
                            }
                            const result = await setModelSizeRpc(nextModelSize);
                            if (!result.success) {
                                setModelSize(previousModelSize);
                                setModelLoading(false);
                                setRpcError(result.error || "Could not update model size");
                            }
                        } })),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: {
                            padding: '10px',
                            backgroundColor: '#2a2a2a',
                            borderRadius: '6px',
                            fontSize: '12px',
                            lineHeight: '1.5',
                            border: '1px solid #444',
                        } }, "Base is fastest. Small is the balanced choice. Medium is more accurate but slower and may download on first use.")),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.DropdownItem, { label: "Lang", menuLabel: "Language", rgOptions: WHISPER_LANGUAGE_OPTIONS, selectedOption: transcriptionLanguage, onChange: async (option) => {
                            const language = option.data;
                            setTranscriptionLanguage(language);
                            const result = await setTranscriptionOptionsRpc(language);
                            if (!result.success) {
                                setRpcError(result.error || "Could not update language setting");
                            }
                        } }))),
            React__default["default"].createElement(deckyFrontendLib.PanelSection, { title: "Input" },
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.ToggleField, { label: "Toasts", description: "Recording alerts", checked: showNotifications, onChange: async (e) => {
                            setShowNotifications(e);
                            logic.showNotifications = e;
                            if (!e && confirmMode) {
                                setConfirmMode(false);
                                await setConfirmModeRpc(false);
                            }
                            await setButtonConfig(buttons, e);
                        } })),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.ToggleField, { label: "Confirm", description: "Delay before send", checked: confirmMode, onChange: async (e) => {
                            setConfirmMode(e);
                            await setConfirmModeRpc(e);
                        } })),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.ToggleField, { label: "Manual", description: "You press Enter", checked: manualSend, onChange: async (e) => {
                            setManualSend(e);
                            await setManualSendRpc(e);
                        } })),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: {
                            padding: '10px',
                            backgroundColor: '#2a2a2a',
                            borderRadius: '6px',
                            fontSize: '13px',
                            textAlign: 'center',
                            border: '1px solid #444',
                            marginBottom: '8px'
                        } },
                        "Hold ",
                        React__default["default"].createElement("strong", null, buttons.join('+')),
                        " to record")),
                buttons.map((button, index) => (React__default["default"].createElement("div", { key: index },
                    React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                        React__default["default"].createElement(deckyFrontendLib.DropdownItem, { label: `Button ${index + 1}`, menuLabel: `Button ${index + 1}`, rgOptions: BUTTON_OPTIONS, selectedOption: button, onChange: async (option) => {
                                const newButtons = [...buttons];
                                newButtons[index] = option.data;
                                setButtons(newButtons);
                                await setButtonConfig(newButtons, showNotifications);
                            } })),
                    buttons.length > 1 && (React__default["default"].createElement("div", { style: { display: 'flex', justifyContent: 'flex-end', paddingRight: '16px' } },
                        React__default["default"].createElement("div", { onClick: async () => {
                                const newButtons = buttons.filter((_, i) => i !== index);
                                setButtons(newButtons);
                                await setButtonConfig(newButtons, showNotifications);
                            }, style: {
                                color: '#e05f5f',
                                cursor: 'pointer',
                                padding: '5px 8px',
                                display: 'flex',
                                alignItems: 'center',
                                gap: '6px',
                                backgroundColor: 'rgba(224, 95, 95, 0.12)',
                                borderRadius: '4px',
                                textDecoration: 'none',
                                userSelect: 'none',
                            } },
                            React__default["default"].createElement(FaTrash, { size: 13 }),
                            React__default["default"].createElement("span", { style: { fontSize: '12px', textDecoration: 'none' } }, "Remove"))))))),
                buttons.length < 5 && (React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: { marginTop: '8px' } },
                        React__default["default"].createElement(deckyFrontendLib.ButtonItem, { layout: "below", onClick: async () => {
                                // Find first button not in current list
                                const availableButton = BUTTON_OPTIONS.find(opt => !buttons.includes(opt.data));
                                if (availableButton) {
                                    const newButtons = [...buttons, availableButton.data];
                                    setButtons(newButtons);
                                    await setButtonConfig(newButtons, showNotifications);
                                }
                            } }, "Add Button")))),
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement("div", { style: {
                            padding: '8px',
                            backgroundColor: logic.inputRegistered ? '#1a3a1a' : '#3a1a1a',
                            borderRadius: '4px',
                            fontSize: '12px',
                            textAlign: 'center',
                            fontFamily: 'monospace'
                        } },
                        "Input: ",
                        logic.inputRegistered ? "OK" : "FAILED",
                        React__default["default"].createElement("br", null),
                        "Button: ",
                        React__default["default"].createElement("strong", null, buttonState)))),
            React__default["default"].createElement(deckyFrontendLib.PanelSection, { title: "Diagnostics" },
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.ToggleField, { label: "Share", description: "Anonymous diagnostics", checked: shareDiagnostics, onChange: async (e) => {
                            setShareDiagnostics(e);
                            const result = await setShareDiagnosticsRpc(e);
                            if (!result.success) {
                                setShareDiagnostics(!e);
                                setRpcError(result.error || "Could not update diagnostics setting");
                            }
                        } }))),
            React__default["default"].createElement(deckyFrontendLib.PanelSection, { title: "How to use:" },
                React__default["default"].createElement(deckyFrontendLib.PanelSectionRow, null,
                    React__default["default"].createElement(deckyFrontendLib.Focusable, { tabIndex: 0, role: "region", "aria-label": "How to use Decktation", onActivate: () => { }, focusWithinClassName: "gpfocuswithin", style: { fontSize: '13px', lineHeight: '1.6' } },
                        React__default["default"].createElement("strong", null, "Push-to-Talk:"),
                        React__default["default"].createElement("ul", { style: { marginLeft: '15px', marginTop: '5px', marginBottom: '10px' } },
                            React__default["default"].createElement("li", null,
                                "Hold ",
                                React__default["default"].createElement("strong", null, buttons.join('+')),
                                " ",
                                buttons.length > 1 ? 'together' : '',
                                " to record"),
                            React__default["default"].createElement("li", null, "Release to transcribe and type into active window"),
                            React__default["default"].createElement("li", null, "Configure button combo above (1-5 buttons)")),
                        React__default["default"].createElement("strong", null, "Tips:"),
                        React__default["default"].createElement("ul", { style: { marginLeft: '15px', marginTop: '5px' } },
                            React__default["default"].createElement("li", null, "Make sure your game/app is the active window"),
                            React__default["default"].createElement("li", null, "Speak clearly for best results"),
                            React__default["default"].createElement("li", null, "Works great for in-game chat")))))));
    };
    var index = deckyFrontendLib.definePlugin(() => {
        let logic = new DecktationLogic();
        let input_register = null;
        // Use RegisterForControllerInputMessages (RegisterForControllerStateChanges doesn't exist)
        try {
            input_register = window.SteamClient.Input.RegisterForControllerInputMessages(logic.handleButtonInput);
            logic.inputRegistered = true;
            console.log("[Decktation] RegisterForControllerInputMessages succeeded");
        }
        catch (e) {
            console.error("[Decktation] RegisterForControllerInputMessages failed:", e);
        }
        // Seed the recording start count so we don't fire a spurious toast on load
        getStatus().then((result) => {
            if (result.success) {
                logic.prevRecordingStartCount = result.recording_start_count || 0;
            }
        });
        // Background notification polling — runs for the full plugin lifetime regardless
        // of whether the Decky panel is open, so toasts appear while in-game.
        let notifyPollInFlight = false;
        const bgNotifyInterval = setInterval(async () => {
            if (!logic.enabled || notifyPollInFlight)
                return;
            notifyPollInFlight = true;
            try {
                const result = await getStatus();
                if (result.success) {
                    if (logic.showNotifications) {
                        const startCount = result.recording_start_count || 0;
                        if (startCount > logic.prevRecordingStartCount) {
                            logic.notify("Recording", 1500, "🎤 Recording...");
                        }
                        logic.prevRecordingStartCount = startCount;
                        const pendingText = result.pending_text || "";
                        const pendingDelay = result.pending_delay || 0;
                        if (pendingText && !logic.prevPendingText) {
                            const secs = Math.round(pendingDelay);
                            logic.notify(`Sending in ${secs}s`, (pendingDelay + 0.5) * 1000, `"${pendingText}" — hold PTT to cancel`)
                                .then(id => { logic.lastPendingToastId = id; });
                        }
                        else if (!pendingText && logic.prevPendingText) {
                            if (logic.lastPendingToastId >= 0) {
                                logic.dismissNotification(logic.lastPendingToastId);
                                logic.lastPendingToastId = -1;
                            }
                        }
                        logic.prevPendingText = pendingText;
                    }
                }
            }
            catch (_e) {
            }
            finally {
                notifyPollInFlight = false;
            }
        }, 1000);
        return {
            title: React__default["default"].createElement("div", { className: deckyFrontendLib.quickAccessMenuClasses.Title }, "Decktation"),
            content: React__default["default"].createElement(DecktationPanel, { logic: logic }),
            icon: React__default["default"].createElement(FaMicrophone, null),
            onDismount() {
                clearInterval(bgNotifyInterval);
                if (input_register) {
                    input_register.unregister();
                }
                if (logic.recording) {
                    void stopRecording();
                }
            },
            alwaysRender: true
        };
    });

    return index;

})(DFL, SP_REACT);
