<?php
// includes/admin/admin-withdrawal-guard.php
//
// [FEAT 1.5.22] GUARDA-COSTAS — Sistema de Auditoria Forense de Levantamentos
//
// Para cada pedido de levantamento, fornece ao admin uma vista detalhada com:
//   1. IDENTIDADE — info completa do artista (conta, histórico, score)
//   2. ORIGEM — para royalties, mostra de que faixas vem o dinheiro,
//      qual o import CSV que gerou, com hash de evidência
//   3. ANTI-FRAUDE — verificações automáticas (prefixo número, primeiro
//      levantamento, valor anómalo, conta banned, sub ativa, etc.)
//   4. CHECKLIST — admin tem de marcar items obrigatórios antes de aprovar
//   5. NOTAS internas — campo livre só para admin
//   6. AUDIT LOG — registo imutável de cada visualização e ação
//
// Padrão de design: similar ao que distribuidoras profissionais (FUGA,
// Symphonic, DistroKid) implementam para AML compliance e prevenção de
// fraude. Cada decisão financeira fica rastreada e justificável.

if ( ! defined( 'ABSPATH' ) ) exit;

/* ============================================================================
 * 1. AUDIT LOG (registo imutável)
 * ============================================================================
 * Princípio: este log NUNCA é apagado nem editado pelo código. Só insere.
 * Permite reconstruir todo o ciclo de vida de qualquer pedido para
 * investigação posterior.
 */

/**
 * Regista uma ação no audit log.
 *
 * @param int    $withdrawal_id ID do pedido em rmbz_withdrawal_requests
 * @param string $action  Slug da ação (created/viewed/checklist_updated/note_updated/approved/rejected/etc.)
 * @param string $details Texto livre descrevendo a ação (opcional)
 */
function rmbz_wg_log( $withdrawal_id, $action, $details = '' ) {
    global $wpdb;
    if ( ! $withdrawal_id ) return false;
    $table = $wpdb->prefix . 'rmbz_withdrawal_audit_log';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table ) return false;

    $current_user = function_exists('wp_get_current_user') ? wp_get_current_user() : null;
    $actor_login = ($current_user && ! empty($current_user->user_login)) ? $current_user->user_login : 'system';

    return $wpdb->insert( $table, [
        'withdrawal_id' => (int) $withdrawal_id,
        'actor_login'   => $actor_login,
        'actor_ip'      => isset($_SERVER['REMOTE_ADDR']) ? substr( sanitize_text_field( $_SERVER['REMOTE_ADDR'] ), 0, 45 ) : null,
        'action'        => substr($action, 0, 40),
        'details'       => $details ? mb_substr($details, 0, 5000) : null,
        'created_at'    => current_time('mysql'),
    ], [ '%d','%s','%s','%s','%s','%s' ] );
}

/**
 * Devolve o histórico completo de um pedido (ordem cronológica).
 */
function rmbz_wg_get_log( $withdrawal_id ) {
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_withdrawal_audit_log';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table ) return [];
    return $wpdb->get_results( $wpdb->prepare(
        "SELECT * FROM $table WHERE withdrawal_id = %d ORDER BY created_at ASC, id ASC",
        $withdrawal_id
    ) );
}

/* ============================================================================
 * 2. REVIEW STATE (checklist + notas + score)
 * ============================================================================ */

// Itens obrigatórios da checklist. A ordem é exibição.
/**
 * Items da checklist.
 *
 * Estrutura por item: ['label' => '...', 'critical' => bool, 'condition' => callable|null]
 *
 *  - critical: quando true, o item exige motivo obrigatório ao ser marcado
 *              (ver rmbz_wg_checklist_complete) e marca-se a vermelho na UI.
 *  - condition: callable que recebe ($withdrawal, $report) e devolve bool;
 *               quando devolve false, o item é OMITIDO da checklist deste pedido.
 *               Quando null, o item aparece sempre.
 *
 * @param object|null $withdrawal Pedido (opcional). Quando passado, items
 *                                condicionais são filtrados consoante o caso.
 * @param array|null  $report     Relatório forense (opcional). Permite
 *                                condições baseadas em flags já detectadas.
 */
function rmbz_wg_checklist_items( $withdrawal = null, $report = null ) {
    $items = [
        'identity_verified'   => [
            'label'    => 'Confirmei a identidade do artista (nome bate com a conta)',
            'critical' => false,
        ],
        'balance_legitimate'  => [
            'label'    => 'Validei que o saldo é legítimo (sem entradas suspeitas)',
            'critical' => false,
        ],
        'phone_verified'      => [
            'label'    => 'Validei o número de telefone com a operadora',
            'critical' => false,
        ],
        'no_red_flags'        => [
            'label'    => 'Verifiquei que não há sinais de fraude (banimentos, contas duplicadas)',
            'critical' => false,
        ],
        // [NOVO] Aparece SÓ quando o número destino é de outra wallet activa
        // (flag CRITICAL destination_is_artist_account). Exige motivo —
        // o suporte tem de ter falado com o artista TITULAR do número.
        'cross_artist_authorized' => [
            'label'     => 'Contactei o artista titular do número destino e confirmou que autoriza este pagamento',
            'critical'  => true,
            'condition' => function( $withdrawal, $report ) {
                if ( ! $report || empty( $report['risk_flags'] ) ) return false;
                foreach ( $report['risk_flags'] as $flag ) {
                    if ( ( $flag['code'] ?? '' ) === 'destination_is_artist_account' ) return true;
                }
                return false;
            },
        ],
        'royalties_audited'   => [
            'label'    => 'Para Royalties: validei que o import CSV está aprovado e é legítimo',
            'critical' => false,
        ],
        'transfer_executed'   => [
            'label'    => 'Já efetuei a transferência via M-Pesa/E-Mola e tenho comprovativo',
            'critical' => false,
        ],
    ];

    // Aplicar condition() para filtrar items que não aplicam a este pedido
    if ( $withdrawal !== null ) {
        $items = array_filter( $items, function( $item ) use ( $withdrawal, $report ) {
            if ( empty( $item['condition'] ) ) return true;
            return (bool) call_user_func( $item['condition'], $withdrawal, $report );
        });
    }

    return $items;
}

/**
 * Devolve o estado atual da revisão (lazy-create se primeira vez).
 * Devolve sempre um objecto/array com os campos preenchidos por defeito.
 */
function rmbz_wg_get_review( $withdrawal_id ) {
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_withdrawal_review';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table ) {
        // Devolver default sem persistir
        return (object) [
            'withdrawal_id'    => $withdrawal_id,
            'checklist_json'   => '{}',
            'admin_notes'      => '',
            'risk_score'       => 0,
            'risk_flags_json'  => '[]',
            'first_viewed_at'  => null,
            'last_viewed_by'   => null,
            'last_updated'     => null,
            '_checklist'       => [],
            '_risk_flags'      => [],
        ];
    }

    $row = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM $table WHERE withdrawal_id = %d",
        $withdrawal_id
    ) );

    if ( ! $row ) {
        $wpdb->insert( $table, [
            'withdrawal_id'   => $withdrawal_id,
            'checklist_json'  => '{}',
            'admin_notes'     => '',
            'risk_score'      => 0,
            'risk_flags_json' => '[]',
            'first_viewed_at' => current_time('mysql'),
            'last_viewed_by'  => function_exists('wp_get_current_user') ? wp_get_current_user()->user_login : 'system',
            'last_updated'    => current_time('mysql'),
        ], [ '%d','%s','%s','%d','%s','%s','%s','%s' ] );
        $row = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $table WHERE withdrawal_id = %d", $withdrawal_id ) );
    }

    if ( $row ) {
        $row->_checklist  = json_decode( $row->checklist_json ?: '{}', true ) ?: [];
        $row->_risk_flags = json_decode( $row->risk_flags_json ?: '[]', true ) ?: [];
    }
    return $row;
}

function rmbz_wg_save_checklist( $withdrawal_id, $checklist_array ) {
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_withdrawal_review';
    rmbz_wg_get_review($withdrawal_id); // garante que a row existe
    return $wpdb->update( $table,
        [
            'checklist_json' => wp_json_encode( $checklist_array ),
            'last_updated'   => current_time('mysql'),
        ],
        [ 'withdrawal_id' => $withdrawal_id ]
    );
}

function rmbz_wg_save_notes( $withdrawal_id, $notes ) {
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_withdrawal_review';
    rmbz_wg_get_review($withdrawal_id);
    return $wpdb->update( $table,
        [
            'admin_notes'  => $notes,
            'last_updated' => current_time('mysql'),
        ],
        [ 'withdrawal_id' => $withdrawal_id ]
    );
}

/**
 * Devolve true se TODOS os items obrigatórios estão marcados — E, para
 * items `critical`, têm um motivo preenchido (pelo menos 10 caracteres).
 *
 * Aceita dois formatos no checklist_json (backwards-compatible):
 *  - Legacy:  { "identity_verified": true }
 *  - Novo:    { "identity_verified": { "done": true, "reason": "..." } }
 */
function rmbz_wg_checklist_complete( $withdrawal_id, $withdrawal = null, $report = null ) {
    $review = rmbz_wg_get_review( $withdrawal_id );
    // Resolver $withdrawal se não foi passado (para items condicionais)
    if ( $withdrawal === null ) {
        global $wpdb;
        $withdrawal = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}rmbz_withdrawal_requests WHERE id = %d",
            $withdrawal_id
        ) );
    }
    $items = rmbz_wg_checklist_items( $withdrawal, $report );

    foreach ( $items as $key => $meta ) {
        $entry = $review->_checklist[$key] ?? null;
        // Backwards-compat: aceita bool ou {done, reason}
        $done   = is_array($entry) ? ! empty($entry['done']) : (bool) $entry;
        $reason = is_array($entry) ? trim( (string) ( $entry['reason'] ?? '' ) ) : '';

        if ( ! $done ) return false;

        // Items críticos exigem motivo com >= 10 caracteres
        if ( ! empty( $meta['critical'] ) && strlen( $reason ) < 10 ) {
            return false;
        }
    }
    return true;
}

/**
 * Helper: extrai {done, reason} de uma entry guardada, lidando com formato
 * legacy (bool). Usado pela vista para pintar checkboxes e textareas.
 */
function rmbz_wg_checklist_entry( $review, $key ) {
    $entry = $review->_checklist[$key] ?? null;
    if ( is_array($entry) ) {
        return [
            'done'   => ! empty( $entry['done'] ),
            'reason' => (string) ( $entry['reason'] ?? '' ),
        ];
    }
    return [
        'done'   => (bool) $entry,
        'reason' => '',
    ];
}

/* ============================================================================
 * 3. ANÁLISE FORENSE (sinais de risco + origem do dinheiro)
 * ============================================================================ */

/**
 * Constrói o "report forense" completo de um pedido.
 * Devolve array com chaves: identity, source, risk_signals, score.
 */
function rmbz_wg_build_forensic_report( $withdrawal ) {
    global $wpdb;

    $report = [
        'identity'    => [],
        'source'      => [ 'type' => null, 'evidence' => [] ],
        'risk_flags'  => [],
        'risk_score'  => 0,
    ];
    if ( ! $withdrawal ) return $report;

    // -----------------------------------------------------
    // IDENTIDADE
    // -----------------------------------------------------
    $tel = $withdrawal->user_telemovel;
    $wallet = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s", $tel
    ) );

    $report['identity'] = [
        'telemovel'       => $tel,
        'nome'            => $wallet ? $wallet->user_nome : '(sem nome)',
        'email'           => $wallet ? $wallet->user_email : null,
        'provincia'       => $wallet ? $wallet->user_provincia : null,
        'is_banned'       => $wallet ? (bool)$wallet->is_banned : false,
        'is_creator'      => $wallet ? (bool)$wallet->is_creator : false,
        'wallet_balance'  => $wallet ? (float)$wallet->balance : 0,
        'created'         => null, // wallets não tem created_at
        'last_updated'    => $wallet ? $wallet->last_updated : null,
    ];

    // Subscrição ativa?
    $sub_table = $wpdb->prefix . 'rmbz_subscriptions';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$sub_table'") === $sub_table ) {
        $sub = $wpdb->get_row( $wpdb->prepare(
            "SELECT id, end_date FROM $sub_table WHERE user_telemovel = %s AND status = 'active' AND end_date > %s ORDER BY end_date DESC LIMIT 1",
            $tel, current_time('mysql')
        ) );
        $report['identity']['has_subscription'] = (bool) $sub;
        $report['identity']['subscription_end'] = $sub ? $sub->end_date : null;
    }

    // Histórico de levantamentos
    $past_wd = $wpdb->get_results( $wpdb->prepare(
        "SELECT id, amount, status, request_date, processed_date, payment_method, payment_details
         FROM {$wpdb->prefix}rmbz_withdrawal_requests
         WHERE user_telemovel = %s AND id != %d
         ORDER BY request_date DESC LIMIT 10",
        $tel, $withdrawal->id
    ) );
    $report['identity']['past_withdrawals'] = $past_wd ?: [];
    $report['identity']['total_approved'] = (float) $wpdb->get_var( $wpdb->prepare(
        "SELECT COALESCE(SUM(amount),0) FROM {$wpdb->prefix}rmbz_withdrawal_requests
         WHERE user_telemovel = %s AND status = 'aprovado'", $tel
    ) );
    $report['identity']['total_rejected'] = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM {$wpdb->prefix}rmbz_withdrawal_requests
         WHERE user_telemovel = %s AND status = 'rejeitado'", $tel
    ) );

    // -----------------------------------------------------
    // ORIGEM DO DINHEIRO
    // -----------------------------------------------------
    $source = isset($withdrawal->source) ? $withdrawal->source : 'wallet';
    $report['source']['type'] = $source;

    if ( $source === 'royalties' ) {
        // Tentar achar a transação no ledger USD que originou esta conversão.
        // O insert em rmbz_secure_transfer_usd_to_mt cria um ledger entry
        // com type='withdrawal_to_wallet' por volta da hora deste pedido.
        $ledger_table = $wpdb->prefix . 'rmbz_distro_ledger';
        if ( $wpdb->get_var("SHOW TABLES LIKE '$ledger_table'") === $ledger_table ) {
            // Procurar conversões USD→MT do mesmo artista numa janela de 5 min antes do pedido
            $window_start = date('Y-m-d H:i:s', strtotime($withdrawal->request_date) - 300);
            $window_end   = $withdrawal->request_date;
            $conversion = $wpdb->get_row( $wpdb->prepare(
                "SELECT * FROM $ledger_table
                 WHERE artist_telemovel = %s
                   AND type = 'withdrawal_to_wallet'
                   AND created_at BETWEEN %s AND %s
                 ORDER BY created_at DESC LIMIT 1",
                $tel, $window_start, $window_end
            ) );
            $report['source']['evidence']['conversion_ledger'] = $conversion;

            // Acumular as últimas linhas do ledger USD que somaram o saldo
            // (créditos antes da conversão, até atingirem o valor convertido)
            if ( $conversion ) {
                $abs_converted = abs( (float) $conversion->amount );
                $credits = $wpdb->get_results( $wpdb->prepare(
                    "SELECT * FROM $ledger_table
                     WHERE artist_telemovel = %s
                       AND amount > 0
                       AND created_at < %s
                     ORDER BY created_at DESC LIMIT 50",
                    $tel, $conversion->created_at
                ) );
                // Acumular até cobrir o valor da conversão
                $sum = 0; $contrib = [];
                foreach ( $credits as $c ) {
                    $contrib[] = $c;
                    $sum += (float) $c->amount;
                    if ( $sum >= $abs_converted ) break;
                }
                $report['source']['evidence']['contributing_credits'] = $contrib;
            }

            // Faixas com streams recentes deste artista (top 10)
            $tracks_table = $wpdb->prefix . 'rmbz_distro_tracks';
            $releases_table = $wpdb->prefix . 'rmbz_distro_releases';
            $daily_table = $wpdb->prefix . 'rmbz_distro_daily_stats';
            if ( $wpdb->get_var("SHOW TABLES LIKE '$daily_table'") === $daily_table ) {
                $top_tracks = $wpdb->get_results( $wpdb->prepare(
                    "SELECT t.id AS track_id, t.track_title, t.isrc_code, r.title AS release_title,
                            SUM(d.streams) AS streams, SUM(d.sales) AS earnings_usd,
                            MAX(d.report_date) AS latest_date
                     FROM $daily_table d
                     JOIN $tracks_table t   ON d.track_id   = t.id
                     JOIN $releases_table r ON t.release_id = r.id
                     WHERE d.artist_telemovel = %s
                     GROUP BY t.id
                     ORDER BY earnings_usd DESC
                     LIMIT 10",
                    $tel
                ) );
                $report['source']['evidence']['top_tracks'] = $top_tracks ?: [];
            }
        }

        // Último import processado (para ligação ao admin import audit)
        $log = get_option('rmbz_import_log', []);
        $report['source']['evidence']['last_import_global'] = ! empty($log) ? end($log) : null;
    }
    else {
        // FONTE: WALLET — mostrar últimas transacções da carteira que justificam saldo
        $trans_table = $wpdb->prefix . 'rmbz_wallet_transactions';
        $recent = $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM $trans_table
             WHERE user_telemovel = %s
               AND transaction_date <= %s
             ORDER BY transaction_date DESC LIMIT 20",
            $tel, $withdrawal->request_date
        ) );
        $report['source']['evidence']['recent_transactions'] = $recent ?: [];
    }

    // -----------------------------------------------------
    // SINAIS DE RISCO (cada um soma X ao score)
    // -----------------------------------------------------
    $flags = [];

    // ⚠️ Conta banida = stop completo
    if ( $report['identity']['is_banned'] ) {
        $flags[] = [ 'level' => 'critical', 'code' => 'banned', 'msg' => 'Conta marcada como BANIDA. Não aprovar sob nenhuma circunstância.' ];
    }

    // [PHP 8.1] Cast explícito para string evita "Passing null to..." em
    // pedidos antigos onde estes campos podem estar NULL.
    $payment_method_raw = (string) ( $withdrawal->payment_method ?? '' );
    $payment_details_raw = (string) ( $withdrawal->payment_details ?? '' );

    // Validar prefixo do número escolhido vs operador
    $payment_method = strtolower( str_replace([' ','-'], '', $payment_method_raw) );
    $phone = preg_replace('/\D/', '', $payment_details_raw);
    if ( strlen($phone) === 12 && substr($phone,0,3) === '258' ) $phone = substr($phone, 3);
    $prefix = strlen($phone) >= 2 ? substr($phone, 0, 2) : '';

    if ( ! in_array($prefix, ['84','85','86','87'], true) ) {
        $flags[] = [ 'level' => 'high', 'code' => 'phone_invalid', 'msg' => 'Número não tem prefixo válido (esperado 84/85 M-Pesa ou 86/87 E-Mola).' ];
    }
    elseif ( in_array($payment_method, ['mpesa','m-pesa'], true) && ! in_array($prefix, ['84','85'], true) ) {
        $flags[] = [ 'level' => 'high', 'code' => 'phone_method_mismatch', 'msg' => "Método é M-Pesa mas o número {$phone} é da Movitel ({$prefix})." ];
    }
    elseif ( in_array($payment_method, ['emola','e-mola'], true) && ! in_array($prefix, ['86','87'], true) ) {
        $flags[] = [ 'level' => 'high', 'code' => 'phone_method_mismatch', 'msg' => "Método é E-Mola mas o número {$phone} é da Vodacom ({$prefix})." ];
    }

    // Número de pagamento ≠ telemóvel da conta = bandeira amarela (legítimo, mas notar)
    $tel_clean = preg_replace('/\D/', '', $tel);
    if ( strlen($tel_clean) === 12 && substr($tel_clean,0,3) === '258' ) $tel_clean = substr($tel_clean, 3);
    if ( $phone !== $tel_clean && strlen($phone) === 9 ) {
        $flags[] = [ 'level' => 'medium', 'code' => 'phone_diff_account', 'msg' => "Número de levantamento ({$phone}) é diferente do telemóvel da conta ({$tel_clean}). Pode ser legítimo (familiar, conta de empresa) mas requer confirmação." ];
    }

    // Primeiro levantamento da conta = +cuidado (dobrar verificação)
    $past_count = is_array($report['identity']['past_withdrawals']) ? count($report['identity']['past_withdrawals']) : 0;
    if ( $past_count === 0 ) {
        $flags[] = [ 'level' => 'medium', 'code' => 'first_withdrawal', 'msg' => 'PRIMEIRO levantamento desta conta. Validar identidade com extra cuidado.' ];
    }

    // Histórico de rejeições > 0
    if ( $report['identity']['total_rejected'] > 0 ) {
        $flags[] = [ 'level' => 'medium', 'code' => 'past_rejections', 'msg' => 'Conta tem ' . $report['identity']['total_rejected'] . ' levantamento(s) rejeitado(s) anteriormente.' ];
    }

    // Sem subscrição (não bloqueante mas notar)
    if ( isset($report['identity']['has_subscription']) && ! $report['identity']['has_subscription'] ) {
        $flags[] = [ 'level' => 'low', 'code' => 'no_subscription', 'msg' => 'Conta sem subscrição ativa.' ];
    }

    // Valor anómalo (mais de 3x maior que o último aprovado)
    if ( $past_count > 0 ) {
        $last_amounts = array_map( fn($w) => (float)$w->amount, array_filter($past_wd, fn($w) => $w->status === 'aprovado') );
        if ( ! empty($last_amounts) ) {
            $avg = array_sum($last_amounts) / count($last_amounts);
            if ( $avg > 0 && (float)$withdrawal->amount > $avg * 3 ) {
                $flags[] = [ 'level' => 'medium', 'code' => 'anomalous_amount', 'msg' => 'Valor (' . number_format($withdrawal->amount,2,',','.') . ' MT) é mais de 3x a média histórica (' . number_format($avg,2,',','.') . ' MT).' ];
            }
        }
    }

    // Verificar se outras contas usam o mesmo número de pagamento
    if ( ! empty($phone) ) {
        $other_uses = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(DISTINCT user_telemovel) FROM {$wpdb->prefix}rmbz_withdrawal_requests
             WHERE payment_details LIKE %s AND user_telemovel != %s",
            '%' . $wpdb->esc_like($phone) . '%', $tel
        ) );
        if ( $other_uses > 0 ) {
            $flags[] = [ 'level' => 'high', 'code' => 'shared_phone', 'msg' => "O número {$phone} já foi usado por {$other_uses} outra(s) conta(s) para receber levantamentos. Possível conta dupla / mula." ];
        }

        // ──────────────────────────────────────────────────────────────────
        // [CRITICAL] Número destino É a wallet de OUTRO ARTISTA REGISTADO.
        // ──────────────────────────────────────────────────────────────────
        // Tentamos várias normalizações de telemóvel porque o handoff avisa
        // que o mesmo número pode estar guardado como "+258...", "258...",
        // ou só local. Comparamos o sufixo de 9 dígitos para apanhar todas
        // as variantes.
        $phone_tail = substr( preg_replace('/\D/', '', $phone), -9 );
        if ( strlen( $phone_tail ) === 9 ) {
            // Sufixo do próprio artista (para excluir si próprio)
            $self_tail = substr( preg_replace('/\D/', '', $tel), -9 );
            $cross_artist = $wpdb->get_row( $wpdb->prepare(
                "SELECT user_telemovel, user_nome, balance
                   FROM {$wpdb->prefix}rmbz_wallets
                  WHERE RIGHT(REPLACE(REPLACE(user_telemovel,'+',''),' ',''), 9) = %s
                    AND RIGHT(REPLACE(REPLACE(user_telemovel,'+',''),' ',''), 9) != %s
                  LIMIT 1",
                $phone_tail, $self_tail
            ) );
            if ( $cross_artist ) {
                $other_name = trim( (string) $cross_artist->user_nome );
                $other_label = ( $other_name !== '' && strcasecmp( $other_name, 'Artista' ) !== 0 )
                    ? $other_name . ' (' . $cross_artist->user_telemovel . ')'
                    : $cross_artist->user_telemovel;
                $flags[] = [
                    'level' => 'critical',
                    'code'  => 'destination_is_artist_account',
                    'msg'   => "O número de destino pertence a OUTRO artista registado: <strong>{$other_label}</strong>. " .
                               "O suporte tem de contactar este artista para confirmar que autoriza o pagamento. " .
                               "Aprovação BLOQUEADA até a checklist incluir o motivo do contacto.",
                ];
            }
        }
    }

    // Royalties sem CSV importado recente
    if ( $source === 'royalties' && empty( $report['source']['evidence']['last_import_global'] ) ) {
        $flags[] = [ 'level' => 'high', 'code' => 'royalties_no_imports', 'msg' => 'Pedido de Royalties mas a 1MZ nunca importou nenhum CSV. Os ganhos podem ter sido lançados manualmente — investigar.' ];
    }

    // ──────────────────────────────────────────────────────────────────────
    // [DS 1.5.112] DETECÇÕES NOVAS — ajudam admin a perceber casos onde o
    // dinheiro pode não estar a fluir como devia.
    // ──────────────────────────────────────────────────────────────────────

    // ▸ A) Wallet MT contaminada por bug pre-1.5.110 (USD-tratado-como-MT)
    //   Se o artista tem créditos errados ainda não corrigidos, aviso forte.
    if ( function_exists('rmbz_wallet_mt_list_affected') ) {
        $contaminated = $wpdb->get_row( $wpdb->prepare(
            "SELECT
                SUM(CASE
                    WHEN type = 'royalty_payout'
                      AND ( details LIKE '%%[royalty_import:%%' OR details LIKE '%%[match_review:%%' )
                    THEN amount ELSE 0 END
                ) AS credited,
                SUM(CASE
                    WHEN type = 'royalty_revert'
                      AND details LIKE '%%[revert:%%'
                    THEN amount ELSE 0 END
                ) AS reverted,
                SUM(CASE
                    WHEN type = 'mt_fix_correction'
                      AND details LIKE '%%[mtfix:%%'
                    THEN amount ELSE 0 END
                ) AS already_fixed
             FROM {$wpdb->prefix}rmbz_wallet_transactions
             WHERE user_telemovel = %s",
            $tel
        ) );
        $net_garbage = (float) ($contaminated->credited ?? 0)
                     + (float) ($contaminated->reverted ?? 0)
                     + (float) ($contaminated->already_fixed ?? 0);
        if ( $net_garbage > 0.01 ) {
            $flags[] = [
                'level' => 'high',
                'code'  => 'wallet_contaminated_pre110',
                'msg'   => sprintf(
                    'A wallet MT desta conta tem %.2f MT de créditos USD-tratados-como-MT (bug pre-1.5.110) ainda por corrigir. Investiga em Diagnóstico → Secção 5 antes de aprovar.',
                    $net_garbage
                ),
            ];
            $report['source']['evidence']['mt_contamination'] = [
                'credited'      => (float) ($contaminated->credited ?? 0),
                'reverted'      => (float) ($contaminated->reverted ?? 0),
                'already_fixed' => (float) ($contaminated->already_fixed ?? 0),
                'net_garbage'   => $net_garbage,
            ];
        }
    }

    // ▸ B) Reembolsos USD recentes (últimos 30 dias)
    //   Se houve levantamento rejeitado recentemente, o dinheiro voltou
    //   a distro_stats. Útil para o admin saber se o saldo actual já
    //   inclui dinheiro reembolsado.
    $ledger_table_b = $wpdb->prefix . 'rmbz_distro_ledger';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$ledger_table_b'") === $ledger_table_b ) {
        $recent_refunds = $wpdb->get_results( $wpdb->prepare(
            "SELECT id, amount, description, created_at, reverted_at
             FROM $ledger_table_b
             WHERE artist_telemovel = %s
               AND type = 'withdrawal_rejected_revert'
               AND created_at >= DATE_SUB(%s, INTERVAL 30 DAY)
             ORDER BY created_at DESC
             LIMIT 10",
            $tel, $withdrawal->request_date
        ) );
        if ( ! empty($recent_refunds) ) {
            $total_refunded = 0;
            $count_active = 0;
            foreach ( $recent_refunds as $rr ) {
                if ( empty($rr->reverted_at) ) {
                    $total_refunded += (float) $rr->amount;
                    $count_active++;
                }
            }
            if ( $count_active > 0 ) {
                $flags[] = [
                    'level' => 'medium',
                    'code'  => 'recent_refunds',
                    'msg'   => sprintf(
                        '%d reembolso(s) de levantamento rejeitado nos últimos 30 dias (total $%.2f USD em distro_stats). Confirma que o dinheiro está coerente antes de aprovar novo pedido.',
                        $count_active,
                        $total_refunded
                    ),
                ];
            }
            $report['source']['evidence']['recent_refunds'] = $recent_refunds;
        }
    }

    // ▸ C) Discrepância USD ↔ MT
    //   Se o pedido é da carteira MT mas o saldo MT é muito superior à
    //   expectativa (distro_stats USD × câmbio), pode haver dinheiro que
    //   entrou pela porta errada.
    if ( $source === 'wallet' && $wallet ) {
        $stats_table = $wpdb->prefix . 'rmbz_distro_stats';
        if ( $wpdb->get_var("SHOW TABLES LIKE '$stats_table'") === $stats_table ) {
            $usd_balance = (float) $wpdb->get_var( $wpdb->prepare(
                "SELECT COALESCE(total_earnings, 0) FROM $stats_table WHERE artist_telemovel = %s",
                $tel
            ) );
            $mt_balance = (float) $wallet->balance;
            $exchange_rate_now = function_exists('rmbz_get_exchange_rate')
                ? (float) rmbz_get_exchange_rate()
                : 63.50;
            // Apenas alertamos se ambos os saldos são significativos
            if ( $usd_balance >= 1.0 && $mt_balance >= 100 ) {
                $expected_mt_if_all_converted = $usd_balance * $exchange_rate_now;
                $report['source']['evidence']['balance_audit'] = [
                    'usd_balance_distro'         => $usd_balance,
                    'mt_balance_wallet'          => $mt_balance,
                    'exchange_rate_now'          => $exchange_rate_now,
                    'expected_mt_if_converted'   => $expected_mt_if_all_converted,
                ];
            }
        }
    }

    // ▸ D) Imports anulados/rejeitados após data deste pedido
    //   Se o admin anulou um import depois deste pedido ter sido criado,
    //   o saldo do utilizador mudou e o pedido pode ter ficado "preso"
    //   com valor desactualizado.
    $logs_table = $wpdb->prefix . 'rmbz_distro_import_logs';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$logs_table'") === $logs_table ) {
        $reverted_after = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(*) FROM $logs_table
             WHERE ( reverted_at IS NOT NULL AND reverted_at > %s )
                OR ( approval_status = 'rejected' AND approved_at > %s )",
            $withdrawal->request_date, $withdrawal->request_date
        ) );
        if ( $reverted_after > 0 ) {
            $flags[] = [
                'level' => 'medium',
                'code'  => 'imports_reverted_after_request',
                'msg'   => sprintf(
                    '%d importação(ões) foram anuladas/rejeitadas DEPOIS deste pedido ter sido criado. O valor actual do saldo do artista pode já não corresponder ao que era no momento do pedido.',
                    $reverted_after
                ),
            ];
            $report['source']['evidence']['imports_reverted_after_request'] = $reverted_after;
        }
    }

    // ──────────────────────────────────────────────────────────────────────
    // FIM das detecções 1.5.112
    // ──────────────────────────────────────────────────────────────────────

    // ──────────────────────────────────────────────────────────────────────
    // Pós-processamento: deduplicar avisos redundantes.
    //
    // Quando o número destino pertence a outro artista registado
    // (destination_is_artist_account = CRITICAL), o aviso
    // phone_diff_account (MEDIUM) é redundante — a flag crítica já
    // contém a informação mais forte. Removemos para não saturar o
    // ecrã do admin com duplicação.
    // ──────────────────────────────────────────────────────────────────────
    $has_critical_cross = false;
    foreach ( $flags as $f ) {
        if ( ( $f['code'] ?? '' ) === 'destination_is_artist_account' ) {
            $has_critical_cross = true;
            break;
        }
    }
    if ( $has_critical_cross ) {
        $flags = array_values( array_filter( $flags, function( $f ) {
            return ( $f['code'] ?? '' ) !== 'phone_diff_account';
        } ) );
    }

    // Calcular score final (0-100; mais alto = mais arriscado)
    $score = 0;
    foreach ( $flags as $f ) {
        switch ( $f['level'] ) {
            case 'critical': $score += 100; break;
            case 'high':     $score += 30;  break;
            case 'medium':   $score += 15;  break;
            case 'low':      $score += 5;   break;
        }
    }
    $score = min(100, $score);

    $report['risk_flags'] = $flags;
    $report['risk_score'] = $score;

    // [1.6.1] Permitir que extensões (ex: análise de origem) acrescentem
    // mais flags e recalculem o score. Ver admin-withdrawal-guard-origin.php.
    $report = apply_filters( 'rmbz_wg_forensic_report', $report, $withdrawal );

    return $report;
}

/* ============================================================================
 * 4. SUBMENU + ROTEAMENTO
 * ============================================================================ */

add_action( 'admin_menu', function () {
    // [BUGFIX 1.5.24] Página escondida do menu, à prova de PHP 8.1+.
    //
    // Histórico do problema:
    //   1.5.22 — usámos add_submenu_page(null, ...). Em PHP 8.1+ o null
    //            é passado a strpos/str_replace internamente → 2 deprecated.
    //   1.5.23 — mudámos para add_submenu_page('', ...). Os warnings
    //            anteriores sumiram MAS apareceu um novo: o WordPress
    //            não consegue determinar o $admin_title (página sem parent),
    //            então admin-header.php:41 chama strip_tags(null).
    //
    // Solução definitiva (padrão WooCommerce): registamos a página como
    // sub-item de 'options.php' (que existe sempre) — assim o admin_title
    // funciona — e depois removemos do menu visível para parecer escondida.
    add_submenu_page(
        'options.php',
        'Guarda-Costas — Detalhe de Levantamento',
        'Guarda-Costas',
        'manage_options',
        'rmbz-withdrawal-guard',
        'rmbz_wg_render_detail_page'
    );
}, 30 );

// Remover do menu visível (continua acessível por URL — é o que queremos).
add_action( 'admin_head', function () {
    remove_submenu_page( 'options.php', 'rmbz-withdrawal-guard' );
}, 999 );

/* ============================================================================
 * 5. HANDLERS (admin-post)
 * ============================================================================ */

// Guardar checklist
add_action( 'admin_post_rmbz_wg_save_checklist', function () {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    check_admin_referer('rmbz_wg_review');

    $wd_id = isset($_POST['withdrawal_id']) ? absint($_POST['withdrawal_id']) : 0;
    if ( ! $wd_id ) wp_die('Pedido inválido.');

    global $wpdb;
    $withdrawal = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}rmbz_withdrawal_requests WHERE id = %d",
        $wd_id
    ) );

    // Reconstruir o relatório para que os items condicionais apareçam
    // na lista (sem isto, items críticos como cross_artist_authorized
    // não seriam guardados mesmo quando aplicáveis).
    $report = function_exists('rmbz_wg_build_forensic_report')
        ? rmbz_wg_build_forensic_report( $withdrawal )
        : null;
    $items = rmbz_wg_checklist_items( $withdrawal, $report );

    $checklist = [];
    foreach ( $items as $key => $meta ) {
        $done   = ! empty( $_POST[ 'check_' . $key ] );
        $reason = isset( $_POST[ 'reason_' . $key ] )
            ? trim( wp_unslash( (string) $_POST[ 'reason_' . $key ] ) )
            : '';
        // Truncar a 2000 chars para evitar payloads abusivos
        if ( strlen( $reason ) > 2000 ) $reason = substr( $reason, 0, 2000 );

        // Formato novo: sempre array {done, reason}. Backwards-compat:
        // o leitor (checklist_entry) aceita o legacy boolean também.
        $checklist[$key] = [
            'done'   => $done,
            'reason' => $reason,
        ];
    }

    rmbz_wg_save_checklist( $wd_id, $checklist );
    rmbz_wg_log(
        $wd_id,
        'checklist_updated',
        'Checklist guardada: ' . count(array_filter($checklist, fn($e) => ! empty($e['done']))) . '/' . count($items) . ' marcados.'
    );

    wp_safe_redirect( add_query_arg(['page'=>'rmbz-withdrawal-guard','id'=>$wd_id,'msg'=>'check_saved'], admin_url('admin.php')) );
    exit;
});

// Guardar nota
add_action( 'admin_post_rmbz_wg_save_note', function () {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    check_admin_referer('rmbz_wg_review');

    $wd_id = isset($_POST['withdrawal_id']) ? absint($_POST['withdrawal_id']) : 0;
    if ( ! $wd_id ) wp_die('Pedido inválido.');

    $note = isset($_POST['admin_notes']) ? sanitize_textarea_field( wp_unslash($_POST['admin_notes']) ) : '';
    rmbz_wg_save_notes( $wd_id, $note );
    rmbz_wg_log( $wd_id, 'note_updated', 'Nota interna actualizada (' . strlen($note) . ' caracteres).' );

    wp_safe_redirect( add_query_arg(['page'=>'rmbz-withdrawal-guard','id'=>$wd_id,'msg'=>'note_saved'], admin_url('admin.php')) );
    exit;
});

/* ============================================================================
 * 6. HOOK NO HANDLER DE APROVAÇÃO (bloquear se checklist incompleta)
 * ============================================================================
 * Em vez de modificar admin-handlers.php (mais arriscado), interceptamos
 * o pedido GET de aprovação ANTES dele correr. Se a checklist não estiver
 * completa, redirecionamos para a vista de detalhe com aviso.
 */
add_action( 'admin_init', function () {
    if ( ! isset($_GET['action']) || $_GET['action'] !== 'rmbz_approve_withdrawal' ) return;
    if ( ! isset($_GET['req_id']) ) return;
    if ( ! current_user_can('manage_options') ) return;

    $req_id = absint($_GET['req_id']);
    if ( ! $req_id ) return;

    // Resolver withdrawal+report para validar items críticos condicionais
    // (ex: cross_artist_authorized só existe se a flag destination_is_artist_account
    // estiver activa — sem isto o handler ignoraria o item e deixaria passar).
    global $wpdb;
    $withdrawal = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}rmbz_withdrawal_requests WHERE id = %d",
        $req_id
    ) );
    $report = $withdrawal ? rmbz_wg_build_forensic_report( $withdrawal ) : null;

    if ( ! rmbz_wg_checklist_complete( $req_id, $withdrawal, $report ) ) {
        rmbz_wg_log( $req_id, 'approve_blocked', 'Tentativa de aprovação bloqueada — checklist incompleta ou motivo crítico em falta.' );
        wp_safe_redirect( add_query_arg(['page'=>'rmbz-withdrawal-guard','id'=>$req_id,'msg'=>'checklist_incomplete'], admin_url('admin.php')) );
        exit;
    }
    // Senão, deixa a aprovação seguir o caminho normal em admin-handlers.php
}, 5 ); // prioridade 5 = corre antes do handler oficial (10)

// Registar audit log na aprovação/rejeição (hook depois do handler oficial)
add_action( 'admin_post_rmbz_approve_withdrawal', function () {
    if ( isset($_GET['req_id']) ) {
        rmbz_wg_log( absint($_GET['req_id']), 'approved', 'Pedido aprovado pelo admin.' );
    }
}, 20 );
add_action( 'admin_post_rmbz_reject_withdrawal', function () {
    if ( isset($_GET['req_id']) ) {
        rmbz_wg_log( absint($_GET['req_id']), 'rejected', 'Pedido rejeitado pelo admin.' );
    }
}, 20 );

/* ============================================================================
 * 7. VIEW DA PÁGINA DE DETALHE
 * ============================================================================ */

function rmbz_wg_render_detail_page() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');

    global $wpdb;
    $wd_id = isset($_GET['id']) ? absint($_GET['id']) : 0;
    if ( ! $wd_id ) {
        echo '<div class="wrap"><h1>Guarda-Costas</h1><p>Pedido não especificado.</p></div>';
        return;
    }

    $withdrawal = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}rmbz_withdrawal_requests WHERE id = %d", $wd_id
    ) );
    if ( ! $withdrawal ) {
        echo '<div class="wrap"><h1>Guarda-Costas</h1><p>Pedido #' . $wd_id . ' não encontrado.</p></div>';
        return;
    }

    // Registar visualização (e marcar first_viewed_at se for primeira vez)
    $review = rmbz_wg_get_review( $wd_id );
    if ( ! $review->first_viewed_at ) {
        rmbz_wg_log( $wd_id, 'first_view', 'Primeira abertura da vista de detalhe.' );
    } else {
        rmbz_wg_log( $wd_id, 'viewed', 'Vista aberta novamente.' );
    }

    // Construir relatório forense
    $report = rmbz_wg_build_forensic_report( $withdrawal );
    $audit_log = rmbz_wg_get_log( $wd_id );
    $checklist_items = rmbz_wg_checklist_items( $withdrawal, $report );

    // Banner de mensagens
    $msg = isset($_GET['msg']) ? sanitize_key($_GET['msg']) : '';
    ?>
    <div class="wrap rmbz-wg-wrap">
        <h1 style="display:flex; align-items:center; gap:12px;">
            🛡️ Guarda-Costas <span style="font-size:14px; color:var(--rmbz-text-faint, #888); font-weight:normal;">— Pedido #<?php echo $wd_id; ?></span>
        </h1>
        <p style="color:var(--rmbz-text-muted, #666);">Análise forense completa antes de aprovar este levantamento. Cada ação aqui fica registada no audit log.</p>

        <?php if ( $msg === 'checklist_incomplete' ): ?>
            <div class="notice notice-error"><p><strong>⚠️ Aprovação bloqueada</strong> — Marque todos os items obrigatórios da Checklist antes de aprovar.</p></div>
        <?php elseif ( $msg === 'check_saved' ): ?>
            <div class="notice notice-success is-dismissible"><p>Checklist guardada.</p></div>
        <?php elseif ( $msg === 'note_saved' ): ?>
            <div class="notice notice-success is-dismissible"><p>Nota guardada.</p></div>
        <?php endif; ?>

        <a href="<?php echo esc_url( admin_url('admin.php?page=rmbz-pedidos-levantamento') ); ?>" class="button" style="margin-bottom:20px;">← Voltar à lista</a>

        <!-- BANNER DE STATUS + RISK SCORE -->
        <?php
        $score = $report['risk_score'];
        $score_color = $score >= 80 ? '#c0392b' : ($score >= 40 ? '#e67e22' : ($score >= 15 ? '#f39c12' : '#27ae60'));
        $score_label = $score >= 80 ? 'CRÍTICO — Não aprovar sem investigação' : ($score >= 40 ? 'ALTO RISCO' : ($score >= 15 ? 'Atenção' : 'Baixo Risco'));
        ?>
        <div class="rmbz-wg-status-bar" style="background:<?php echo $score_color; ?>; color:var(--rmbz-text-on-color, #fff); padding:14px 20px; border-radius:8px; margin-bottom:20px; display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:15px;">
            <div>
                <strong style="font-size:18px;">Score de Risco: <?php echo $score; ?>/100</strong>
                <span style="opacity:0.9; margin-left:10px;"><?php echo $score_label; ?></span>
            </div>
            <div style="font-size:13px;">
                Estado actual: <strong style="text-transform:uppercase;"><?php echo esc_html($withdrawal->status); ?></strong>
            </div>
        </div>

        <div class="rmbz-wg-grid">

            <!-- COLUNA ESQUERDA -->
            <div class="rmbz-wg-col">

                <!-- 1. PEDIDO -->
                <div class="rmbz-wg-card">
                    <h3>📋 O Pedido</h3>
                    <table class="rmbz-wg-kv">
                        <tr><th>ID</th><td>#<?php echo $wd_id; ?></td></tr>
                        <tr><th>Valor</th><td><strong style="color:var(--rmbz-info-strong, #2563eb); font-size:18px;"><?php echo number_format((float)$withdrawal->amount, 2, ',', '.'); ?> MT</strong></td></tr>
                        <tr><th>Fonte</th><td>
                            <?php if ( ($withdrawal->source ?? 'wallet') === 'royalties' ): ?>
                                <span class="rmbz-wg-pill" style="background:#fff3cd;color:#856404;">🎵 Royalties (USD convertidos)</span>
                            <?php else: ?>
                                <span class="rmbz-wg-pill" style="background:#d1ecf1;color:#0c5460;">💼 Carteira (MT directos)</span>
                            <?php endif; ?>
                        </td></tr>
                        <tr><th>Método</th><td><?php echo esc_html($withdrawal->payment_method); ?></td></tr>
                        <tr><th>Número destino</th><td><strong style="font-family:monospace;"><?php echo esc_html($withdrawal->payment_details); ?></strong></td></tr>
                        <tr><th>Data do pedido</th><td><?php echo esc_html( mysql2date('d/m/Y H:i:s', $withdrawal->request_date) ); ?></td></tr>
                        <?php if ( $withdrawal->processed_date ): ?>
                            <tr><th>Processado</th><td><?php echo esc_html( mysql2date('d/m/Y H:i:s', $withdrawal->processed_date) ); ?></td></tr>
                        <?php endif; ?>
                    </table>
                </div>

                <!-- 2. IDENTIDADE -->
                <div class="rmbz-wg-card">
                    <h3>👤 Identidade do Artista</h3>
                    <?php $i = $report['identity']; ?>
                    <table class="rmbz-wg-kv">
                        <tr><th>Nome</th><td><strong><?php echo esc_html($i['nome']); ?></strong></td></tr>
                        <tr><th>Telemóvel da conta</th><td><code><?php echo esc_html($i['telemovel']); ?></code></td></tr>
                        <tr><th>Email</th><td><?php echo esc_html($i['email'] ?: '—'); ?></td></tr>
                        <tr><th>Província</th><td><?php echo esc_html($i['provincia'] ?: '—'); ?></td></tr>
                        <tr><th>Estado</th><td>
                            <?php if ( $i['is_banned'] ): ?>
                                <span class="rmbz-wg-pill" style="background:#f8d7da;color:var(--rmbz-danger-strong, #721c24);">🚫 BANIDA</span>
                            <?php else: ?>
                                <span class="rmbz-wg-pill" style="background:#d4edda;color:var(--rmbz-success-strong, #166534);">✅ Activa</span>
                            <?php endif; ?>
                            <?php if ( ! empty($i['has_subscription']) ): ?>
                                <span class="rmbz-wg-pill" style="background:#fff3cd;color:#856404;">⭐ Subscrição até <?php echo date('d/m/Y', strtotime($i['subscription_end'])); ?></span>
                            <?php endif; ?>
                        </td></tr>
                        <tr><th>Saldo carteira (agora)</th><td><?php echo number_format($i['wallet_balance'], 2, ',', '.'); ?> MT</td></tr>
                        <tr><th>Total já levantado</th><td><strong><?php echo number_format($i['total_approved'], 2, ',', '.'); ?> MT</strong> (aprovados)</td></tr>
                        <tr><th>Levantamentos passados</th><td>
                            <?php echo count($i['past_withdrawals']); ?> total
                            <?php if ( $i['total_rejected'] > 0 ): ?>
                                · <span style="color:var(--rmbz-danger-strong, #b91c1c);"><?php echo $i['total_rejected']; ?> rejeitado(s)</span>
                            <?php endif; ?>
                        </td></tr>
                    </table>

                    <?php if ( ! empty($i['past_withdrawals']) ): ?>
                    <details style="margin-top:12px;">
                        <summary style="cursor:pointer; color:var(--rmbz-info-strong, #2563eb); font-size:13px;">Ver histórico de levantamentos (<?php echo count($i['past_withdrawals']); ?>)</summary>
                        <table class="rmbz-wg-kv" style="margin-top:10px;">
                            <tr><th>Data</th><th>Valor</th><th>Método</th><th>Estado</th></tr>
                            <?php foreach ( $i['past_withdrawals'] as $pw ): ?>
                            <tr>
                                <td style="font-size:11px;"><?php echo esc_html( mysql2date('d/m/Y', $pw->request_date) ); ?></td>
                                <td><?php echo number_format($pw->amount,2,',','.'); ?> MT</td>
                                <td style="font-size:11px;"><?php echo esc_html($pw->payment_method); ?>: <?php echo esc_html($pw->payment_details); ?></td>
                                <td>
                                    <?php
                                    $stcolor = $pw->status === 'aprovado' ? '#27ae60' : ($pw->status === 'rejeitado' ? '#c0392b' : '#f39c12');
                                    ?>
                                    <span style="color:<?php echo $stcolor; ?>; font-weight:bold; text-transform:uppercase; font-size:10px;"><?php echo $pw->status; ?></span>
                                </td>
                            </tr>
                            <?php endforeach; ?>
                        </table>
                    </details>
                    <?php endif; ?>
                </div>

                <?php
                // [1.6.1] Hook para extensões adicionarem secções após a identidade
                // (ex: secção "📍 Origem do Pedido" do admin-withdrawal-guard-origin.php)
                do_action( 'rmbz_wg_after_identity_section', $report, $withdrawal );
                ?>

                <!-- 3. ORIGEM DO DINHEIRO -->
                <div class="rmbz-wg-card">
                    <h3>💰 Origem do Dinheiro</h3>
                    <?php if ( $report['source']['type'] === 'royalties' ):
                        $conv = $report['source']['evidence']['conversion_ledger'] ?? null;
                        $contrib = $report['source']['evidence']['contributing_credits'] ?? [];
                        $tracks = $report['source']['evidence']['top_tracks'] ?? [];
                        $last_imp = $report['source']['evidence']['last_import_global'] ?? null;
                    ?>
                        <p style="color:var(--rmbz-text-muted, #666); font-size:13px; margin:0 0 12px 0;">
                            Este levantamento veio dos Royalties (USD), convertidos automaticamente para MT no momento do pedido.
                        </p>

                        <?php if ( $conv ): ?>
                        <div class="rmbz-wg-evidence">
                            <strong>📜 Conversão USD → MT (no momento do pedido)</strong>
                            <table class="rmbz-wg-kv" style="margin-top:6px;">
                                <tr><th>Ledger ID</th><td>#<?php echo $conv->id; ?></td></tr>
                                <tr><th>Valor convertido</th><td><strong><?php echo number_format( abs((float)$conv->amount), 2 ); ?> USD</strong></td></tr>
                                <tr><th>Saldo USD após</th><td><?php echo number_format( (float)$conv->balance_after, 2 ); ?> USD</td></tr>
                                <tr><th>Referência interna</th><td><code><?php echo esc_html($conv->reference_id); ?></code></td></tr>
                                <tr><th>Quando</th><td><?php echo esc_html( mysql2date('d/m/Y H:i:s', $conv->created_at) ); ?></td></tr>
                            </table>
                        </div>
                        <?php else: ?>
                        <div class="rmbz-wg-evidence" style="background:#fff3cd;">
                            ⚠️ Não foi encontrada nenhuma conversão USD→MT na janela esperada (5 min antes do pedido). Pode ser um pedido antigo (antes do sistema novo) ou inconsistência. <strong>Investigar.</strong>
                        </div>
                        <?php endif; ?>

                        <?php if ( ! empty($contrib) ): ?>
                        <details style="margin-top:12px;">
                            <summary style="cursor:pointer; color:var(--rmbz-info-strong, #2563eb); font-size:13px;">📈 Créditos USD que somaram este saldo (<?php echo count($contrib); ?>)</summary>
                            <table class="rmbz-wg-kv" style="margin-top:10px;">
                                <tr><th>Data</th><th>Tipo</th><th>Valor USD</th><th>Descrição</th></tr>
                                <?php foreach ( $contrib as $c ): ?>
                                <tr>
                                    <td style="font-size:11px;"><?php echo esc_html( mysql2date('d/m/Y', $c->created_at) ); ?></td>
                                    <td style="font-size:11px;"><code><?php echo esc_html($c->type); ?></code></td>
                                    <td>+<?php echo number_format((float)$c->amount, 2); ?></td>
                                    <td style="font-size:11px;"><?php echo esc_html($c->description); ?></td>
                                </tr>
                                <?php endforeach; ?>
                            </table>
                        </details>
                        <?php endif; ?>

                        <?php if ( ! empty($tracks) ): ?>
                        <div style="margin-top:14px;">
                            <strong>🎵 Faixas que geraram receita (top 10)</strong>
                            <table class="rmbz-wg-kv" style="margin-top:6px;">
                                <tr><th>Faixa</th><th>Release</th><th>ISRC</th><th>Streams</th><th>Ganhos</th></tr>
                                <?php foreach ( $tracks as $t ): ?>
                                <tr>
                                    <td><strong><?php echo esc_html($t->track_title); ?></strong></td>
                                    <td style="font-size:11px;"><?php echo esc_html($t->release_title); ?></td>
                                    <td style="font-size:11px;"><code><?php echo esc_html($t->isrc_code ?: '—'); ?></code></td>
                                    <td><?php echo number_format($t->streams); ?></td>
                                    <td>$<?php echo number_format($t->earnings_usd, 2); ?></td>
                                </tr>
                                <?php endforeach; ?>
                            </table>
                        </div>
                        <?php endif; ?>

                        <?php if ( $last_imp ): ?>
                        <div class="rmbz-wg-evidence" style="margin-top:12px;">
                            <strong>📥 Último import global da 1MZ:</strong>
                            <?php echo esc_html(date_i18n('j \d\e F \d\e Y', strtotime($last_imp['date']))); ?>
                            <?php if ( ! empty($last_imp['file']) ): ?>
                                — <code><?php echo esc_html($last_imp['file']); ?></code>
                            <?php endif; ?>
                            <?php if ( ! empty($last_imp['hash']) ): ?>
                                <br><small>Hash: <code><?php echo esc_html(substr($last_imp['hash'],0,16)); ?>...</code></small>
                            <?php endif; ?>
                        </div>
                        <?php endif; ?>

                    <?php else:
                        $recent = $report['source']['evidence']['recent_transactions'] ?? [];
                    ?>
                        <p style="color:var(--rmbz-text-muted, #666); font-size:13px; margin:0 0 12px 0;">
                            Este levantamento sai diretamente da Carteira em MT. As últimas transacções desta carteira mostram como o saldo foi formado:
                        </p>
                        <?php if ( ! empty($recent) ): ?>
                        <table class="rmbz-wg-kv rmbz-wg-tx-table">
                            <tr>
                                <th style="width:130px;">Data</th>
                                <th style="width:160px;">Tipo</th>
                                <th style="width:130px;">Valor</th>
                                <th>Resumo</th>
                                <th style="width:120px; text-align:right;">Ações</th>
                            </tr>
                            <?php foreach ( $recent as $idx => $t ):
                                $is_credit = (float) $t->amount >= 0;
                                $modal_data = wp_json_encode([
                                    'date'    => $t->transaction_date,
                                    'type'    => $t->type,
                                    'amount'  => (float) $t->amount,
                                    'details' => $t->details,
                                ]);
                                // Resumo curto da descrição (primeiros 60 chars, sem cortar palavra)
                                $details_raw = (string) $t->details;
                                if ( mb_strlen($details_raw) > 70 ) {
                                    $summary = mb_substr($details_raw, 0, 70);
                                    $last_space = mb_strrpos($summary, ' ');
                                    if ( $last_space !== false && $last_space > 30 ) {
                                        $summary = mb_substr($summary, 0, $last_space);
                                    }
                                    $summary .= '…';
                                } else {
                                    $summary = $details_raw;
                                }
                            ?>
                            <tr>
                                <td style="font-size:12px; color:#374151; white-space:nowrap;">
                                    <?php echo esc_html( mysql2date('d/m/Y', $t->transaction_date) ); ?><br>
                                    <small style="color:#9ca3af;"><?php echo esc_html( mysql2date('H:i', $t->transaction_date) ); ?></small>
                                </td>
                                <td>
                                    <span class="rmbz-wg-tx-type rmbz-wg-tx-type-<?php echo esc_attr( preg_replace('/[^a-z0-9_-]/i','_', strtolower($t->type)) ); ?>">
                                        <?php echo esc_html($t->type); ?>
                                    </span>
                                </td>
                                <td>
                                    <strong style="color:<?php echo $is_credit ? '#059669' : '#dc2626'; ?>; font-size:14px; white-space:nowrap;">
                                        <?php echo $is_credit ? '+' : ''; ?><?php echo number_format((float)$t->amount, 2, ',', '.'); ?> MT
                                    </strong>
                                </td>
                                <td style="font-size:12.5px; color:#4b5563; line-height:1.45;">
                                    <?php echo esc_html($summary); ?>
                                </td>
                                <td style="text-align:right;">
                                    <button type="button"
                                            class="rmbz-wg-tx-view-btn"
                                            data-tx='<?php echo esc_attr( $modal_data ); ?>'>
                                        Ver Detalhes
                                    </button>
                                </td>
                            </tr>
                            <?php endforeach; ?>
                        </table>

                        <!-- Modal de detalhe da transação -->
                        <div id="rmbz-wg-tx-modal" class="rmbz-wg-tx-modal" aria-hidden="true">
                            <div class="rmbz-wg-tx-modal-backdrop" data-close-tx-modal></div>
                            <div class="rmbz-wg-tx-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="rmbz-wg-tx-modal-title">
                                <div class="rmbz-wg-tx-modal-header">
                                    <h3 id="rmbz-wg-tx-modal-title">Detalhe da Transação</h3>
                                    <button type="button" class="rmbz-wg-tx-modal-close" data-close-tx-modal aria-label="Fechar">&times;</button>
                                </div>
                                <div class="rmbz-wg-tx-modal-body">
                                    <div class="rmbz-wg-tx-amount-block">
                                        <span class="rmbz-wg-tx-amount-label">Valor da transação</span>
                                        <span id="wg-tx-amount" class="rmbz-wg-tx-amount">—</span>
                                    </div>
                                    <dl class="rmbz-wg-tx-info">
                                        <dt>Data e hora</dt><dd id="wg-tx-date">—</dd>
                                        <dt>Tipo</dt><dd id="wg-tx-type">—</dd>
                                        <dt>Direção</dt><dd id="wg-tx-direction">—</dd>
                                    </dl>
                                    <div class="rmbz-wg-tx-details-block">
                                        <strong>Descrição completa</strong>
                                        <p id="wg-tx-details" class="rmbz-wg-tx-details-text">—</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <?php else: ?>
                        <p style="color:var(--rmbz-text-faint, #999);">Sem transacções recentes na carteira.</p>
                        <?php endif; ?>
                    <?php endif; ?>
                </div>

                <?php
                // ──────────────────────────────────────────────────────────
                // [DS 1.5.112] CARD: Saúde financeira da conta
                // ──────────────────────────────────────────────────────────
                // Mostra detecções avançadas que ajudam o admin a perceber
                // se há problemas de coerência entre USD (distro) e MT
                // (wallet), reembolsos pendentes, contaminação por bug, etc.
                $contam = $report['source']['evidence']['mt_contamination'] ?? null;
                $refunds_recent = $report['source']['evidence']['recent_refunds'] ?? [];
                $balance_audit = $report['source']['evidence']['balance_audit'] ?? null;
                $imports_after = $report['source']['evidence']['imports_reverted_after_request'] ?? 0;
                $has_health_data = $contam || ! empty($refunds_recent) || $balance_audit || $imports_after > 0;
                ?>

                <?php if ( $has_health_data ): ?>
                <div class="rmbz-wg-card">
                    <h3>🩺 Saúde financeira da conta</h3>
                    <p style="color:var(--rmbz-text-muted, #666); font-size:13px; margin-top:0;">
                        Verificações automáticas de coerência entre as contas USD (Distribuição)
                        e MT (Carteira Principal). Importante para garantir que o dinheiro flui
                        como deve.
                    </p>

                    <?php if ( $contam ): ?>
                        <div class="rmbz-wg-evidence" style="background:#fff5f5; border-left-color:var(--rmbz-danger-strong, #b91c1c);">
                            <strong style="color:var(--rmbz-danger-strong, #b91c1c);">⚠ Contaminação detectada (bug pre-1.5.110)</strong>
                            <table class="rmbz-wg-kv" style="margin-top:8px;">
                                <tr>
                                    <td>Créditos USD-tratados-como-MT acumulados</td>
                                    <td style="text-align:right; color:var(--rmbz-danger-strong, #b91c1c);">
                                        +<?php echo number_format($contam['credited'], 2); ?>
                                    </td>
                                </tr>
                                <tr>
                                    <td>Já debitado por reverts antigos</td>
                                    <td style="text-align:right; color:var(--rmbz-text-faint, #888);">
                                        <?php echo number_format($contam['reverted'], 2); ?>
                                    </td>
                                </tr>
                                <tr>
                                    <td>Já corrigido manualmente (1.5.111)</td>
                                    <td style="text-align:right; color:var(--rmbz-success-strong, #059669);">
                                        <?php echo number_format($contam['already_fixed'], 2); ?>
                                    </td>
                                </tr>
                                <tr style="border-top:2px solid #c0392b;">
                                    <td><strong>Lixo ainda a corrigir</strong></td>
                                    <td style="text-align:right; color:var(--rmbz-danger-strong, #b91c1c); font-weight:bold;">
                                        <?php echo number_format($contam['net_garbage'], 2); ?> MT
                                    </td>
                                </tr>
                            </table>
                            <p style="margin:8px 0 0; font-size:12px;">
                                💡 Vai a <strong>Distribuição → 🩺 Diagnóstico → Secção 5</strong>
                                para corrigir antes de aprovar este pedido.
                            </p>
                        </div>
                    <?php endif; ?>

                    <?php if ( ! empty($refunds_recent) ): ?>
                        <div class="rmbz-wg-evidence" style="margin-top:12px; background:#fffbe5; border-left-color:var(--rmbz-brand, #f0b90b);">
                            <strong>↩ Reembolsos USD recentes (últimos 30 dias)</strong>
                            <table class="rmbz-wg-kv" style="margin-top:8px;">
                                <tr><th>Data</th><th>Valor</th><th>Estado</th><th style="text-align:right;">Detalhes</th></tr>
                                <?php foreach ( array_slice($refunds_recent, 0, 5) as $rr ):
                                    $rr_id = 'rmbz-rd-' . md5($rr->id . $rr->created_at);
                                ?>
                                    <tr>
                                        <td style="font-size:11px;"><?php echo esc_html(mysql2date('d/m/Y', $rr->created_at)); ?></td>
                                        <td style="font-size:11px; color:var(--rmbz-success-strong, #059669);">
                                            +$<?php echo number_format((float) $rr->amount, 2); ?>
                                        </td>
                                        <td style="font-size:11px;">
                                            <?php if ( ! empty($rr->reverted_at) ): ?>
                                                <span style="color:var(--rmbz-text-faint, #888);">↺ revertido</span>
                                            <?php else: ?>
                                                <span style="color:var(--rmbz-success-strong, #059669);">activo</span>
                                            <?php endif; ?>
                                        </td>
                                        <td style="text-align:right;">
                                            <button type="button"
                                                    class="button button-small rmbz-wg-show-refund"
                                                    data-target="<?php echo esc_attr($rr_id); ?>">
                                                Ver descrição
                                            </button>
                                            <template id="<?php echo esc_attr($rr_id); ?>">
                                                <div data-meta="<?php echo esc_attr(wp_json_encode([
                                                    'date'   => mysql2date('d/m/Y H:i', $rr->created_at),
                                                    'amount' => '+$' . number_format((float) $rr->amount, 2) . ' USD',
                                                    'state'  => ! empty($rr->reverted_at) ? '↺ revertido' : '✓ activo',
                                                ])); ?>"></div>
                                                <?php echo esc_html((string) $rr->description); ?>
                                            </template>
                                        </td>
                                    </tr>
                                <?php endforeach; ?>
                            </table>
                        </div>
                    <?php endif; ?>

                    <?php if ( $balance_audit ): ?>
                        <div class="rmbz-wg-evidence" style="margin-top:12px;">
                            <strong>⚖ Auditoria de saldos USD ↔ MT</strong>
                            <table class="rmbz-wg-kv" style="margin-top:8px;">
                                <tr>
                                    <td>Saldo em Distribuição (USD)</td>
                                    <td style="text-align:right;">
                                        $<?php echo number_format($balance_audit['usd_balance_distro'], 2); ?>
                                    </td>
                                </tr>
                                <tr>
                                    <td>Saldo em Carteira Principal (MT)</td>
                                    <td style="text-align:right;">
                                        <?php echo number_format($balance_audit['mt_balance_wallet'], 2); ?> MT
                                    </td>
                                </tr>
                                <tr>
                                    <td>Câmbio actual nas configurações</td>
                                    <td style="text-align:right; color:var(--rmbz-text-faint, #888);">
                                        <?php echo number_format($balance_audit['exchange_rate_now'], 2); ?> MT/USD
                                    </td>
                                </tr>
                                <tr style="color:var(--rmbz-text-faint, #888);">
                                    <td><small>(Se todo USD fosse convertido agora, daria...)</small></td>
                                    <td style="text-align:right;">
                                        <small><?php echo number_format($balance_audit['expected_mt_if_converted'], 2); ?> MT</small>
                                    </td>
                                </tr>
                            </table>
                            <p style="margin:8px 0 0; font-size:12px; color:var(--rmbz-text-muted, #666);">
                                💡 Os saldos são <strong>independentes</strong>. O artista escolhe
                                de qual conta levantar. Esta tabela é só para contexto.
                            </p>
                        </div>
                    <?php endif; ?>

                    <?php if ( $imports_after > 0 ): ?>
                        <div class="rmbz-wg-evidence" style="margin-top:12px; background:#fffbe5; border-left-color:var(--rmbz-brand, #f0b90b);">
                            <strong>⏰ Imports anulados/rejeitados depois deste pedido</strong>
                            <p style="margin:6px 0 0; font-size:13px;">
                                <?php echo (int) $imports_after; ?> importação(ões)
                                tiveram o seu estado mudado para "anulado" ou "rejeitado"
                                <strong>depois</strong> deste pedido ter sido criado em
                                <?php echo esc_html(mysql2date('d/m/Y H:i', $withdrawal->request_date)); ?>.
                                O saldo da conta pode já não corresponder ao valor original do pedido.
                            </p>
                        </div>
                    <?php endif; ?>
                </div>

                <?php // [DS 1.5.113] Modal genérico para detalhes de reembolso ?>
                <div id="rmbz-wg-refund-modal" class="rmbz-wg-modal" aria-hidden="true">
                    <div class="rmbz-wg-modal-overlay" data-close="1"></div>
                    <div class="rmbz-wg-modal-box" role="dialog" aria-labelledby="rmbz-wg-modal-title">
                        <div class="rmbz-wg-modal-header">
                            <h3 id="rmbz-wg-modal-title">↩ Detalhes do reembolso</h3>
                            <button type="button" class="rmbz-wg-modal-close" data-close="1" aria-label="Fechar">×</button>
                        </div>
                        <div class="rmbz-wg-modal-body">
                            <table class="rmbz-wg-modal-meta">
                                <tr><td>Data</td><td id="rmbz-wg-modal-date">—</td></tr>
                                <tr><td>Valor</td><td id="rmbz-wg-modal-amount">—</td></tr>
                                <tr><td>Estado</td><td id="rmbz-wg-modal-state">—</td></tr>
                            </table>
                            <h4 style="margin:14px 0 6px;">Descrição completa</h4>
                            <div id="rmbz-wg-modal-desc" class="rmbz-wg-modal-desc">—</div>
                        </div>
                    </div>
                </div>

                <style>
                    .rmbz-wg-modal { display:none; position:fixed; inset:0; z-index:100000; }
                    .rmbz-wg-modal.is-open { display:block; }
                    .rmbz-wg-modal-overlay {
                        position:absolute; inset:0;
                        background:rgba(0,0,0,0.55);
                        backdrop-filter:blur(2px);
                        cursor:pointer;
                    }
                    .rmbz-wg-modal-box {
                        position:relative;
                        max-width:560px;
                        margin:6vh auto 0;
                        background:var(--rmbz-bg-card, #fff);
                        border-radius:10px;
                        box-shadow:0 20px 60px rgba(0,0,0,0.35);
                        overflow:hidden;
                        animation:rmbzModalIn 0.18s ease-out;
                    }
                    @keyframes rmbzModalIn {
                        from { opacity:0; transform:translateY(-12px); }
                        to   { opacity:1; transform:translateY(0); }
                    }
                    .rmbz-wg-modal-header {
                        display:flex; align-items:center; justify-content:space-between;
                        padding:14px 20px;
                        background:linear-gradient(135deg, #f0b90b 0%, #d4a30a 100%);
                        color:var(--rmbz-text-strong, #1a1a1a);
                    }
                    .rmbz-wg-modal-header h3 {
                        margin:0; font-size:16px; font-weight:600;
                    }
                    .rmbz-wg-modal-close {
                        background:transparent; border:0;
                        font-size:28px; line-height:1;
                        cursor:pointer; color:var(--rmbz-text-strong, #1a1a1a);
                        padding:0 4px;
                    }
                    .rmbz-wg-modal-close:hover { color:#000; }
                    .rmbz-wg-modal-body { padding:18px 20px 20px; }
                    .rmbz-wg-modal-meta {
                        width:100%; border-collapse:collapse; font-size:13px;
                        background:#fafafa; border-radius:6px; overflow:hidden;
                    }
                    .rmbz-wg-modal-meta td {
                        padding:8px 12px; border-bottom:1px solid #eee;
                    }
                    .rmbz-wg-modal-meta tr:last-child td { border-bottom:0; }
                    .rmbz-wg-modal-meta td:first-child {
                        color:var(--rmbz-text-muted, #666); width:100px; font-weight:500;
                    }
                    .rmbz-wg-modal-desc {
                        background:#f5f9ff; border:1px solid #d6e3f5;
                        border-radius:6px; padding:12px;
                        font-size:13px; line-height:1.55;
                        white-space:pre-wrap; word-wrap:break-word;
                        color:var(--rmbz-text-strong, #1a1a1a);
                        max-height:240px; overflow-y:auto;
                    }
                </style>

                <script>
                (function(){
                    var modal = document.getElementById('rmbz-wg-refund-modal');
                    if (!modal) return;
                    var titleEl  = document.getElementById('rmbz-wg-modal-title');
                    var dateEl   = document.getElementById('rmbz-wg-modal-date');
                    var amountEl = document.getElementById('rmbz-wg-modal-amount');
                    var stateEl  = document.getElementById('rmbz-wg-modal-state');
                    var descEl   = document.getElementById('rmbz-wg-modal-desc');

                    function openModal(targetId) {
                        var tpl = document.getElementById(targetId);
                        if (!tpl) return;
                        var metaHolder = tpl.content.querySelector('[data-meta]');
                        var meta = {};
                        if (metaHolder) {
                            try { meta = JSON.parse(metaHolder.getAttribute('data-meta')); }
                            catch(e) { meta = {}; }
                        }
                        // Texto da descrição: tudo o que estiver no template menos o div de meta
                        var clone = tpl.content.cloneNode(true);
                        var metaInClone = clone.querySelector('[data-meta]');
                        if (metaInClone) metaInClone.remove();
                        var descText = (clone.textContent || '').trim();

                        dateEl.textContent   = meta.date   || '—';
                        amountEl.textContent = meta.amount || '—';
                        stateEl.textContent  = meta.state  || '—';
                        descEl.textContent   = descText || '(sem descrição)';
                        modal.classList.add('is-open');
                        modal.setAttribute('aria-hidden', 'false');
                    }
                    function closeModal() {
                        modal.classList.remove('is-open');
                        modal.setAttribute('aria-hidden', 'true');
                    }
                    document.querySelectorAll('.rmbz-wg-show-refund').forEach(function(btn){
                        btn.addEventListener('click', function(){
                            openModal(btn.getAttribute('data-target'));
                        });
                    });
                    modal.addEventListener('click', function(e){
                        if (e.target.getAttribute('data-close') === '1') closeModal();
                    });
                    document.addEventListener('keydown', function(e){
                        if (e.key === 'Escape' && modal.classList.contains('is-open')) closeModal();
                    });
                })();
                </script>
                <?php endif; ?>

                <!-- 4. AUDIT LOG -->
                <div class="rmbz-wg-card">
                    <h3>📜 Audit Log <small style="color:var(--rmbz-text-faint, #888); font-weight:normal;">(<?php echo count($audit_log); ?> entrada<?php echo count($audit_log) === 1 ? '' : 's'; ?>)</small></h3>
                    <?php if ( empty($audit_log) ): ?>
                        <p style="color:var(--rmbz-text-faint, #999);">Sem registos. (Estranho — esta vista deveria ter criado pelo menos um.)</p>
                    <?php else: ?>
                    <div class="rmbz-wg-timeline">
                        <?php foreach ( $audit_log as $entry ):
                            $icons = [
                                'created' => '➕', 'first_view' => '👁️', 'viewed' => '👁️',
                                'checklist_updated' => '☑️', 'note_updated' => '📝',
                                'approved' => '✅', 'rejected' => '❌', 'approve_blocked' => '🚫',
                            ];
                            $icon = $icons[$entry->action] ?? '•';
                        ?>
                        <div class="rmbz-wg-timeline-item">
                            <span class="rmbz-wg-tl-icon"><?php echo $icon; ?></span>
                            <div class="rmbz-wg-tl-body">
                                <strong><?php echo esc_html(str_replace('_', ' ', $entry->action)); ?></strong>
                                <?php if ( $entry->details ): ?>
                                    <span style="color:var(--rmbz-text-muted, #666);"> — <?php echo esc_html($entry->details); ?></span>
                                <?php endif; ?>
                                <div class="rmbz-wg-tl-meta">
                                    <?php echo esc_html($entry->actor_login); ?>
                                    <?php if ($entry->actor_ip): ?> · IP <code><?php echo esc_html($entry->actor_ip); ?></code><?php endif; ?>
                                    · <?php echo esc_html( mysql2date('d/m/Y H:i:s', $entry->created_at) ); ?>
                                </div>
                            </div>
                        </div>
                        <?php endforeach; ?>
                    </div>
                    <?php endif; ?>
                </div>

            </div><!-- /col esquerda -->

            <!-- COLUNA DIREITA -->
            <div class="rmbz-wg-col">

                <!-- 5. SINAIS DE RISCO -->
                <div class="rmbz-wg-card">
                    <h3>⚠️ Sinais de Risco <small style="color:var(--rmbz-text-faint, #888); font-weight:normal;">(<?php echo count($report['risk_flags']); ?>)</small></h3>
                    <?php if ( empty($report['risk_flags']) ): ?>
                        <div style="background:#d4edda; color:var(--rmbz-success-strong, #166534); padding:12px; border-radius:6px; text-align:center;">
                            ✅ Nenhum sinal de risco detectado.
                        </div>
                    <?php else: ?>
                    <div class="rmbz-wg-flags">
                        <?php foreach ( $report['risk_flags'] as $flag ):
                            $colors = [
                                'critical' => ['bg' => '#f8d7da', 'fg' => '#721c24', 'border' => '#c0392b'],
                                'high'     => ['bg' => '#fff3cd', 'fg' => '#856404', 'border' => '#e67e22'],
                                'medium'   => ['bg' => '#d1ecf1', 'fg' => '#0c5460', 'border' => '#3498db'],
                                'low'      => ['bg' => '#e2e3e5', 'fg' => '#383d41', 'border' => '#95a5a6'],
                            ];
                            $c = $colors[$flag['level']] ?? $colors['low'];
                            $emoji = ['critical'=>'🚨','high'=>'⚠️','medium'=>'⚡','low'=>'ℹ️'][$flag['level']] ?? '•';
                        ?>
                        <div class="rmbz-wg-flag" style="background:<?php echo $c['bg']; ?>; color:<?php echo $c['fg']; ?>; border-left:4px solid <?php echo $c['border']; ?>;">
                            <strong><?php echo $emoji; ?> <?php echo strtoupper($flag['level']); ?></strong>
                            <p style="margin:4px 0 0 0;"><?php
                                // Permitimos um conjunto pequeno e seguro de tags
                                // para destaque (strong, em, code) — sem risco de
                                // injecção porque as mensagens são sempre construídas
                                // por nós em rmbz_wg_collect_flags(). Continua a
                                // escapar tudo o resto.
                                echo wp_kses( $flag['msg'], [
                                    'strong' => [],
                                    'b'      => [],
                                    'em'     => [],
                                    'i'      => [],
                                    'code'   => [],
                                    'br'     => [],
                                ] );
                            ?></p>
                            <small style="opacity:0.7;">code: <code><?php echo esc_html($flag['code']); ?></code></small>
                        </div>
                        <?php endforeach; ?>
                    </div>
                    <?php endif; ?>
                </div>

                <!-- 6. CHECKLIST OBRIGATÓRIA -->
                <div class="rmbz-wg-card">
                    <h3>☑️ Checklist Obrigatória</h3>
                    <p style="color:var(--rmbz-text-muted, #666); font-size:12px; margin-top:0;">
                        Marque cada item após verificar. Itens marcados <span class="rmbz-wg-crit-tag">CRÍTICO</span> exigem um motivo escrito (mínimo 10 caracteres) — fica registado para o suporte.
                    </p>
                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                        <?php wp_nonce_field('rmbz_wg_review'); ?>
                        <input type="hidden" name="action" value="rmbz_wg_save_checklist">
                        <input type="hidden" name="withdrawal_id" value="<?php echo $wd_id; ?>">

                        <div class="rmbz-wg-checklist">
                            <?php foreach ( $checklist_items as $key => $meta ):
                                // $meta pode ser string (legacy) ou array (novo)
                                $label    = is_array($meta) ? (string) $meta['label']    : (string) $meta;
                                $critical = is_array($meta) ? ! empty($meta['critical']) : false;
                                $entry    = rmbz_wg_checklist_entry( $review, $key );
                                $done     = $entry['done'];
                                $reason   = $entry['reason'];
                                $row_class = 'rmbz-wg-check' . ($critical ? ' rmbz-wg-check-critical' : '');
                            ?>
                            <div class="<?php echo $row_class; ?>" data-key="<?php echo esc_attr($key); ?>">
                                <label class="rmbz-wg-check-row">
                                    <input type="checkbox" name="check_<?php echo esc_attr($key); ?>" value="1" <?php checked($done); ?>>
                                    <span>
                                        <?php echo esc_html($label); ?>
                                        <?php if ($critical): ?>
                                            <span class="rmbz-wg-crit-tag">CRÍTICO · MOTIVO OBRIGATÓRIO</span>
                                        <?php endif; ?>
                                    </span>
                                </label>
                                <?php if ($critical): ?>
                                <div class="rmbz-wg-reason-wrap" <?php echo $done ? '' : 'hidden'; ?>>
                                    <label class="rmbz-wg-reason-label" for="reason_<?php echo esc_attr($key); ?>">
                                        Motivo / detalhes do contacto com o artista titular do número
                                        <small>(mínimo 10 caracteres — descreva quando contactou, com quem falou, e o que ficou decidido)</small>
                                    </label>
                                    <textarea
                                        id="reason_<?php echo esc_attr($key); ?>"
                                        name="reason_<?php echo esc_attr($key); ?>"
                                        rows="3"
                                        placeholder="Ex.: Contactei o artista João Manuel (titular do número) por chamada no dia 21/05 às 14h30. Confirmou que autoriza o pagamento à Maria por ser sua irmã e ter perdido o cartão SIM. Encaminhei o screenshot da conversa para a pasta de suporte #1234."
                                        class="rmbz-wg-reason-textarea"
                                    ><?php echo esc_textarea($reason); ?></textarea>
                                </div>
                                <?php endif; ?>
                            </div>
                            <?php endforeach; ?>
                        </div>

                        <button type="submit" class="button button-primary" style="margin-top:14px; width:100%;">💾 Guardar Checklist</button>
                    </form>
                </div>

                <!-- 7. NOTAS INTERNAS -->
                <div class="rmbz-wg-card">
                    <h3>📝 Notas Internas <small style="color:var(--rmbz-text-faint, #888); font-weight:normal;">(só admin)</small></h3>
                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                        <?php wp_nonce_field('rmbz_wg_review'); ?>
                        <input type="hidden" name="action" value="rmbz_wg_save_note">
                        <input type="hidden" name="withdrawal_id" value="<?php echo $wd_id; ?>">
                        <textarea name="admin_notes" rows="5" style="width:100%; font-family:inherit;"
                                  placeholder="Comentários, contactos com o artista, evidências externas, links de comprovativos, etc..."><?php echo esc_textarea($review->admin_notes ?? ''); ?></textarea>
                        <button type="submit" class="button" style="margin-top:8px;">💾 Guardar Nota</button>
                    </form>
                </div>

                <!-- 8. AÇÕES -->
                <?php if ( $withdrawal->status === 'pendente' ):
                    $checklist_done = rmbz_wg_checklist_complete($wd_id, $withdrawal, $report);
                    $approve_url = wp_nonce_url(
                        admin_url('admin-post.php?action=rmbz_approve_withdrawal&req_id=' . $wd_id),
                        'rmbz_approve_withdrawal_nonce_' . $wd_id
                    );
                    $reject_url = wp_nonce_url(
                        admin_url('admin-post.php?action=rmbz_reject_withdrawal&req_id=' . $wd_id),
                        'rmbz_reject_withdrawal_nonce_' . $wd_id
                    );
                ?>
                <div class="rmbz-wg-card" style="border-top:3px solid #f0b90b;">
                    <h3>🎯 Decisão Final</h3>
                    <?php if ( ! $checklist_done ): ?>
                        <div style="background:#f8d7da; color:var(--rmbz-danger-strong, #721c24); padding:10px; border-radius:6px; margin-bottom:12px; font-size:13px;">
                            🔒 Aprovação bloqueada. Marque <strong>todos</strong> os items da Checklist primeiro.
                        </div>
                    <?php endif; ?>

                    <a href="<?php echo $checklist_done ? esc_url($approve_url) : '#'; ?>"
                       class="button button-primary <?php echo $checklist_done ? '' : 'disabled'; ?>"
                       style="display:block; text-align:center; margin-bottom:8px; <?php echo $checklist_done ? 'background:var(--rmbz-success-strong, #059669); border-color:var(--rmbz-success-strong, #059669);' : 'opacity:0.4; cursor:not-allowed;'; ?>"
                       <?php if ( ! $checklist_done ): ?>onclick="event.preventDefault(); alert('Marque todos os items da Checklist antes de aprovar.');"<?php endif; ?>
                       <?php if ( $checklist_done ): ?>onclick="return confirm('Confirma que já efetuou a transferência ao artista? Esta ação não pode ser desfeita.');"<?php endif; ?>>
                        ✅ Pagar & Aprovar
                    </a>

                    <a href="<?php echo esc_url($reject_url); ?>"
                       class="button"
                       style="display:block; text-align:center; color:var(--rmbz-danger-strong, #b91c1c); border-color:var(--rmbz-danger-strong, #b91c1c);"
                       onclick="return confirm('Rejeitar este pedido e devolver o saldo ao artista?');">
                        ❌ Rejeitar
                    </a>
                </div>
                <?php endif; ?>

            </div><!-- /col direita -->
        </div><!-- /grid -->

        <style>
        /* ====================================================================
         * Guarda-Costas — design modernizado (apenas CSS, sem alterar HTML).
         *
         * Estratégia: as classes .rmbz-wg-* já estão espalhadas por todo o
         * PHP (vista principal + extensão origin.php). Repintando-as aqui
         * todas as 9 secções beneficiam de uma só vez. Zero risco de
         * partir o fluxo crítico de aprovação.
         *
         * Notas-chave do redesign:
         *  - Fundo com tom muito subtil (não branco puro) — descansa olhos
         *  - Cards com sombra suave + hover lift discreto
         *  - Headings de secção com barra dourada à esquerda (marca 1MZ)
         *  - Tabelas kv com mais respiração e tipografia mais legível
         *  - Status bar do score com gradiente, sombra e pulse subtil
         *  - Flags de risco com cor de fundo + barra lateral por severidade
         *  - Botões de ação ("Marcar confiável/suspeito") modernos e claros
         * ==================================================================== */

        /* Wrap full-width (mantido) — agora com fundo cinza muito subtil
         * para os cards brancos sobressaírem. */
        .rmbz-wg-wrap {
            width: 100%; max-width: 100%;
            background: linear-gradient(180deg, #fafbfc 0%, #f5f6f8 100%);
            padding: 8px 4px 24px;
            border-radius: 10px;
        }

        /* Título da página */
        .rmbz-wg-wrap > h1 {
            font-size: 24px !important;
            color: #1a1a1a;
            margin-bottom: 6px !important;
        }

        /* Grid principal (sem mudanças funcionais) */
        .rmbz-wg-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 22px; }
        @media (max-width: 1100px) { .rmbz-wg-grid { grid-template-columns: 1fr; } }
        .rmbz-wg-col { display: flex; flex-direction: column; gap: 20px; }

        /* ── CARDS ── */
        .rmbz-wg-card {
            background: #fff;
            border: 1px solid #e6e8eb;
            border-radius: 12px;
            padding: 22px 22px 20px;
            box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04), 0 4px 12px rgba(15, 23, 42, 0.03);
            transition: box-shadow 0.18s ease, transform 0.18s ease;
        }
        .rmbz-wg-card:hover {
            box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06), 0 8px 24px rgba(15, 23, 42, 0.06);
        }

        /* Heading com barra dourada à esquerda */
        .rmbz-wg-card h3 {
            margin: 0 0 16px 0 !important;
            font-size: 16px;
            font-weight: 700;
            color: #1a1a1a;
            padding: 0 0 12px 12px;
            border-bottom: 1px solid #f0f1f3;
            position: relative;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .rmbz-wg-card h3::before {
            content: '';
            position: absolute;
            left: 0; top: 2px; bottom: 14px;
            width: 3px;
            background: linear-gradient(180deg, #f0b90b, #d4a000);
            border-radius: 2px;
        }
        .rmbz-wg-card h4 {
            font-size: 13px;
            font-weight: 600;
            color: #4a5568;
            margin: 16px 0 8px;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        /* ── TABELA chave-valor ── */
        .rmbz-wg-kv {
            width: 100%;
            border-collapse: collapse;
            font-size: 13px;
        }
        .rmbz-wg-kv th {
            text-align: left;
            color: #6b7280;
            font-weight: 500;
            font-size: 12px;
            text-transform: uppercase;
            letter-spacing: 0.03em;
            padding: 10px 12px 10px 0;
            border-bottom: 1px solid #f3f4f6;
            vertical-align: top;
            width: 36%;
        }
        .rmbz-wg-kv td {
            padding: 10px 0 10px 12px;
            border-bottom: 1px solid #f3f4f6;
            color: #1f2937;
            font-size: 13.5px;
            line-height: 1.5;
        }
        .rmbz-wg-kv tr:last-child th,
        .rmbz-wg-kv tr:last-child td { border-bottom: none; }
        .rmbz-wg-kv code,
        .rmbz-wg-kv .wg-mono {
            background: #f3f4f6;
            padding: 2px 8px;
            border-radius: 5px;
            font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
            font-size: 12px;
            color: #1f2937;
        }

        /* ── PILLS / BADGES ── */
        .rmbz-wg-pill {
            display: inline-block;
            padding: 3px 12px;
            border-radius: 14px;
            font-size: 11px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        /* ── EVIDÊNCIA ── */
        .rmbz-wg-evidence {
            background: #f8fafc;
            border: 1px solid #e6e8eb;
            border-left: 3px solid #f0b90b;
            border-radius: 8px;
            padding: 12px 14px;
            font-size: 13px;
            color: #374151;
            margin-top: 8px;
        }

        /* ── FLAGS DE RISCO (a parte mais importante visualmente) ── */
        .rmbz-wg-flags { display: flex; flex-direction: column; gap: 10px; }
        .rmbz-wg-flag {
            padding: 12px 14px 12px 16px;
            border-radius: 10px;
            font-size: 13px;
            background: #f9fafb;
            border: 1px solid #e6e8eb;
            border-left-width: 4px;
            line-height: 1.5;
        }
        .rmbz-wg-flag p { margin: 4px 0; }
        .rmbz-wg-flag p:first-child { font-weight: 600; color: #1a1a1a; }
        /* Severidade — quando o PHP inline-style usa cores, herdamos.
         * Adicionalmente, se houver classes adicionais, aplicamos cor: */
        .rmbz-wg-flag[style*="c0392b"],
        .rmbz-wg-flag.wg-critical { border-left-color: #c0392b; background: #fef2f2; }
        .rmbz-wg-flag[style*="e67e22"],
        .rmbz-wg-flag.wg-high     { border-left-color: #e67e22; background: #fff7ed; }
        .rmbz-wg-flag[style*="f39c12"],
        .rmbz-wg-flag.wg-medium   { border-left-color: #f39c12; background: #fffbeb; }

        /* ── CHECKLIST ── */
        .rmbz-wg-checklist { display: flex; flex-direction: column; gap: 8px; }
        .rmbz-wg-check {
            display: flex; gap: 12px; align-items: flex-start;
            padding: 12px 14px;
            background: #fafbfc;
            border: 1px solid #e6e8eb;
            border-radius: 9px;
            cursor: pointer;
            transition: all 0.15s ease;
        }
        .rmbz-wg-check:hover {
            background: #fff8e1;
            border-color: #f0b90b;
            transform: translateX(2px);
        }
        .rmbz-wg-check:has(input:checked) {
            background: #f0fdf4;
            border-color: #10b981;
        }
        .rmbz-wg-check input {
            margin-top: 2px;
            width: 16px; height: 16px;
            accent-color: #10b981;
            cursor: pointer;
        }
        .rmbz-wg-check span {
            font-size: 13.5px;
            line-height: 1.5;
            color: #1f2937;
        }

        /* ── TIMELINE / AUDIT LOG ── */
        .rmbz-wg-timeline {
            display: flex; flex-direction: column;
            gap: 0;
            max-height: 420px;
            overflow-y: auto;
            padding-right: 4px;
        }
        .rmbz-wg-timeline-item {
            display: flex; gap: 12px; align-items: flex-start;
            padding: 10px 0;
            border-bottom: 1px dashed #e6e8eb;
        }
        .rmbz-wg-timeline-item:last-child { border-bottom: none; }
        .rmbz-wg-tl-icon {
            font-size: 16px; flex-shrink: 0;
            width: 28px; height: 28px;
            display: flex; align-items: center; justify-content: center;
            background: #f3f4f6; border-radius: 50%;
        }
        .rmbz-wg-tl-body { font-size: 13px; flex: 1; color: #1f2937; line-height: 1.45; }
        .rmbz-wg-tl-meta { color: #9ca3af; font-size: 11px; margin-top: 3px; }

        /* ── STATUS BAR DO SCORE (mais marcante) ── */
        .rmbz-wg-status-bar {
            padding: 18px 24px !important;
            border-radius: 12px !important;
            margin-bottom: 22px !important;
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.10);
            position: relative;
            overflow: hidden;
        }
        .rmbz-wg-status-bar::before {
            content: '';
            position: absolute;
            top: -50%; right: -10%;
            width: 40%; height: 200%;
            background: radial-gradient(circle, rgba(255,255,255,0.18) 0%, transparent 60%);
            pointer-events: none;
        }
        .rmbz-wg-status-bar > div { position: relative; z-index: 1; }
        .rmbz-wg-status-bar strong { font-size: 19px !important; }

        /* ── BOTÕES DE AÇÃO origin (Marcar confiável/suspeito) ── */
        /* O PHP usa <button class="button"> (estilo wp-admin default).
         * Aqui só damos um polimento extra sem competir com o wp-admin. */
        .rmbz-wg-card .button {
            border-radius: 8px !important;
            padding: 7px 14px !important;
            font-weight: 600 !important;
            transition: all 0.15s ease;
        }
        .rmbz-wg-card .button:hover {
            transform: translateY(-1px);
            box-shadow: 0 3px 8px rgba(0, 0, 0, 0.10);
        }

        /* ── Scrollbar fininho nas zonas com overflow ── */
        .rmbz-wg-timeline::-webkit-scrollbar { width: 6px; }
        .rmbz-wg-timeline::-webkit-scrollbar-track { background: transparent; }
        .rmbz-wg-timeline::-webkit-scrollbar-thumb {
            background: #d1d5db; border-radius: 3px;
        }

        /* ════════════════════════════════════════════════════════════════════
         * TABELA "Origem do Dinheiro" — modernizada com botão Ver Detalhes
         * ════════════════════════════════════════════════════════════════════ */
        .rmbz-wg-tx-table { table-layout: fixed; }
        .rmbz-wg-tx-table th {
            background: #fafbfc;
            padding: 11px 12px !important;
            font-size: 11px !important;
        }
        .rmbz-wg-tx-table td {
            padding: 12px 12px !important;
            vertical-align: middle !important;
        }
        .rmbz-wg-tx-table tr:hover td { background: #fafbfc; }

        /* Pill colorido por tipo de transação. Cores por categoria:
         *  - distro_payout (receita royalties) → verde
         *  - withdrawal_request (saída)        → vermelho/rosa
         *  - withdrawal_rejected (reembolso)   → âmbar
         *  - default                            → cinza neutro
         */
        .rmbz-wg-tx-type {
            display: inline-block;
            padding: 3px 10px;
            border-radius: 12px;
            font-size: 11px;
            font-weight: 600;
            font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
            background: #f3f4f6;
            color: #4b5563;
            border: 1px solid #e5e7eb;
            white-space: nowrap;
        }
        .rmbz-wg-tx-type-distro_payout {
            background: #d1fae5; color: #065f46; border-color: #a7f3d0;
        }
        .rmbz-wg-tx-type-withdrawal_request {
            background: #fee2e2; color: #991b1b; border-color: #fecaca;
        }
        .rmbz-wg-tx-type-withdrawal_rejected,
        .rmbz-wg-tx-type-withdrawal_refund {
            background: #fef3c7; color: #92400e; border-color: #fde68a;
        }

        /* Botão "Ver Detalhes" — mesmo estilo do botão da página de
         * Levantamentos para consistência visual. */
        .rmbz-wg-tx-view-btn {
            display: inline-flex;
            align-items: center; justify-content: center;
            padding: 6px 12px;
            border-radius: 7px;
            font-size: 11px;
            font-weight: 600;
            cursor: pointer;
            background: #1a1a1a;
            color: #f0b90b;
            border: 1px solid #f0b90b;
            transition: all 0.18s ease;
            white-space: nowrap;
        }
        .rmbz-wg-tx-view-btn:hover {
            background: #f0b90b;
            color: #1a1a1a;
            transform: translateY(-1px);
            box-shadow: 0 3px 8px rgba(240,185,11,0.35);
        }

        /* ── MODAL de detalhe da transação ── */
        .rmbz-wg-tx-modal {
            position: fixed; inset: 0; z-index: 100001;
            display: none; align-items: center; justify-content: center;
            padding: 20px;
        }
        .rmbz-wg-tx-modal.is-open { display: flex; }
        .rmbz-wg-tx-modal-backdrop {
            position: absolute; inset: 0;
            background: rgba(10,10,10,0.65);
            backdrop-filter: blur(2px);
        }
        .rmbz-wg-tx-modal-dialog {
            position: relative;
            background: #fff;
            border-radius: 14px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.4);
            max-width: 560px;
            width: 100%;
            max-height: 90vh;
            overflow: hidden;
            display: flex; flex-direction: column;
        }
        .rmbz-wg-tx-modal-header {
            display: flex; justify-content: space-between; align-items: center;
            padding: 16px 22px;
            background: linear-gradient(135deg, #1a1a1a, #2a2a2a);
            color: #fff;
        }
        .rmbz-wg-tx-modal-header h3 { margin: 0; font-size: 17px; color: #fff; }
        .rmbz-wg-tx-modal-close {
            background: transparent; border: 0; color: #fff;
            font-size: 28px; cursor: pointer; line-height: 1;
            padding: 0 6px; opacity: 0.8;
        }
        .rmbz-wg-tx-modal-close:hover { opacity: 1; }
        .rmbz-wg-tx-modal-body {
            padding: 22px;
            overflow-y: auto;
        }

        /* Bloco grande do valor — destaque visual primário */
        .rmbz-wg-tx-amount-block {
            text-align: center;
            padding: 18px 16px;
            background: linear-gradient(180deg, #fafbfc 0%, #f3f4f6 100%);
            border-radius: 10px;
            border: 1px solid #e6e8eb;
            margin-bottom: 18px;
        }
        .rmbz-wg-tx-amount-label {
            display: block;
            font-size: 11px;
            color: #6b7280;
            text-transform: uppercase;
            letter-spacing: 0.05em;
            margin-bottom: 4px;
        }
        .rmbz-wg-tx-amount {
            display: block;
            font-size: 30px;
            font-weight: 800;
            letter-spacing: -0.02em;
        }
        .rmbz-wg-tx-amount.is-credit { color: #059669; }
        .rmbz-wg-tx-amount.is-debit { color: #dc2626; }

        .rmbz-wg-tx-info {
            margin: 0;
            display: grid;
            grid-template-columns: 130px 1fr;
            gap: 8px 14px;
        }
        .rmbz-wg-tx-info dt {
            font-size: 11px; color: #6b7280; font-weight: 600;
            text-transform: uppercase; letter-spacing: 0.04em;
            padding-top: 2px;
        }
        .rmbz-wg-tx-info dd {
            margin: 0; font-size: 14px; color: #1f2937;
        }
        .rmbz-wg-tx-info dd code {
            background: #f3f4f6; padding: 3px 8px; border-radius: 5px;
            font-size: 12px; color: #1f2937;
        }

        .rmbz-wg-tx-details-block {
            margin-top: 18px;
            padding-top: 16px;
            border-top: 1px dashed #e6e8eb;
        }
        .rmbz-wg-tx-details-block strong {
            display: block; margin-bottom: 8px;
            font-size: 11px; color: #6b7280;
            text-transform: uppercase; letter-spacing: 0.04em;
        }
        .rmbz-wg-tx-details-text {
            margin: 0; padding: 12px 14px;
            background: #f8fafc;
            border: 1px solid #e6e8eb;
            border-left: 3px solid #f0b90b;
            border-radius: 8px;
            font-size: 13.5px;
            color: #1f2937;
            line-height: 1.55;
            white-space: pre-wrap;
            word-break: break-word;
        }

        @media (max-width: 720px) {
            .rmbz-wg-tx-info { grid-template-columns: 1fr; gap: 4px 0; }
            .rmbz-wg-tx-info dt { margin-top: 10px; }
            .rmbz-wg-tx-amount { font-size: 26px; }
        }

        /* ════════════════════════════════════════════════════════════════════
         * CHECKLIST — items críticos com motivo obrigatório
         * ════════════════════════════════════════════════════════════════════ */
        .rmbz-wg-check-critical {
            background: #fff7ed !important;
            border-color: #fdba74 !important;
        }
        .rmbz-wg-check-critical:hover {
            background: #ffedd5 !important;
        }
        .rmbz-wg-check-critical:has(input:checked) {
            background: #fff !important;
            border-color: #f0b90b !important;
            border-left-width: 4px !important;
        }
        .rmbz-wg-check-row {
            display: flex;
            gap: 12px;
            align-items: flex-start;
            cursor: pointer;
        }
        .rmbz-wg-check-row input {
            margin-top: 2px;
            width: 16px; height: 16px;
            accent-color: #10b981;
            cursor: pointer;
            flex-shrink: 0;
        }
        .rmbz-wg-check-row span {
            font-size: 13.5px;
            line-height: 1.5;
            color: #1f2937;
        }
        .rmbz-wg-crit-tag {
            display: inline-block;
            margin-left: 6px;
            padding: 1px 8px;
            background: #fed7aa;
            color: #9a3412;
            border-radius: 10px;
            font-size: 9.5px;
            font-weight: 700;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            vertical-align: middle;
        }
        .rmbz-wg-reason-wrap {
            margin-top: 12px;
            padding: 12px 14px;
            background: #fff;
            border: 1px solid #fde68a;
            border-left: 3px solid #f0b90b;
            border-radius: 8px;
        }
        .rmbz-wg-reason-wrap[hidden] { display: none; }
        .rmbz-wg-reason-label {
            display: block;
            font-size: 11px;
            font-weight: 600;
            color: #92400e;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            margin-bottom: 8px;
        }
        .rmbz-wg-reason-label small {
            display: block;
            color: #b45309;
            font-weight: 400;
            text-transform: none;
            letter-spacing: 0;
            margin-top: 3px;
            font-size: 11px;
        }
        .rmbz-wg-reason-textarea {
            width: 100%;
            min-height: 80px;
            padding: 10px 12px;
            border: 1px solid #fde68a;
            border-radius: 7px;
            font-size: 13px;
            color: #1f2937;
            font-family: inherit;
            resize: vertical;
            background: #fffbeb;
            transition: border-color 0.15s, background 0.15s;
        }
        .rmbz-wg-reason-textarea:focus {
            outline: none;
            border-color: #f0b90b;
            background: #fff;
            box-shadow: 0 0 0 3px rgba(240, 185, 11, 0.15);
        }
        </style>

        <script>
        // Expandir/colapsar o textarea de motivo conforme o checkbox crítico
        (function () {
            document.querySelectorAll('.rmbz-wg-check-critical').forEach(function (row) {
                var cb = row.querySelector('input[type="checkbox"]');
                var wrap = row.querySelector('.rmbz-wg-reason-wrap');
                if (!cb || !wrap) return;
                cb.addEventListener('change', function () {
                    if (cb.checked) {
                        wrap.hidden = false;
                        var ta = wrap.querySelector('textarea');
                        if (ta && !ta.value) ta.focus();
                    } else {
                        wrap.hidden = true;
                    }
                });
            });
        })();
        </script>

        <script>
            (function () {
                var modal = document.getElementById('rmbz-wg-tx-modal');
                if (!modal) return;

                function setText(id, val) {
                    var el = document.getElementById(id);
                    if (el) el.textContent = (val == null || val === '') ? '—' : String(val);
                }
                function formatAmount(n) {
                    if (typeof n !== 'number') n = parseFloat(n) || 0;
                    var s = n.toLocaleString('pt-PT', {
                        minimumFractionDigits: 2, maximumFractionDigits: 2,
                    });
                    return (n >= 0 ? '+' : '') + s + ' MT';
                }
                function formatDate(s) {
                    if (!s || s === '0000-00-00 00:00:00') return '—';
                    // MySQL "YYYY-MM-DD HH:MM:SS" → "DD/MM/YYYY HH:MM"
                    var m = s.match(/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})/);
                    if (m) return m[3] + '/' + m[2] + '/' + m[1] + ' ' + m[4] + ':' + m[5];
                    return s;
                }

                function openTx(data) {
                    var amount = parseFloat(data.amount) || 0;
                    var isCredit = amount >= 0;

                    // Valor (bloco grande)
                    var amountEl = document.getElementById('wg-tx-amount');
                    if (amountEl) {
                        amountEl.textContent = formatAmount(amount);
                        amountEl.className = 'rmbz-wg-tx-amount ' + (isCredit ? 'is-credit' : 'is-debit');
                    }

                    setText('wg-tx-date', formatDate(data.date));

                    // Tipo (com tag <code>)
                    var typeEl = document.getElementById('wg-tx-type');
                    if (typeEl) {
                        typeEl.innerHTML = '';
                        var codeEl = document.createElement('code');
                        codeEl.textContent = data.type || '—';
                        typeEl.appendChild(codeEl);
                    }

                    setText('wg-tx-direction', isCredit ? '⬆ Entrada (crédito)' : '⬇ Saída (débito)');
                    setText('wg-tx-details', data.details && data.details.trim() !== ''
                        ? data.details : 'Sem descrição registada.');

                    modal.classList.add('is-open');
                    modal.setAttribute('aria-hidden', 'false');
                }

                function closeTx() {
                    modal.classList.remove('is-open');
                    modal.setAttribute('aria-hidden', 'true');
                }

                document.addEventListener('click', function (e) {
                    var btn = e.target.closest('.rmbz-wg-tx-view-btn');
                    if (btn) {
                        try {
                            openTx(JSON.parse(btn.getAttribute('data-tx')));
                        } catch (err) {
                            console.error('1MZ: payload tx inválido', err);
                        }
                        return;
                    }
                    if (e.target.closest('[data-close-tx-modal]')) closeTx();
                });
                document.addEventListener('keydown', function (e) {
                    if (e.key === 'Escape' && modal.classList.contains('is-open')) closeTx();
                });
            })();
        </script>
    </div>
    <?php
}

// ============================================================================
// [1.6.1] EXTENSÃO DE ANÁLISE DE ORIGEM
// ============================================================================
// Carrega flags e renderização adicionais que dependem das colunas de origem
// em rmbz_withdrawal_requests e da tabela rmbz_app_devices.
// Se o ficheiro não existir, simplesmente não carrega (compatibilidade).
$rmbz_origin_ext = __DIR__ . '/admin-withdrawal-guard-origin.php';
if ( file_exists( $rmbz_origin_ext ) ) {
    require_once $rmbz_origin_ext;
}
