(function () {
    var SELLER_ASSET_TYPE = 'COIN_SELLER_COIN';
    var query = new URLSearchParams(window.location.search);

    var mock = {
        profile: {
            name: 'CoinSeller Mina',
            uid: '163009',
            region: 'Saudi Arabia',
            avatar: avatarData('C', '#dbc8ff', '#7d57c7'),
        },
        balance: {
            coins: 1285000,
        },
        users: [
            {
                uid: '2001',
                userId: '9002001',
                name: 'Alice',
                avatar: avatarData('A', '#dbc8ff', '#7d57c7'),
            },
            {
                uid: '2002',
                userId: '9002002',
                name: 'Bob',
                avatar: avatarData('B', '#f4ebff', '#7d57c7'),
            },
            {
                uid: '2003',
                userId: '9002003',
                name: 'Nora',
                avatar: avatarData('N', '#efe4ff', '#7d57c7'),
            },
        ],
        quickAmounts: [10000, 50000, 100000],
        records: [
            {
                id: 'tx-001',
                type: 'income',
                name: 'Stock transfer',
                uid: 'System',
                avatar: avatarData('S', '#e7f7f3', '#31a88f'),
                coins: 300000,
                amount: 36,
                currency: 'USD',
                time: '2026-06-04 10:30',
            },
            {
                id: 'tx-002',
                type: 'expenditure',
                name: 'Alice',
                uid: '2001',
                avatar: avatarData('A', '#dbc8ff', '#7d57c7'),
                coins: 110000,
                amount: 12.5,
                currency: 'USD',
                time: '2026-06-04 10:10',
            },
            {
                id: 'tx-003',
                type: 'expenditure',
                name: 'Bob',
                uid: '2002',
                avatar: avatarData('B', '#f4ebff', '#7d57c7'),
                coins: 88000,
                amount: 9.25,
                currency: 'USD',
                time: '2026-06-04 09:20',
            },
            {
                id: 'tx-004',
                type: 'income',
                name: 'Manager recharge',
                uid: 'System',
                avatar: avatarData('M', '#e7f7f3', '#31a88f'),
                coins: 180000,
                amount: 22,
                currency: 'USD',
                time: '2026-06-03 18:42',
            },
        ],
        subSellerPermission: {
            visible: true,
            canInvite: true,
            canTransfer: true,
        },
        subSellers: [
            {
                uid: '7001001',
                userId: '107001001',
                name: 'Sub Seller Sara',
                avatar: avatarData('S', '#efe4ff', '#7d57c7'),
                status: 'active',
                balance: 320000,
            },
            {
                uid: '7001002',
                userId: '107001002',
                name: 'Sub Seller Omar',
                avatar: avatarData('O', '#e7f7f3', '#31a88f'),
                status: 'active',
                balance: 180000,
            },
        ],
    };

    var data = {
        profile: emptyProfile(),
        balance: { coins: 0 },
        users: [],
        quickAmounts: mock.quickAmounts.slice(),
        records: [],
        subSellerPermission: emptySubSellerPermission(),
        subSellers: [],
    };

    var state = {
        target: null,
        coinAmount: '',
        historyTab: 'income',
        historyQuery: '',
        historyLimit: 3,
        isMock: query.get('mock') === '1',
        loading: query.get('mock') !== '1',
        searching: false,
        submitting: false,
        subSellerLoading: false,
        invitingSubSeller: false,
        subSellerTransferTarget: null,
        subSellerTransferAmount: '',
        subSellerTransferSubmitting: false,
    };

    function $(id) {
        return document.getElementById(id);
    }

    function t(key, fallback) {
        return window.HyAppI18n && window.HyAppI18n.t
            ? window.HyAppI18n.t(key, fallback)
            : fallback || key;
    }

    function avatarData(text, background, foreground) {
        var value =
            String(text || 'C')
                .trim()
                .charAt(0) || 'C';
        var letter = value.replace(/[<>&"']/g, '');
        var svg =
            '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">' +
            '<rect width="96" height="96" rx="48" fill="' +
            background +
            '"/>' +
            '<text x="50%" y="54%" text-anchor="middle" dominant-baseline="middle" fill="' +
            foreground +
            '" font-family="Arial, sans-serif" font-size="38" font-weight="800">' +
            letter +
            '</text>' +
            '</svg>';
        return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
    }

    function emptyProfile() {
        return {
            name: '',
            uid: '',
            region: '',
            avatar: '',
        };
    }

    function emptySubSellerPermission() {
        return {
            visible: false,
            canInvite: false,
            canTransfer: false,
        };
    }

    function initial(text) {
        return String(text || '')
            .trim()
            .charAt(0)
            .toUpperCase();
    }

    function count(value) {
        return Number(value || 0).toLocaleString('en-US', {
            maximumFractionDigits: 0,
        });
    }

    function toNumber(value) {
        var number = Number(value);
        return Number.isFinite(number) ? number : 0;
    }

    function positiveNumber(value) {
        var number = toNumber(value);
        return number > 0 ? number : 0;
    }

    function booleanValue(value) {
        if (value === true || value === 1) return true;
        if (value === false || value === 0) return false;
        var text = String(value || '')
            .trim()
            .toLowerCase();
        return text === 'true' || text === '1' || text === 'yes';
    }

    function firstValue(source, keys) {
        if (!source) return '';
        for (var i = 0; i < keys.length; i += 1) {
            var value = source[keys[i]];
            if (value !== undefined && value !== null && value !== '') {
                return value;
            }
        }
        return '';
    }

    function unwrapData(payload) {
        if (!payload || typeof payload !== 'object') return payload;
        return Object.prototype.hasOwnProperty.call(payload, 'data')
            ? payload.data
            : payload;
    }

    function replaceChildren(node, children) {
        node.textContent = '';
        children.forEach(function (child) {
            node.appendChild(child);
        });
    }

    function toast(message) {
        if (!message) return;
        if (window.HyAppToast && window.HyAppToast.show) {
            window.HyAppToast.show(message);
            return;
        }
        window.alert(message);
    }

    function setStatus(node, message, type) {
        node.hidden = !message;
        node.textContent = message || '';
        node.className = 'form-status' + (type ? ' ' + type : '');
    }

    function setSkeleton(element, loading, text) {
        if (!element) return;
        element.classList.toggle('skeleton-line', !!loading);
        if (loading) {
            element.textContent = '';
            return;
        }
        element.textContent = text || '';
    }

    function hasAPI() {
        return (
            window.HyAppAPI && window.HyAppAPI.user && window.HyAppAPI.wallet
        );
    }

    function hasSubSellerAPI() {
        return (
            hasAPI() &&
            window.HyAppAPI.wallet.getCoinSellerSubSellerPermission &&
            window.HyAppAPI.wallet.listCoinSellerSubSellers
        );
    }

    function setImage(image, fallback, src, name) {
        if (!image || !fallback) return;
        fallback.textContent = initial(name) || 'C';
        if (!src) {
            image.hidden = true;
            image.removeAttribute('src');
            fallback.hidden = false;
            return;
        }
        image.onload = function () {
            image.hidden = false;
            fallback.hidden = true;
        };
        image.onerror = function () {
            image.hidden = true;
            fallback.hidden = false;
        };
        image.src = src;
    }

    function renderAvatar(container, item) {
        container.textContent = '';
        if (item.avatar) {
            var image = document.createElement('img');
            image.src = item.avatar;
            image.alt = '';
            image.addEventListener('error', function () {
                container.textContent = initial(item.name || item.uid) || 'U';
            });
            container.appendChild(image);
            return;
        }
        container.textContent = initial(item.name || item.uid) || 'U';
    }

    function normalizeProfile(payload) {
        var source = unwrapData(payload) || {};
        return {
            name:
                firstValue(source, [
                    'username',
                    'nickname',
                    'name',
                    'display_user_id',
                    'displayUserID',
                    'user_id',
                    'userId',
                ]) || '-',
            uid:
                firstValue(source, [
                    'display_user_id',
                    'displayUserID',
                    'displayUserId',
                    'user_id',
                    'userId',
                ]) || '-',
            region:
                firstValue(source, [
                    'country_display_name',
                    'countryDisplayName',
                    'country_name',
                    'countryName',
                    'region_name',
                    'regionName',
                    'country',
                    'region',
                ]) || '',
            avatar:
                firstValue(source, [
                    'avatar',
                    'avatar_url',
                    'avatarUrl',
                    'profile_picture_url',
                    'profilePictureUrl',
                ]) || '',
        };
    }

    function normalizeBalance(payload) {
        var source = unwrapData(payload) || {};
        var balances = Array.isArray(source.balances)
            ? source.balances
            : Array.isArray(source)
              ? source
              : [];
        var matched =
            balances.find(function (item) {
                return item && item.asset_type === SELLER_ASSET_TYPE;
            }) ||
            balances.find(function (item) {
                return item && item.assetType === SELLER_ASSET_TYPE;
            }) ||
            balances[0] ||
            {};
        return {
            coins: toNumber(
                firstValue(matched, [
                    'available_amount',
                    'availableAmount',
                    'available',
                    'amount',
                ])
            ),
        };
    }

    function timeLabelFromMS(value) {
        var number = Number(value || 0);
        if (!Number.isFinite(number) || number <= 0) return '';
        var date = new Date(number);
        if (Number.isNaN(date.getTime())) return '';
        return (
            date.getFullYear() +
            '-' +
            String(date.getMonth() + 1).padStart(2, '0') +
            '-' +
            String(date.getDate()).padStart(2, '0') +
            ' ' +
            String(date.getHours()).padStart(2, '0') +
            ':' +
            String(date.getMinutes()).padStart(2, '0')
        );
    }

    function normalizeTransferAmount(item) {
        // 转账美金来自服务端账务 metadata；不同入账来源汇率可能不同，前端不能用金币数反推，缺字段时保持不展示。
        var minor = positiveNumber(
            firstValue(item, [
                'transfer_usd_minor',
                'transferUsdMinor',
                'salary_usd_minor',
                'salaryUsdMinor',
                'recharge_usd_minor',
                'rechargeUsdMinor',
                'usd_minor_amount',
                'usdMinorAmount',
            ])
        );
        if (minor > 0) return minor / 100;
        var micro = positiveNumber(
            firstValue(item, [
                'paid_amount_micro',
                'paidAmountMicro',
                'amount_usdt_micro',
                'amountUsdtMicro',
            ])
        );
        if (micro > 0) return micro / 1000000;
        return positiveNumber(
            firstValue(item, [
                'amount_usd',
                'amountUsd',
                'transfer_amount_usd',
                'transferAmountUsd',
            ])
        );
    }

    function normalizeTransferCurrency(item, amount) {
        return amount > 0
            ? String(
                  firstValue(item, [
                      'transfer_currency_code',
                      'transferCurrencyCode',
                      'recharge_currency_code',
                      'rechargeCurrencyCode',
                      'paid_currency_code',
                      'paidCurrencyCode',
                      'currency_code',
                      'currencyCode',
                  ]) || 'USD'
              ).toUpperCase()
            : '';
    }

    function formatTransferAmount(amount, currency) {
        if (!amount || amount <= 0) return '';
        var code = String(currency || 'USD').toUpperCase();
        var value = Number(amount).toLocaleString('en-US', {
            minimumFractionDigits: 2,
            maximumFractionDigits: 2,
        });
        return code + ' ' + value;
    }

    function normalizeResolvedUser(payload, keyword) {
        var source = unwrapData(payload) || {};
        var identity = source.identity || source.user_identity || source;
        var profile = source.profile || source.user || source;
        var displayID =
            firstValue(identity, [
                'display_user_id',
                'displayUserID',
                'displayUserId',
                'display_id',
                'displayId',
            ]) ||
            firstValue(profile, [
                'display_user_id',
                'displayUserID',
                'displayUserId',
                'display_id',
                'displayId',
            ]) ||
            String(keyword || '').trim();
        var userID =
            firstValue(identity, ['user_id', 'userId', 'id']) ||
            firstValue(profile, ['user_id', 'userId', 'id']) ||
            '';
        return {
            uid: displayID,
            userId: userID,
            name:
                firstValue(profile, ['username', 'nickname', 'name']) ||
                firstValue(identity, ['username', 'nickname', 'name']) ||
                t('coinseller_center.user_name_template', 'User {id}').replace(
                    '{id}',
                    displayID
                ),
            avatar:
                firstValue(profile, [
                    'avatar',
                    'avatar_url',
                    'avatarUrl',
                    'profile_picture_url',
                    'profilePictureUrl',
                ]) ||
                firstValue(identity, [
                    'avatar',
                    'avatar_url',
                    'avatarUrl',
                    'profile_picture_url',
                    'profilePictureUrl',
                ]) ||
                '',
        };
    }

    function normalizeTransactionRecord(item, index) {
        var delta = toNumber(
            firstValue(item, ['available_delta', 'availableDelta'])
        );
        var type = delta >= 0 ? 'income' : 'expenditure';
        var counterpartyUserID = String(
            firstValue(item, ['counterparty_user_id', 'counterpartyUserId']) ||
                ''
        );
        var counterpartyDisplayID = String(
            firstValue(item, [
                'counterparty_display_user_id',
                'counterpartyDisplayUserId',
                'counterpartyDisplayUserID',
            ]) || ''
        );
        var counterpartyName = firstValue(item, [
            'counterparty_username',
            'counterpartyUsername',
            'counterparty_name',
            'counterpartyName',
        ]);
        var counterpartyAvatar = firstValue(item, [
            'counterparty_avatar',
            'counterpartyAvatar',
        ]);
        var counterpartyUID = counterpartyDisplayID || counterpartyUserID;
        // 入账流水也可能来自某个用户的工资转币商，标题必须优先展示对方资料；只有后台进货这类没有对方用户的流水才展示库存入账。
        var name =
            counterpartyName ||
            (counterpartyUID
                ? t(
                      'coinseller_center.user_name_template',
                      'User {id}'
                  ).replace('{id}', counterpartyUID)
                : type === 'income'
                  ? t('coinseller_center.stock_transfer', 'Stock transfer')
                  : t('coinseller_center.transfer_out', 'Transfer out'));
        var uid =
            counterpartyUID ||
            (type === 'income' ? t('coinseller_center.system', 'System') : '-');
        var transferAmount = normalizeTransferAmount(item);
        return {
            id:
                firstValue(item, ['transaction_id', 'transactionId']) ||
                String(firstValue(item, ['entry_id', 'entryId']) || index),
            type: type,
            name: name,
            uid: uid,
            avatar:
                counterpartyAvatar ||
                avatarData(
                    name,
                    type === 'income' ? '#e7f7f3' : '#dbc8ff',
                    type === 'income' ? '#31a88f' : '#7d57c7'
                ),
            coins: Math.abs(delta),
            amount: transferAmount,
            currency: normalizeTransferCurrency(item, transferAmount),
            time: timeLabelFromMS(
                firstValue(item, ['created_at_ms', 'createdAtMs'])
            ),
        };
    }

    function normalizeTransactions(payload) {
        var source = unwrapData(payload) || {};
        var items = Array.isArray(source.items)
            ? source.items
            : Array.isArray(source.transactions)
              ? source.transactions
              : Array.isArray(source)
                ? source
                : [];
        return items.map(function (item, index) {
            return normalizeTransactionRecord(item || {}, index);
        });
    }

    function normalizeSubSellerPermission(payload) {
        var source = unwrapData(payload) || {};
        var canInvite = booleanValue(
            firstValue(source, [
                'can_invite_sub_seller',
                'canInviteSubSeller',
                'can_open_sub_seller',
                'canOpenSubSeller',
                'can_invite',
                'canInvite',
            ])
        );
        var canTransfer = booleanValue(
            firstValue(source, [
                'can_transfer_sub_seller',
                'canTransferSubSeller',
                'can_transfer',
                'canTransfer',
            ])
        );
        var canList = booleanValue(
            firstValue(source, [
                'can_list_sub_sellers',
                'canListSubSellers',
                'can_list',
                'canList',
            ])
        );
        var explicitVisible = firstValue(source, [
            'visible',
            'enabled',
            'allowed',
            'has_permission',
            'hasPermission',
        ]);
        return {
            visible:
                explicitVisible === '' || explicitVisible === undefined
                    ? canInvite || canTransfer || canList
                    : booleanValue(explicitVisible),
            canInvite: canInvite,
            canTransfer: canTransfer,
        };
    }

    function normalizeSubSeller(item, index) {
        var source = item || {};
        var displayID =
            firstValue(source, [
                'display_user_id',
                'displayUserID',
                'displayUserId',
                'display_id',
                'displayId',
            ]) || '';
        var userID = firstValue(source, ['user_id', 'userId', 'id']) || '';
        var name =
            firstValue(source, ['username', 'nickname', 'name']) ||
            t('coinseller_center.user_name_template', 'User {id}').replace(
                '{id}',
                displayID || userID || index + 1
            );
        return {
            uid: displayID || userID,
            userId: userID,
            name: name,
            avatar:
                firstValue(source, [
                    'avatar',
                    'avatar_url',
                    'avatarUrl',
                    'profile_picture_url',
                    'profilePictureUrl',
                ]) || '',
            status: firstValue(source, ['status']) || '',
            balance: toNumber(
                firstValue(source, [
                    'coin_seller_balance',
                    'coinSellerBalance',
                    'available_amount',
                    'availableAmount',
                    'balance',
                    'amount',
                ])
            ),
            region:
                firstValue(source, [
                    'country_display_name',
                    'countryDisplayName',
                    'region_name',
                    'regionName',
                    'country_name',
                    'countryName',
                ]) || '',
        };
    }

    function normalizeSubSellers(payload) {
        var source = unwrapData(payload) || {};
        var items = Array.isArray(source.items)
            ? source.items
            : Array.isArray(source.sub_sellers)
              ? source.sub_sellers
              : Array.isArray(source.subSellers)
                ? source.subSellers
                : Array.isArray(source.children)
                  ? source.children
                  : Array.isArray(source)
                    ? source
                    : [];
        return items
            .map(function (item, index) {
                return normalizeSubSeller(item, index);
            })
            .filter(function (item) {
                var status = String(item.status || '').toLowerCase();
                // 列表接口的服务端契约只返回 active 直属关系；这里再过滤一次，避免异常数据把 pending 申请展示成可转账子币商。
                return !status || status === 'active';
            });
    }

    function applyMockData() {
        data.profile = Object.assign({}, mock.profile);
        data.balance = Object.assign({}, mock.balance);
        data.users = mock.users.slice();
        data.quickAmounts = mock.quickAmounts.slice();
        data.records = mock.records.slice();
        data.subSellerPermission = Object.assign({}, mock.subSellerPermission);
        data.subSellers = mock.subSellers.slice();
    }

    function applyEmptyData() {
        data.profile = emptyProfile();
        data.balance = { coins: 0 };
        data.users = [];
        data.quickAmounts = mock.quickAmounts.slice();
        data.records = [];
        data.subSellerPermission = emptySubSellerPermission();
        data.subSellers = [];
    }

    function loadSubSellerCapability() {
        if (!hasSubSellerAPI()) {
            data.subSellerPermission = emptySubSellerPermission();
            data.subSellers = [];
            return Promise.resolve();
        }
        state.subSellerLoading = true;
        renderSubSellers();
        return window.HyAppAPI.wallet
            .getCoinSellerSubSellerPermission()
            .then(function (response) {
                data.subSellerPermission =
                    normalizeSubSellerPermission(response);
                // 子币商列表属于权限增强区；只有服务端明确给到能力时才拉取，避免普通币商看到空功能入口。
                if (!data.subSellerPermission.visible) {
                    data.subSellers = [];
                    return null;
                }
                return window.HyAppAPI.wallet
                    .listCoinSellerSubSellers({
                        page: 1,
                        page_size: 50,
                    })
                    .then(function (listResponse) {
                        data.subSellers = normalizeSubSellers(listResponse);
                    });
            })
            .catch(function (error) {
                if (window.console && window.console.warn) {
                    window.console.warn(
                        '[coinseller-center] sub seller api failed',
                        error
                    );
                }
                data.subSellerPermission = emptySubSellerPermission();
                data.subSellers = [];
            })
            .finally(function () {
                state.subSellerLoading = false;
                renderSubSellers();
            });
    }

    function loadRealData() {
        if (!hasAPI()) {
            toast(
                t(
                    'coinseller_center.load_failed',
                    'Load failed. Try again later.'
                )
            );
            return Promise.resolve();
        }
        state.loading = true;
        render();
        return Promise.all([
            window.HyAppAPI.user.me(),
            window.HyAppAPI.wallet.balances(SELLER_ASSET_TYPE),
            window.HyAppAPI.wallet.transactions
                ? window.HyAppAPI.wallet
                      .transactions({
                          asset_type: SELLER_ASSET_TYPE,
                          page: 1,
                          page_size: 20,
                      })
                      .catch(function (error) {
                          if (window.console && window.console.warn) {
                              window.console.warn(
                                  '[coinseller-center] records api failed',
                                  error
                              );
                          }
                          return null;
                      })
                : Promise.resolve(null),
            loadSubSellerCapability(),
        ])
            .then(function (results) {
                data.profile = normalizeProfile(results[0]);
                data.balance = normalizeBalance(results[1]);
                data.records = normalizeTransactions(results[2]);
            })
            .catch(function (error) {
                if (window.console && window.console.warn) {
                    window.console.warn(
                        '[coinseller-center] api failed',
                        error
                    );
                }
                toast(
                    t(
                        'coinseller_center.load_failed',
                        'Load failed. Try again later.'
                    )
                );
            })
            .finally(function () {
                state.loading = false;
                render();
            });
    }

    function renderProfile() {
        var image = $('profileAvatar');
        var fallback = $('profileAvatarFallback');
        var profile = data.profile;
        var loading = !!state.loading;

        setSkeleton($('profileName'), loading, profile.name || '');
        setSkeleton(
            $('profileUID'),
            loading,
            profile.uid
                ? t('coinseller_center.uid_prefix', 'UID: {id}').replace(
                      '{id}',
                      profile.uid
                  )
                : ''
        );
        fallback.classList.toggle('avatar-skeleton', loading);
        if (loading) {
            image.hidden = true;
            image.removeAttribute('src');
            fallback.hidden = false;
            fallback.textContent = '';
            return;
        }

        setImage(image, fallback, profile.avatar, profile.name || profile.uid);
    }

    function renderBalance() {
        setSkeleton($('coinBalance'), state.loading, count(data.balance.coins));
        var coinIcon = document.querySelector('.balance-value .coin-icon');
        if (coinIcon) {
            coinIcon.classList.toggle('skeleton-coin', !!state.loading);
        }
    }

    function createSubSellerRow(item) {
        var row = document.createElement('article');
        var avatar = document.createElement('div');
        var main = document.createElement('div');
        var title = document.createElement('div');
        var meta = document.createElement('div');
        var balance = document.createElement('div');
        var action = document.createElement('button');

        row.className = 'sub-seller-row';
        avatar.className = 'record-avatar';
        main.className = 'sub-seller-main';
        title.className = 'record-title';
        meta.className = 'record-meta';
        balance.className = 'sub-seller-balance';
        action.className = 'sub-seller-transfer';
        action.type = 'button';
        action.disabled =
            !data.subSellerPermission.canTransfer ||
            state.subSellerTransferSubmitting;
        action.textContent = t('coinseller_center.transfer', 'Transfer');

        renderAvatar(avatar, item);
        title.textContent = item.name || '-';
        meta.textContent = t(
            'coinseller_center.uid_prefix',
            'UID: {id}'
        ).replace('{id}', item.uid || '-');
        balance.textContent =
            t('coinseller_center.sub_seller_wallet', 'Wallet') +
            ': ' +
            count(item.balance) +
            ' ' +
            t('coinseller_center.coins_lower', 'coins');
        action.addEventListener('click', function () {
            openSubSellerTransfer(item);
        });

        main.appendChild(title);
        main.appendChild(meta);
        if (item.balance > 0) main.appendChild(balance);
        row.appendChild(avatar);
        row.appendChild(main);
        if (data.subSellerPermission.canTransfer) row.appendChild(action);
        return row;
    }

    function renderSubSellers() {
        var section = $('subSellerSection');
        if (!section) return;
        var permission = data.subSellerPermission || emptySubSellerPermission();
        section.hidden = !permission.visible;
        $('inviteSubSellerButton').hidden = !permission.canInvite;
        if (!permission.visible) return;

        if (state.subSellerLoading) {
            setStatus(
                $('subSellerStatus'),
                t('coinseller_center.loading', 'Loading...'),
                ''
            );
        } else {
            setStatus(
                $('subSellerStatus'),
                data.subSellers.length
                    ? ''
                    : t(
                          'coinseller_center.no_sub_sellers',
                          'No sub coin sellers yet.'
                      ),
                data.subSellers.length ? '' : 'warning'
            );
        }
        replaceChildren(
            $('subSellerList'),
            data.subSellers.map(function (item) {
                return createSubSellerRow(item);
            })
        );
    }

    function renderQuickAmounts() {
        replaceChildren(
            $('quickAmounts'),
            data.quickAmounts.map(function (amount) {
                var button = document.createElement('button');
                button.className =
                    'quick-amount' +
                    (String(amount) === state.coinAmount ? ' is-active' : '');
                button.type = 'button';
                button.textContent = count(amount);
                button.addEventListener('click', function () {
                    state.coinAmount = String(amount);
                    $('coinAmountInput').value = state.coinAmount;
                    setStatus($('rechargeStatus'), '', '');
                    renderRechargeState();
                });
                return button;
            })
        );
    }

    function renderTarget() {
        var card = $('targetCard');
        if (!state.target) {
            card.hidden = true;
            $('rechargeTargetName').textContent = '-';
            return;
        }
        card.hidden = false;
        renderAvatar($('targetAvatar'), state.target);
        $('targetName').textContent = state.target.name;
        $('targetUID').textContent = t(
            'coinseller_center.uid_prefix',
            'UID: {id}'
        ).replace('{id}', state.target.uid);
        $('rechargeTargetName').textContent =
            t('coinseller_center.target_user', 'Target user') +
            ': ' +
            state.target.name;
    }

    function parsedCoinAmount() {
        var input = $('coinAmountInput');
        if (input) {
            var sanitized = String(input.value || '').replace(/[^\d]/g, '');
            if (input.value !== sanitized) input.value = sanitized;
            state.coinAmount = sanitized;
        }
        return Number(state.coinAmount || 0);
    }

    function renderRechargeState() {
        var amount = parsedCoinAmount();
        var disabled =
            state.loading ||
            state.submitting ||
            state.searching ||
            !state.target ||
            amount <= 0;
        $('rechargeButton').disabled = disabled;
        $('searchButton').disabled = state.searching;
        renderQuickAmounts();
    }

    function recordMatchesQuery(record) {
        if (!state.historyQuery) return true;
        var keyword = state.historyQuery.toLowerCase();
        return (
            String(record.name || '')
                .toLowerCase()
                .indexOf(keyword) >= 0 ||
            String(record.uid || '')
                .toLowerCase()
                .indexOf(keyword) >= 0
        );
    }

    function visibleHistoryRecords() {
        return data.records
            .filter(function (record) {
                return (
                    record.type === state.historyTab &&
                    recordMatchesQuery(record)
                );
            })
            .slice(0, state.historyLimit);
    }

    function createRecordRow(record) {
        var row = document.createElement('article');
        var avatar = document.createElement('div');
        var main = document.createElement('div');
        var title = document.createElement('div');
        var metaGroup = document.createElement('div');
        var meta = document.createElement('div');
        var transfer = document.createElement('span');
        var side = document.createElement('div');
        var amount = document.createElement('strong');
        var time = document.createElement('span');

        row.className = 'record-row';
        avatar.className = 'record-avatar';
        main.className = 'record-main';
        title.className = 'record-title';
        metaGroup.className = 'record-meta-group';
        meta.className = 'record-meta';
        transfer.className = 'record-transfer';
        side.className =
            'record-side' + (record.type === 'income' ? ' is-income' : '');

        renderAvatar(avatar, record);
        title.textContent = record.name || '-';
        meta.textContent = t(
            'coinseller_center.uid_prefix',
            'UID: {id}'
        ).replace('{id}', record.uid || '-');
        transfer.textContent = formatTransferAmount(
            record.amount,
            record.currency
        );
        amount.textContent =
            (record.type === 'income' ? '+' : '-') +
            count(record.coins) +
            ' ' +
            t('coinseller_center.coins_lower', 'coins');
        time.textContent = record.time || '';

        main.appendChild(title);
        metaGroup.appendChild(meta);
        if (transfer.textContent) metaGroup.appendChild(transfer);
        main.appendChild(metaGroup);
        side.appendChild(amount);
        side.appendChild(time);
        row.appendChild(avatar);
        row.appendChild(main);
        row.appendChild(side);
        return row;
    }

    function renderRecent() {
        replaceChildren(
            $('recentList'),
            data.records.slice(0, 3).map(function (record) {
                return createRecordRow(record);
            })
        );
    }

    function renderHistory() {
        document.querySelectorAll('[data-history-tab]').forEach(function (tab) {
            var active =
                tab.getAttribute('data-history-tab') === state.historyTab;
            tab.classList.toggle('is-active', active);
            tab.setAttribute('aria-selected', String(active));
        });

        var all = data.records.filter(function (record) {
            return (
                record.type === state.historyTab && recordMatchesQuery(record)
            );
        });
        var records = visibleHistoryRecords();
        $('loadMoreButton').hidden = records.length >= all.length;
        setStatus(
            $('historyStatus'),
            all.length
                ? ''
                : t(
                      'coinseller_center.no_transaction_records',
                      'No transaction records'
                  ),
            all.length ? '' : 'warning'
        );
        replaceChildren(
            $('historyList'),
            records.map(function (record) {
                return createRecordRow(record);
            })
        );
    }

    function findMockUser(keyword) {
        var normalized = String(keyword || '')
            .trim()
            .toLowerCase();
        return data.users.find(function (user) {
            return (
                String(user.uid || '')
                    .toLowerCase()
                    .indexOf(normalized) >= 0 ||
                String(user.name || '')
                    .toLowerCase()
                    .indexOf(normalized) >= 0
            );
        });
    }

    function findUser(keyword) {
        if (state.isMock) {
            return Promise.resolve(findMockUser(keyword) || null);
        }
        if (!hasAPI() || !window.HyAppAPI.user.resolveDisplayUserID) {
            return Promise.reject(new Error('api_not_ready'));
        }
        return window.HyAppAPI.user
            .resolveDisplayUserID(keyword)
            .then(function (payload) {
                return normalizeResolvedUser(payload, keyword);
            });
    }

    function handleSearch(value) {
        state.searching = true;
        setStatus(
            $('searchStatus'),
            t('coinseller_center.loading', 'Loading...'),
            ''
        );
        renderRechargeState();
        findUser(value)
            .then(function (user) {
                if (!user) {
                    state.target = null;
                    renderTarget();
                    renderRechargeState();
                    setStatus(
                        $('searchStatus'),
                        t(
                            'coinseller_center.user_not_found',
                            'User not found.'
                        ),
                        'warning'
                    );
                    return;
                }
                state.target = user;
                renderTarget();
                renderRechargeState();
                setStatus($('searchStatus'), '', '');
            })
            .catch(function (error) {
                if (window.console && window.console.warn) {
                    window.console.warn(
                        '[coinseller-center] user search failed',
                        error
                    );
                }
                state.target = null;
                renderTarget();
                renderRechargeState();
                setStatus(
                    $('searchStatus'),
                    t('coinseller_center.user_not_found', 'User not found.'),
                    'warning'
                );
            })
            .finally(function () {
                state.searching = false;
                renderRechargeState();
            });
    }

    function commandID() {
        return [
            'coin-seller-transfer',
            Date.now(),
            Math.random().toString(36).slice(2, 8),
        ].join('-');
    }

    function subSellerCommandID(action) {
        return [
            'coin-seller-sub-seller',
            action || 'action',
            Date.now(),
            Math.random().toString(36).slice(2, 8),
        ].join('-');
    }

    function buildTransferPayload(amount) {
        return {
            command_id: commandID(),
            target_display_user_id: String(state.target.uid || '').trim(),
            amount: amount,
            reason: 'player recharge',
        };
    }

    function appendTransferRecord(amount, response) {
        var payload = unwrapData(response) || {};
        var coins = toNumber(
            firstValue(payload, ['amount', 'coin_amount', 'coinAmount'])
        );
        var transferAmount = normalizeTransferAmount(payload);
        data.records.unshift({
            id:
                firstValue(payload, ['transaction_id', 'transactionId']) ||
                'tx-' + Date.now(),
            type: 'expenditure',
            name: state.target.name,
            uid: state.target.uid,
            avatar: state.target.avatar,
            coins: coins || amount,
            amount: transferAmount,
            currency: normalizeTransferCurrency(payload, transferAmount),
            time: currentTimeLabel(),
        });
    }

    function appendSubSellerTransferRecord(amount, response) {
        var target = state.subSellerTransferTarget;
        if (!target) return;
        var payload = unwrapData(response) || {};
        var coins = toNumber(
            firstValue(payload, ['amount', 'coin_amount', 'coinAmount'])
        );
        data.records.unshift({
            id:
                firstValue(payload, ['transaction_id', 'transactionId']) ||
                'sub-seller-tx-' + Date.now(),
            type: 'expenditure',
            name: target.name,
            uid: target.uid,
            avatar: target.avatar,
            coins: coins || amount,
            amount: 0,
            currency: '',
            time: currentTimeLabel(),
        });
    }

    function refreshSubSellerFromResponse(target, payload, amount) {
        if (!target) return;
        var balanceAfter = firstValue(payload, [
            'sub_seller_balance_after',
            'subSellerBalanceAfter',
            'child_balance_after',
            'childBalanceAfter',
            'target_balance_after',
            'targetBalanceAfter',
        ]);
        data.subSellers = data.subSellers.map(function (item) {
            if (String(item.uid) !== String(target.uid)) return item;
            return Object.assign({}, item, {
                balance:
                    balanceAfter !== '' && balanceAfter !== undefined
                        ? toNumber(balanceAfter)
                        : item.balance + amount,
            });
        });
    }

    function inviteSubSeller() {
        var input = $('inviteSubSellerInput');
        var displayID = String(input.value || '').trim();
        if (!data.subSellerPermission.canInvite) {
            setStatus(
                $('inviteSubSellerStatus'),
                t('coinseller_center.invite_failed', 'Invite failed.'),
                'warning'
            );
            return;
        }
        if (!displayID) {
            setStatus(
                $('inviteSubSellerStatus'),
                t('coinseller_center.enter_user_id', 'Enter user ID'),
                'warning'
            );
            return;
        }
        if (state.isMock) {
            input.value = '';
            closeModal('inviteSubSellerModal');
            toast(
                t(
                    'coinseller_center.invite_success',
                    'Official will review your invitation within 24 hours.'
                )
            );
            return;
        }
        if (!hasAPI() || !window.HyAppAPI.wallet.inviteCoinSellerSubSeller) {
            setStatus(
                $('inviteSubSellerStatus'),
                t('coinseller_center.invite_failed', 'Invite failed.'),
                'warning'
            );
            return;
        }

        state.invitingSubSeller = true;
        $('submitInviteSubSellerButton').disabled = true;
        setStatus(
            $('inviteSubSellerStatus'),
            t('coinseller_center.loading', 'Loading...'),
            ''
        );
        // 邀请子币商现在只创建待审核申请；command_id 保证移动端重试不会重复生成多个 pending 申请。
        window.HyAppAPI.wallet
            .inviteCoinSellerSubSeller({
                command_id: subSellerCommandID('invite'),
                target_display_user_id: displayID,
            })
            .then(function (response) {
                input.value = '';
                setStatus(
                    $('inviteSubSellerStatus'),
                    t(
                        'coinseller_center.invite_success',
                        'Official will review your invitation within 24 hours.'
                    ),
                    'success'
                );
                // 申请提交成功不代表父子关系已经生效，列表必须继续以服务端 active 关系为准。
                toast(
                    t(
                        'coinseller_center.invite_success',
                        'Official will review your invitation within 24 hours.'
                    )
                );
                closeModal('inviteSubSellerModal');
            })
            .catch(function (error) {
                if (window.console && window.console.warn) {
                    window.console.warn(
                        '[coinseller-center] invite sub seller failed',
                        error
                    );
                }
                setStatus(
                    $('inviteSubSellerStatus'),
                    error && error.message
                        ? error.message
                        : t(
                              'coinseller_center.invite_failed',
                              'Invite failed.'
                          ),
                    'warning'
                );
            })
            .finally(function () {
                state.invitingSubSeller = false;
                $('submitInviteSubSellerButton').disabled = false;
            });
    }

    function openSubSellerTransfer(item) {
        state.subSellerTransferTarget = item;
        state.subSellerTransferAmount = '';
        $('subSellerTransferAmountInput').value = '';
        $('subSellerTransferTargetName').textContent =
            t(
                'coinseller_center.transfer_to_sub_seller',
                'Transfer to sub seller'
            ) +
            ': ' +
            item.name;
        setStatus($('subSellerTransferStatus'), '', '');
        renderSubSellerTransferState();
        openModal('subSellerTransferModal');
        window.setTimeout(function () {
            $('subSellerTransferAmountInput').focus();
        }, 80);
    }

    function parsedSubSellerTransferAmount() {
        var input = $('subSellerTransferAmountInput');
        if (input) {
            var sanitized = String(input.value || '').replace(/[^\d]/g, '');
            if (input.value !== sanitized) input.value = sanitized;
            state.subSellerTransferAmount = sanitized;
        }
        return Number(state.subSellerTransferAmount || 0);
    }

    function renderSubSellerTransferState() {
        var amount = parsedSubSellerTransferAmount();
        $('submitSubSellerTransferButton').disabled =
            state.loading ||
            state.subSellerTransferSubmitting ||
            !state.subSellerTransferTarget ||
            amount <= 0;
    }

    function transferToSubSeller() {
        var amount = parsedSubSellerTransferAmount();
        var target = state.subSellerTransferTarget;
        if (!target) {
            setStatus(
                $('subSellerTransferStatus'),
                t(
                    'coinseller_center.select_sub_seller_first',
                    'Select a sub coin seller first.'
                ),
                'warning'
            );
            return;
        }
        if (amount <= 0) {
            setStatus(
                $('subSellerTransferStatus'),
                t(
                    'coinseller_center.valid_amount_required',
                    'Please enter a valid amount.'
                ),
                'warning'
            );
            return;
        }
        if (amount > data.balance.coins) {
            setStatus(
                $('subSellerTransferStatus'),
                t(
                    'coinseller_center.amount_exceeds_stock',
                    'Amount exceeds stock.'
                ),
                'warning'
            );
            return;
        }
        if (state.isMock) {
            data.balance.coins -= amount;
            refreshSubSellerFromResponse(target, {}, amount);
            appendSubSellerTransferRecord(amount, {});
            finishSubSellerTransfer();
            return;
        }
        if (
            !hasAPI() ||
            !window.HyAppAPI.wallet.transferCoinSellerToSubSeller
        ) {
            setStatus($('subSellerTransferStatus'), '', '');
            toast(t('coinseller_center.transfer_failed', 'Transfer failed.'));
            return;
        }

        state.subSellerTransferSubmitting = true;
        setStatus(
            $('subSellerTransferStatus'),
            t('coinseller_center.loading', 'Loading...'),
            ''
        );
        renderSubSellerTransferState();
        // 子币商转账目标是对方的币商专用钱包，不是玩家普通金币；payload 单独命名，避免误走老的玩家充值接口。
        window.HyAppAPI.wallet
            .transferCoinSellerToSubSeller({
                command_id: subSellerCommandID('transfer'),
                target_display_user_id: String(target.uid || '').trim(),
                amount: amount,
                reason: 'sub coin seller stock transfer',
            })
            .then(function (response) {
                var payload = unwrapData(response) || {};
                var balanceAfter = firstValue(payload, [
                    'parent_balance_after',
                    'parentBalanceAfter',
                    'seller_balance_after',
                    'sellerBalanceAfter',
                ]);
                data.balance.coins =
                    balanceAfter !== '' && balanceAfter !== undefined
                        ? toNumber(balanceAfter)
                        : data.balance.coins - amount;
                refreshSubSellerFromResponse(target, payload, amount);
                appendSubSellerTransferRecord(amount, response);
                finishSubSellerTransfer();
            })
            .catch(function (error) {
                if (window.console && window.console.warn) {
                    window.console.warn(
                        '[coinseller-center] sub seller transfer failed',
                        error
                    );
                }
                setStatus($('subSellerTransferStatus'), '', '');
                toast(
                    error && error.message
                        ? error.message
                        : t(
                              'coinseller_center.transfer_failed',
                              'Transfer failed.'
                          )
                );
            })
            .finally(function () {
                state.subSellerTransferSubmitting = false;
                renderSubSellerTransferState();
                renderSubSellers();
            });
    }

    function rechargeNow() {
        var amount = parsedCoinAmount();
        if (!state.target) {
            setStatus(
                $('rechargeStatus'),
                t(
                    'coinseller_center.select_user_first',
                    'Select a user first.'
                ),
                'warning'
            );
            return;
        }
        if (amount <= 0) {
            setStatus(
                $('rechargeStatus'),
                t(
                    'coinseller_center.valid_amount_required',
                    'Please enter a valid amount.'
                ),
                'warning'
            );
            return;
        }
        if (amount > data.balance.coins) {
            setStatus(
                $('rechargeStatus'),
                t(
                    'coinseller_center.amount_exceeds_stock',
                    'Amount exceeds stock.'
                ),
                'warning'
            );
            return;
        }
        if (state.isMock) {
            data.balance.coins -= amount;
            appendTransferRecord(amount, {});
            finishRecharge();
            return;
        }
        if (!hasAPI() || !window.HyAppAPI.wallet.transferCoinFromSeller) {
            setStatus($('rechargeStatus'), '', '');
            toast(t('coinseller_center.transfer_failed', 'Transfer failed.'));
            return;
        }

        state.submitting = true;
        setStatus(
            $('rechargeStatus'),
            t('coinseller_center.loading', 'Loading...'),
            ''
        );
        renderRechargeState();
        window.HyAppAPI.wallet
            .transferCoinFromSeller(buildTransferPayload(amount))
            .then(function (response) {
                var payload = unwrapData(response) || {};
                var balanceAfter = toNumber(
                    firstValue(payload, [
                        'seller_balance_after',
                        'sellerBalanceAfter',
                    ])
                );
                if (balanceAfter > 0 || payload.seller_balance_after === 0) {
                    data.balance.coins = balanceAfter;
                } else {
                    data.balance.coins -= amount;
                }
                appendTransferRecord(amount, response);
                finishRecharge();
            })
            .catch(function (error) {
                if (window.console && window.console.warn) {
                    window.console.warn(
                        '[coinseller-center] transfer failed',
                        error
                    );
                }
                setStatus($('rechargeStatus'), '', '');
                toast(
                    error && error.message
                        ? error.message
                        : t(
                              'coinseller_center.transfer_failed',
                              'Transfer failed.'
                          )
                );
            })
            .finally(function () {
                state.submitting = false;
                renderRechargeState();
            });
    }

    function finishRecharge() {
        state.coinAmount = '';
        $('coinAmountInput').value = '';
        setStatus(
            $('rechargeStatus'),
            t('coinseller_center.recharge_success', 'Recharge success.'),
            'success'
        );
        renderBalance();
        renderRecent();
        renderRechargeState();
        if (!$('historyModal').hidden) renderHistory();
        closeModal('rechargeModal');
        toast(t('coinseller_center.recharge_success', 'Recharge success.'));
    }

    function finishSubSellerTransfer() {
        state.subSellerTransferAmount = '';
        $('subSellerTransferAmountInput').value = '';
        setStatus(
            $('subSellerTransferStatus'),
            t('coinseller_center.transfer_success', 'Transfer success.'),
            'success'
        );
        renderBalance();
        renderSubSellers();
        renderRecent();
        renderSubSellerTransferState();
        if (!$('historyModal').hidden) renderHistory();
        closeModal('subSellerTransferModal');
        toast(t('coinseller_center.transfer_success', 'Transfer success.'));
    }

    function currentTimeLabel() {
        var now = new Date();
        return (
            now.getFullYear() +
            '-' +
            String(now.getMonth() + 1).padStart(2, '0') +
            '-' +
            String(now.getDate()).padStart(2, '0') +
            ' ' +
            String(now.getHours()).padStart(2, '0') +
            ':' +
            String(now.getMinutes()).padStart(2, '0')
        );
    }

    function openModal(id) {
        var modal = $(id);
        if (!modal) return;
        modal.hidden = false;
        modal.setAttribute('aria-hidden', 'false');
        document.body.classList.add('modal-open');
    }

    function closeModal(id) {
        var modal = $(id);
        if (!modal) return;
        modal.hidden = true;
        modal.setAttribute('aria-hidden', 'true');
        var hasOpen = Array.prototype.some.call(
            document.querySelectorAll('.sheet-modal'),
            function (node) {
                return !node.hidden;
            }
        );
        document.body.classList.toggle('modal-open', hasOpen);
    }

    function bindEvents() {
        $('backButton').addEventListener('click', function () {
            if (window.HyAppBridge) window.HyAppBridge.back();
        });
        $('historyButton').addEventListener('click', function () {
            state.historyLimit = 3;
            renderHistory();
            openModal('historyModal');
        });
        $('viewAllHistoryButton').addEventListener('click', function () {
            state.historyLimit = 3;
            renderHistory();
            openModal('historyModal');
        });
        $('helpButton').addEventListener('click', function () {
            openModal('helpModal');
        });
        $('inviteSubSellerButton').addEventListener('click', function () {
            $('inviteSubSellerInput').value = '';
            setStatus($('inviteSubSellerStatus'), '', '');
            openModal('inviteSubSellerModal');
            window.setTimeout(function () {
                $('inviteSubSellerInput').focus();
            }, 80);
        });
        document
            .querySelectorAll('[data-close-modal]')
            .forEach(function (node) {
                node.addEventListener('click', function () {
                    closeModal(node.getAttribute('data-close-modal'));
                });
            });
        $('searchForm').addEventListener('submit', function (event) {
            event.preventDefault();
            var value = $('userSearchInput').value.trim();
            if (!value) {
                setStatus(
                    $('searchStatus'),
                    t('coinseller_center.enter_user_id', 'Enter user ID'),
                    'warning'
                );
                return;
            }
            handleSearch(value);
        });
        $('openRechargeButton').addEventListener('click', function () {
            if (!state.target) return;
            state.coinAmount = '';
            $('coinAmountInput').value = '';
            setStatus($('rechargeStatus'), '', '');
            renderRechargeState();
            openModal('rechargeModal');
            window.setTimeout(function () {
                $('coinAmountInput').focus();
            }, 80);
        });
        $('coinAmountInput').addEventListener('input', function () {
            state.coinAmount = $('coinAmountInput').value.replace(/[^\d]/g, '');
            $('coinAmountInput').value = state.coinAmount;
            setStatus($('rechargeStatus'), '', '');
            renderRechargeState();
        });
        $('rechargeForm').addEventListener('submit', function (event) {
            event.preventDefault();
            rechargeNow();
        });
        $('inviteSubSellerForm').addEventListener('submit', function (event) {
            event.preventDefault();
            inviteSubSeller();
        });
        $('subSellerTransferAmountInput').addEventListener(
            'input',
            function () {
                state.subSellerTransferAmount = $(
                    'subSellerTransferAmountInput'
                ).value.replace(/[^\d]/g, '');
                $('subSellerTransferAmountInput').value =
                    state.subSellerTransferAmount;
                setStatus($('subSellerTransferStatus'), '', '');
                renderSubSellerTransferState();
            }
        );
        $('subSellerTransferForm').addEventListener('submit', function (event) {
            event.preventDefault();
            transferToSubSeller();
        });
        document.querySelectorAll('[data-history-tab]').forEach(function (tab) {
            tab.addEventListener('click', function () {
                state.historyTab = tab.getAttribute('data-history-tab');
                state.historyLimit = 3;
                renderHistory();
            });
        });
        $('historySearchForm').addEventListener('submit', function (event) {
            event.preventDefault();
            state.historyQuery = $('historySearchInput').value.trim();
            state.historyLimit = 3;
            renderHistory();
        });
        $('historyClearButton').addEventListener('click', function () {
            state.historyQuery = '';
            $('historySearchInput').value = '';
            state.historyLimit = 3;
            renderHistory();
        });
        $('loadMoreButton').addEventListener('click', function () {
            state.historyLimit += 3;
            renderHistory();
        });
        document.addEventListener('keydown', function (event) {
            if (event.key !== 'Escape') return;
            closeModal('historyModal');
            closeModal('helpModal');
            closeModal('inviteSubSellerModal');
            closeModal('subSellerTransferModal');
        });
    }

    function render() {
        renderProfile();
        renderBalance();
        renderQuickAmounts();
        renderTarget();
        renderRechargeState();
        renderSubSellers();
        renderSubSellerTransferState();
        renderRecent();
    }

    function init() {
        if (state.isMock) {
            applyMockData();
        } else {
            applyEmptyData();
        }
        render();
        bindEvents();
        if (window.HyAppBridge) {
            window.HyAppBridge.ready({
                page: 'coinseller-center',
                mock: state.isMock,
            });
        }
        if (!state.isMock) loadRealData();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    window.addEventListener('hyapp:i18n-ready', function () {
        render();
        if (!$('historyModal').hidden) renderHistory();
    });
})();
