<?php
if(!isLoggedIn()) { redirect(1,'login'); return; }
$roulette = $this;
$fragmentIconUrl = __PATH_TEMPLATE_IMG__.'nexora-fragment.png?v=1.8.0';
$wcCoinIconUrl = __PATH_TEMPLATE_IMG__.'nexora-wc-coin.png?v=1.8.0';
$legacyIconUrl = __PATH_TEMPLATE_IMG__.'nexora-legacy-icon.png?v=1.8.0';
$reentryIconUrl = __PATH_TEMPLATE_IMG__.'nexora-reentry-icon.png?v=1.8.0';
$wheelBrandLogoUrl = __PATH_TEMPLATE_IMG__.'mu-nexora-wheel-center.png?v=1.7.2';
$soundBaseUrl = __PATH_TEMPLATE__.'sounds/nexoraroulette/';
if(!function_exists('nxrFragmentIconHtml')) {
    function nxrFragmentIconHtml($url, $class='nxr-fragment-inline') {
        return '<span class="'.htmlspecialchars($class,ENT_QUOTES,'UTF-8').'" aria-hidden="true"><img src="'.htmlspecialchars($url,ENT_QUOTES,'UTF-8').'" alt=""></span>';
    }
}
if(!function_exists('nxrNormalizeRewardText')) {
    function nxrNormalizeRewardText($value) {
        $value = mb_strtolower(trim((string)$value), 'UTF-8');
        $value = str_replace(array('á','à','ä','â','ã','å','é','è','ë','ê','í','ì','ï','î','ó','ò','ö','ô','õ','ú','ù','ü','û','ñ'), array('a','a','a','a','a','a','e','e','e','e','i','i','i','i','o','o','o','o','o','u','u','u','u','n'), $value);
        $value = preg_replace('/\s+/', ' ', $value);
        return trim((string)$value);
    }
}
if(!function_exists('nxrRewardTextHas')) {
    function nxrRewardTextHas($value, array $needles) {
        $haystack = nxrNormalizeRewardText($value);
        foreach($needles as $needle) {
            $needle = nxrNormalizeRewardText($needle);
            if($needle !== '' && mb_strpos($haystack, $needle, 0, 'UTF-8') !== false) return true;
        }
        return false;
    }
}

$spinResult = null;
$spinError = null;
$exchangeResult = null;
$exchangeError = null;

$spinRequested = ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST'
    && (isset($_POST['spin_submit']) || ((string)($_POST['roulette_action'] ?? '') === 'spin'));

if($spinRequested) {
    try {
        $spinResult = $roulette->spin(
            (int)$_SESSION['userid'],
            (string)$_SESSION['username'],
            (string)($_POST['roulette_request_token'] ?? '')
        );
    } catch(Throwable $e) {
        $spinError = $e->getMessage();
        message('error', $spinError);
    }
}

if(isset($_POST['claim_spin_id'])) {
    try {
        $claim = $roulette->claimItem(
            (int)$_POST['claim_spin_id'],
            (int)$_SESSION['userid'],
            (string)$_SESSION['username']
        );
        message('success', !empty($claim['already']) ? 'Este premio ya había sido entregado.' : 'Entrega confirmada. El ítem ya está en tu baúl.');
    } catch(Throwable $e) {
        message('error', $e->getMessage());
    }
}

$exchangeAction = (string)($_POST['roulette_action'] ?? '');
if(($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && $exchangeAction === 'redeem_fragment') {
    try {
        $exchangeResult = $roulette->redeemFragmentReward(
            (int)($_POST['exchange_reward_id'] ?? 0),
            (int)$_SESSION['userid'],
            (string)$_SESSION['username'],
            (string)($_POST['exchange_request_token'] ?? '')
        );
        $msg='Canje #'.(int)$exchangeResult['redemption_id'].' confirmado: '.(string)$exchangeResult['reward']['name'].'.';
        if((string)$exchangeResult['status']==='pending_item') {
            $msg.=' La recompensa quedó reservada para tu cuenta.';
            if(trim((string)($exchangeResult['delivery_error']??''))!=='') $msg.=' '.trim((string)$exchangeResult['delivery_error']);
        } elseif((string)$exchangeResult['status']==='pending_manual') {
            $msg.=' La entrega quedó registrada para revisión del staff.';
        }
        message('success',$msg);
    } catch(Throwable $e) {
        $exchangeError=$e->getMessage();
        message('error',$exchangeError);
    }
}

if(($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && ($exchangeAction === 'claim_exchange_item' || isset($_POST['claim_exchange_id']))) {
    try {
        $claim=$roulette->claimExchangeItem(
            (int)($_POST['claim_exchange_id'] ?? 0),
            (int)$_SESSION['userid'],
            (string)$_SESSION['username'],
            (string)($_POST['exchange_request_token'] ?? ''),
            true
        );
        message('success',!empty($claim['already'])?'Este canje ya había sido entregado.':'Entrega confirmada. El ítem canjeado ya está en tu baúl.');
    } catch(Throwable $e) {
        $exchangeError=$e->getMessage();
        message('error',$exchangeError);
    }
}

$socialAction=(string)($_POST['roulette_action'] ?? '');
if(($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST' && $socialAction === 'save_public_nickname') {
    try {
        $roulette->savePublicNickname(
            (int)$_SESSION['userid'],
            (string)$_SESSION['username'],
            (string)($_POST['public_nickname'] ?? ''),
            (string)($_POST['social_request_token'] ?? '')
        );
        message('success','Tu apodo público fue actualizado. La comunidad verá este nombre en Actividad reciente.');
    } catch(Throwable $e) {
        message('error',$e->getMessage());
    }
}

$settings = $roulette->settings();
$poolStudio = new \Plugin\NexoraRoulette\NexoraPoolStudio($roulette->getRealm());
$poolExperience = $poolStudio->publicConfig();
$prizeAvailability = $roulette->prizeAvailability((string)$_SESSION['username']);
$state = $roulette->state((string)$_SESSION['username']);
$progressSnapshot = $roulette->progressSnapshot((string)$_SESSION['username']);
$networkProfile = $roulette->networkProfile((string)$_SESSION['username']);
$exchangeRewards = (!empty($settings['show_exchange']) && !empty($settings['progression_enabled'])) ? $roulette->getExchangeRewards(true) : array();
$exchangeUsage = (!empty($settings['show_exchange']) && !empty($settings['progression_enabled'])) ? $roulette->exchangeUsage((string)$_SESSION['username']) : array('global'=>array(),'account'=>array());
$exchangeHistory = (!empty($settings['show_exchange']) && !empty($settings['progression_enabled'])) ? $roulette->accountExchangeHistory((string)$_SESSION['username'],8) : array();
$odds = $roulette->odds(true);
$prizes = $odds['prizes'];
$history = !empty($settings['show_history']) ? $roulette->accountHistory((string)$_SESSION['username'], 20) : array();
$recent = !empty($settings['show_recent_winners']) ? $roulette->recentWins(12) : array();
$balance = null;
try {
    $balance = $roulette->currentBalance((int)$_SESSION['userid'], (string)$_SESSION['username']);
} catch(Throwable $ignored) {}

$walletLabel = 'Moneda';
foreach($roulette->creditConfigs() as $cfg) {
    if((int)$cfg['config_id'] === (int)$settings['credit_config']) {
        $walletLabel = (string)$cfg['config_title'];
        break;
    }
}

$creditLabels=array();
foreach($roulette->creditConfigs() as $cfg) $creditLabels[(int)$cfg['config_id']]=(string)$cfg['config_title'];
$exchangeCards=array();
foreach($exchangeRewards as $reward) {
    $rewardId=(int)$reward['id'];
    $globalUsed=(int)($exchangeUsage['global'][$rewardId]??0);
    $accountUsed=(int)($exchangeUsage['account'][$rewardId]??0);
    $globalLimit=max(0,(int)$reward['global_limit']);
    $accountLimit=max(0,(int)$reward['account_limit']);
    $globalRemaining=$globalLimit>0?max(0,$globalLimit-$globalUsed):null;
    $accountRemaining=$accountLimit>0?max(0,$accountLimit-$accountUsed):null;
    $available=($globalRemaining===null || $globalRemaining>0) && ($accountRemaining===null || $accountRemaining>0);
    $canAfford=(int)$progressSnapshot['fragments'] >= (int)$reward['fragment_cost'];
    $visual=null;
    $customVisualUrl='';
    if(trim((string)($reward['image_file']??''))!=='') $customVisualUrl=__PATH_TEMPLATE__.'img/nexoraroulette/exchange/'.rawurlencode(basename((string)$reward['image_file']));
    if((string)$reward['reward_type']==='itemshop' && !empty($reward['item_id'])) $visual=$roulette->itemshopRewardVisual((int)$reward['item_id']);
    $delivery='Entrega registrada';
    if((string)$reward['reward_type']==='credits') $delivery='+'.number_format((int)$reward['amount']).' '.($creditLabels[(int)$reward['credit_config_id']]??'créditos');
    elseif((string)$reward['reward_type']==='free_spins') $delivery='+'.number_format((int)$reward['amount']).' giro'.((int)$reward['amount']===1?'':'s');
    elseif((string)$reward['reward_type']==='itemshop') $delivery=is_array($visual)&&trim((string)($visual['name']??''))!==''?(string)$visual['name']:'Ítem de Arsenal';
    elseif((string)$reward['reward_type']==='manual') $delivery='Entrega coordinada por staff';
    $exchangeCards[]=array(
        'reward'=>$reward,'global_used'=>$globalUsed,'account_used'=>$accountUsed,'global_remaining'=>$globalRemaining,
        'account_remaining'=>$accountRemaining,'available'=>$available,'can_afford'=>$canAfford,'visual'=>$visual,'custom_visual_url'=>$customVisualUrl,'delivery'=>$delivery,
    );
}

$rarityLabels = \Plugin\NexoraRoulette\NexoraRoulette::rarityLabels();
$segmentData = array();
$visualCount = count($prizes);
$equalAngle = $visualCount > 0 ? (360 / $visualCount) : 360;
$topPrizeNames = array();

foreach($prizes as $index => $prize) {
    $start = $index * $equalAngle;
    $end = ($index + 1) * $equalAngle;
    $mid = ($start + $end) / 2;
    $name = (string)$prize['name'];
    $shortName = $name;
    if(mb_strlen($shortName) > 18) $shortName = mb_substr($shortName, 0, 16) . '…';
    if($equalAngle < 24) {
        $pieces = preg_split('/\s+/', trim($name));
        if(is_array($pieces) && count($pieces) > 1) $shortName = (string)$pieces[0];
    }
    $iconType = 'manual';
    $iconUrl = '';
    $prizeType = (string)$prize['prize_type'];
    $displayLabel = $shortName;
    if($prizeType === 'credits') $displayLabel = number_format((int)$prize['amount']).' WC';
    elseif($prizeType === 'free_spins') $displayLabel = '+'.number_format(max(1,(int)$prize['amount'])).' GIRO'.((int)$prize['amount']===1?'':'S');
    elseif($prizeType === 'fragments') $displayLabel = '+'.number_format(max(1,(int)$prize['amount'])).' NXR';
    elseif($prizeType === 'itemshop') {
        if(nxrRewardTextHas($name,array('legado nexora','legado nxr'))) $displayLabel='LEGADO';
        elseif((string)$prize['rarity']==='legendary') $displayLabel='LEGENDARIO';
        elseif((string)$prize['rarity']==='epic') $displayLabel='ÉPICO';
        elseif((string)$prize['rarity']==='rare') $displayLabel='RARO';
        else $displayLabel=mb_strtoupper($shortName,'UTF-8');
    }
    $availabilityRow = $prizeAvailability[(int)$prize['id']] ?? array();
    $prizeTextIndex = $name.' '.(string)($prize['description'] ?? '').' '.$prizeType;
    if($prizeType === 'credits') { $iconType = 'credits'; $iconUrl = $wcCoinIconUrl; }
    elseif($prizeType === 'free_spins') {
        $iconType = 'spin';
        if(nxrRewardTextHas($prizeTextIndex, array('reentrada nexora','reentrada nxr','reentrada'))) $iconUrl = $reentryIconUrl;
    }
    elseif($prizeType === 'fragments') { $iconType = 'fragments'; $iconUrl = $fragmentIconUrl; }
    elseif($prizeType === 'itemshop') {
        $iconType = 'item';
        if(!empty($settings['show_segment_icons']) && !empty($prize['item_id'])) {
            $visual = $roulette->itemshopRewardVisual((int)$prize['item_id']);
            if(is_array($visual) && !empty($visual['url'])) $iconUrl = (string)$visual['url'];
        }
    }
    if(nxrRewardTextHas($prizeTextIndex, array('legado nexora','legado nxr'))) {
        $iconType = 'manual';
        $iconUrl = $legacyIconUrl;
    }
    $segmentData[] = array(
        'id' => (int)$prize['id'],
        'name' => $name,
        'short_name' => $shortName,
        'display_label' => $displayLabel,
        'rarity' => (string)$prize['rarity'],
        'rarity_label' => (string)($rarityLabels[$prize['rarity']] ?? $prize['rarity']),
        'probability' => (float)$prize['probability'],
        'start' => round($start, 4),
        'end' => round($end, 4),
        'mid' => round($mid, 4),
        'angle' => round($equalAngle, 4),
        'description' => (string)$prize['description'],
        'prize_type' => $prizeType,
        'amount' => (int)$prize['amount'],
        'icon_type' => $iconType,
        'icon_url' => $iconUrl,
        'global_limit' => (int)($availabilityRow['global_limit'] ?? 0),
        'global_remaining' => isset($availabilityRow['global_remaining']) ? $availabilityRow['global_remaining'] : null,
        'account_limit' => (int)($availabilityRow['account_limit'] ?? 0),
        'account_remaining' => isset($availabilityRow['account_remaining']) ? $availabilityRow['account_remaining'] : null,
        'visual_index' => (int)$index,
    );
    $topPrizeNames[] = $name;
}

$resultData = null;
if($spinResult) {
    $resultSegment = null;
    foreach($segmentData as $segmentRow) {
        if((int)$segmentRow['id'] === (int)$spinResult['prize']['id']) { $resultSegment = $segmentRow; break; }
    }
    $resultStatusLabel = 'Premio acreditado';
    if($spinResult['status'] === 'pending_item') $resultStatusLabel = 'Reclamar en Arsenal';
    elseif($spinResult['status'] === 'pending_manual') $resultStatusLabel = 'Entrega manual pendiente';
    $resultData = array(
        'id'=>(int)$spinResult['spin_id'],
        'status'=>(string)$spinResult['status'],
        'status_label'=>$resultStatusLabel,
        'cost'=>(int)($spinResult['cost']??0),
        'used_free_spin'=>!empty($spinResult['used_free_spin']),
        'pity_triggered'=>!empty($spinResult['pity_triggered']),
        'fragments_earned'=>(int)($spinResult['fragments_earned']??0),
        'fragments_balance'=>(int)($spinResult['fragments_balance']??$progressSnapshot['fragments']),
        'milestones_awarded'=>isset($spinResult['milestones_awarded'])&&is_array($spinResult['milestones_awarded'])?$spinResult['milestones_awarded']:array(),
        'prize'=>array(
            'id'=>(int)$spinResult['prize']['id'],
            'name'=>(string)$spinResult['prize']['name'],
            'description'=>(string)$spinResult['prize']['description'],
            'rarity'=>(string)$spinResult['prize']['rarity'],
            'rarity_label'=>(string)($rarityLabels[$spinResult['prize']['rarity']] ?? $spinResult['prize']['rarity']),
            'type'=>(string)$spinResult['prize']['prize_type'],
            'amount'=>(int)($spinResult['prize']['amount']??0),
            'icon_type'=>is_array($resultSegment)?(string)$resultSegment['icon_type']:'manual',
            'icon_url'=>is_array($resultSegment)?(string)$resultSegment['icon_url']:'',
        ),
    );
}

$featuredPrize = null;
$featuredId = max(0,(int)($poolExperience['featured_prize_id']??0));
if($featuredId>0) foreach($prizes as $p) if((int)$p['id']===$featuredId) { $featuredPrize=$p; break; }
if(!is_array($featuredPrize)) foreach($prizes as $p) if((string)$p['rarity']==='legendary') { $featuredPrize=$p; break; }
if(!is_array($featuredPrize) && $prizes) $featuredPrize=$prizes[0];
$featuredVisualUrl='';
$featuredAvailability=array();
if(is_array($featuredPrize)) {
    foreach($segmentData as $sg) if((int)$sg['id']===(int)$featuredPrize['id']) { $featuredVisualUrl=(string)$sg['icon_url']; break; }
    $featuredAvailability=$prizeAvailability[(int)$featuredPrize['id']]??array();
}
$requestToken = \Plugin\NexoraRoulette\NexoraRoulette::issueSpinToken();
$exchangeToken = \Plugin\NexoraRoulette\NexoraRoulette::issueExchangeToken();
$socialToken = \Plugin\NexoraRoulette\NexoraRoulette::issueSocialToken();
$pityThreshold = max(0, (int)$settings['pity_threshold']);
$pityCurrent = max(0, (int)$state['pity_streak']);
$pityRemaining = 0;
if(!empty($settings['pity_enabled']) && $pityThreshold > 0) {
    $pityRemaining = max(1, $pityThreshold - $pityCurrent);
}
$canSpin = $roulette->isEnabled() && $visualCount > 0;
$realmLabel = $roulette->getRealmLabel();
$spinButtonSub = (int)$state['free_spins'] > 0
    ? 'No consume saldo'
    : number_format((int)$settings['spin_cost']) . ' ' . $walletLabel;
$nextMilestone = isset($progressSnapshot['next']) && is_array($progressSnapshot['next']) ? $progressSnapshot['next'] : null;
$milestoneProgressPct = 100;
$milestoneRemaining = 0;
if($nextMilestone) {
    $previousThreshold = 0;
    foreach($progressSnapshot['milestones'] as $m) { if((int)$m['spins'] < (int)$nextMilestone['spins']) $previousThreshold=max($previousThreshold,(int)$m['spins']); }
    $span=max(1,(int)$nextMilestone['spins']-$previousThreshold);
    $within=max(0,(int)$state['total_spins']-$previousThreshold);
    $milestoneProgressPct=min(100,($within/$span)*100);
    $milestoneRemaining=max(0,(int)$nextMilestone['spins']-(int)$state['total_spins']);
}
$rootStyle = implode(';', array(
    '--nxr-accent:'.$settings['accent_color'],
    '--nxr-accent-soft:'.$settings['accent_soft_color'],
    '--nxr-secondary:'.$settings['secondary_color'],
    '--nxr-panel:'.$settings['panel_color'],
    '--nxr-bg:'.$settings['background_color'],
    '--nxr-wheel-size:'.(int)$settings['wheel_size'].'px',
    '--nxr-segment-gap:'.(int)$settings['segment_gap'].'px',
    '--nxr-spin-duration:'.(int)$settings['spin_duration_ms'].'ms',
));
?>
<link rel="stylesheet" href="<?php echo htmlspecialchars(__PATH_TEMPLATE_CSS__ . 'nexora-roulette.css?v=1.8.0', ENT_QUOTES, 'UTF-8'); ?>">
<div class="nxr-shell" style="<?php echo htmlspecialchars($rootStyle, ENT_QUOTES, 'UTF-8'); ?>">
    <section class="nxr-hero">
        <div class="nxr-hero-copy">
            <span class="nxr-kicker"><?php echo htmlspecialchars($realmLabel,ENT_QUOTES,'UTF-8'); ?> · <?php echo htmlspecialchars($settings['hero_kicker'],ENT_QUOTES,'UTF-8'); ?></span>
            <h1><?php echo htmlspecialchars($settings['title'],ENT_QUOTES,'UTF-8'); ?></h1>
            <p><?php echo htmlspecialchars($settings['hero_description'],ENT_QUOTES,'UTF-8'); ?></p>
            <?php if($topPrizeNames) { ?>
                <div class="nxr-pool-highlight nxr-pool-highlight--campaign">
                    <span><?php echo htmlspecialchars((string)($poolExperience['campaign_title']??'Pool activo'),ENT_QUOTES,'UTF-8'); ?></span>
                    <b><?php echo htmlspecialchars(implode(' · ', array_slice($topPrizeNames,0,6)),ENT_QUOTES,'UTF-8'); ?></b>
                    <?php if(!empty($poolExperience['show_campaign']) && !empty($poolExperience['campaign_ends_at'])) { ?><small class="nxr-campaign-countdown" data-nxr-countdown="<?php echo htmlspecialchars((string)$poolExperience['campaign_ends_at'],ENT_QUOTES,'UTF-8'); ?>">Calculando ventana de campaña…</small><?php } ?>
                </div>
            <?php } ?>
        </div>
        <div class="nxr-hero-side">
            <div class="nxr-hero-balance">
                <span><?php echo htmlspecialchars($walletLabel,ENT_QUOTES,'UTF-8'); ?></span>
                <strong id="nxrWalletBalance"><?php echo $balance===null?'—':number_format((int)$balance); ?></strong>
                <small id="nxrFreeSpins">Giros disponibles: <?php echo number_format((int)$state['free_spins']); ?></small>
            </div>
        </div>
    </section>

    <?php if(!$roulette->isEnabled()) { ?><div class="nxr-notice">La ruleta está en preparación para este reino. El staff puede estructurarla sin afectar el saldo de los jugadores.</div><?php } ?>
    <?php if(!$prizes) { ?><div class="nxr-notice nxr-notice-warning">Todavía no hay premios activos con peso de probabilidad.</div><?php } ?>
    <?php $moduleError=$spinError!==null?$spinError:$exchangeError; ?><div id="nxrFlash" class="nxr-flash<?php echo $moduleError !== null ? ' is-visible is-error' : ''; ?>"<?php echo $moduleError === null ? ' hidden' : ''; ?>><?php echo $moduleError !== null ? htmlspecialchars($moduleError, ENT_QUOTES, 'UTF-8') : ''; ?></div>

    <?php if(!empty($settings['show_stats'])) { ?>
    <section class="nxr-stats">
        <article class="nxr-stat-card"><span>Saldo</span><strong id="nxrStatBalance"><?php echo $balance===null?'—':number_format((int)$balance); ?></strong><small><?php echo htmlspecialchars($walletLabel,ENT_QUOTES,'UTF-8'); ?></small></article>
        <article class="nxr-stat-card"><span>Costo</span><strong><?php echo number_format((int)$settings['spin_cost']); ?></strong><small><?php echo htmlspecialchars($walletLabel,ENT_QUOTES,'UTF-8'); ?></small></article>
        <article class="nxr-stat-card"><span>Giros</span><strong id="nxrTotalSpins"><?php echo number_format((int)$state['total_spins']); ?></strong><small>Acumulados en este reino</small></article>
        <article class="nxr-stat-card"><span>Racha</span><strong id="nxrPityCounter"><?php echo !empty($settings['pity_enabled']) ? number_format($pityCurrent).' / '.number_format($pityThreshold) : '—'; ?></strong><small>Protección de constancia</small></article>
    </section>
    <?php } ?>

    <?php if(!empty($settings['progression_enabled']) && !empty($settings['show_progress'])) { ?>
    <section class="nxr-progression-strip">
        <div class="nxr-fragment-balance">
            <?php echo nxrFragmentIconHtml($fragmentIconUrl,'nxr-fragment-mark'); ?>
            <div><small>FRAGMENTOS NXR</small><strong id="nxrFragmentBalanceValue" data-final="<?php echo (int)$progressSnapshot['fragments']; ?>"><?php echo number_format((int)$progressSnapshot['fragments']); ?></strong><span>Acumulados: <?php echo number_format((int)$progressSnapshot['lifetime_fragments']); ?></span></div>
        </div>
        <div class="nxr-milestone-track">
            <?php if($nextMilestone) { ?>
            <div class="nxr-milestone-copy"><div><small>PRÓXIMO HITO</small><strong><?php echo number_format((int)$state['total_spins']); ?> / <?php echo number_format((int)$nextMilestone['spins']); ?> giros</strong></div><span><?php echo number_format($milestoneRemaining); ?> restante<?php echo $milestoneRemaining===1?'':'s'; ?></span></div>
            <div class="nxr-milestone-bar"><i id="nxrMilestoneProgressBar" style="width:<?php echo number_format($milestoneProgressPct,2,'.',''); ?>%"></i></div>
            <div class="nxr-milestone-reward"><span>Al completar</span><b><?php echo (int)$nextMilestone['fragments']>0?'+'.number_format((int)$nextMilestone['fragments']).' fragmentos':''; ?><?php echo ((int)$nextMilestone['fragments']>0 && (int)$nextMilestone['free_spins']>0)?' · ':''; ?><?php echo (int)$nextMilestone['free_spins']>0?'+'.number_format((int)$nextMilestone['free_spins']).' giro'.((int)$nextMilestone['free_spins']===1?'':'s'):''; ?></b></div>
            <?php } else { ?>
            <div class="nxr-milestone-copy"><div><small>HITOS DE CONSTANCIA</small><strong>Ciclo completado</strong></div><span>Tu progreso permanece registrado</span></div>
            <div class="nxr-milestone-bar is-complete"><i style="width:100%"></i></div>
            <?php } ?>
        </div>
    </section>
    <?php } ?>

    <?php if(!empty($settings['progression_enabled']) && !empty($settings['show_progress'])) { ?>
    <section class="nxr-fragment-story" aria-label="Qué son los Fragmentos NXR">
        <div class="nxr-fragment-story-icon"><img src="<?php echo htmlspecialchars($fragmentIconUrl,ENT_QUOTES,'UTF-8'); ?>" alt="Talismán Fragmento NXR"></div>
        <div class="nxr-fragment-story-copy">
            <span class="nxr-section-label">EL TALISMÁN DE NEXORA</span>
            <h2>Tu constancia toma forma.</h2>
            <p>Los <strong>Fragmentos NXR</strong> son piezas del talismán de Nexora que representan progreso acumulado. Los obtienes al girar, alcanzar hitos y recibir recompensas especiales; permanecen ligados a tu cuenta y a este reino.</p>
            <div class="nxr-fragment-story-points">
                <span><b>ACUMULA</b> Cada giro puede fortalecer tu reserva.</span>
                <span><b>CONSERVA</b> Tu progreso no desaparece por una mala racha.</span>
                <span><b>CANJEA</b> Úsalos en el catálogo por recompensas controladas.</span>
            </div>
        </div>
        <?php if(!empty($settings['show_exchange'])) { ?><a class="nxr-fragment-story-cta" href="#nxrFragmentExchange">VER CANJES <span>↓</span></a><?php } ?>
    </section>
    <?php } ?>

    <section class="nxr-main-grid <?php echo empty($settings['show_pool'])?'nxr-main-grid--solo':''; ?>">
        <div class="nxr-wheel-panel" id="nxrPlayZone">
            <div class="nxr-panel-head">
                <div><span class="nxr-section-label">CENTRO DE GIRO</span><h2>Movimiento, tensión y resultado</h2></div>
                <div class="nxr-panel-tools">
                    <small><?php echo $visualCount>0 ? number_format($visualCount).' segmentos iguales · '.number_format($equalAngle,2).'° por sector' : 'Esperando pool activo'; ?></small>
                    <?php if(!empty($settings['sound_enabled']) && (string)($settings['sound_profile']??'nexora')!=='silent') { ?><button type="button" id="nxrSoundToggle" class="nxr-sound-toggle" aria-pressed="false" title="Activar o silenciar sonido Nexora"><i aria-hidden="true"><span></span><span></span><span></span></i><b>SONIDO</b></button><?php } ?>
                    <button type="button" id="nxrMotionModeToggle" class="nxr-mode-toggle" aria-pressed="false" title="Alternar giro rápido o cinemático"><span aria-hidden="true">⚡</span><b>MODO</b><em id="nxrMotionModeLabel">CINEMÁTICO</em></button>
                    <?php if(!empty($poolExperience['show_probability_modal'])) { ?><button type="button" id="nxrOddsOpen" class="nxr-odds-button"><span aria-hidden="true">%</span><b>PROBABILIDADES</b></button><?php } ?>
                </div>
            </div>

            <?php if(!empty($poolExperience['show_campaign'])) { ?>
            <div class="nxr-campaign-strip is-<?php echo htmlspecialchars((string)($poolExperience['campaign_state']??'active'),ENT_QUOTES,'UTF-8'); ?>">
                <div><small>POOL DE CAMPAÑA</small><strong><?php echo htmlspecialchars((string)($poolExperience['campaign_title']??'Pool activo'),ENT_QUOTES,'UTF-8'); ?></strong><span><?php echo htmlspecialchars((string)($poolExperience['campaign_subtitle']??''),ENT_QUOTES,'UTF-8'); ?></span></div>
                <?php if(!empty($poolExperience['campaign_ends_at'])) { ?><div class="nxr-campaign-clock"><small>VENTANA</small><strong class="nxr-campaign-countdown" data-nxr-countdown="<?php echo htmlspecialchars((string)$poolExperience['campaign_ends_at'],ENT_QUOTES,'UTF-8'); ?>">—</strong></div><?php } ?>
            </div>
            <?php } ?>
            <div class="nxr-wheel-machine">
                <div class="nxr-wheel-frame">
                    <div class="nxr-wheel-glow"></div>
                    <div class="nxr-wheel-brand-halo" aria-hidden="true"></div>
                    <div class="nxr-wheel-ornate-ring" aria-hidden="true"></div>
                    <div id="nxrWheelPointer" class="nxr-wheel-pointer" aria-hidden="true"><span class="nxr-wheel-pointer-cap"></span><span class="nxr-wheel-pointer-head"></span><span class="nxr-wheel-pointer-stem"></span></div>
                    <div id="nxrWheelCanvas" class="nxr-wheel-canvas"><div id="nxrWheelSvgMount" class="nxr-wheel-svg-mount"></div></div>
                    <div id="nxrWheelCoreOverlay" class="nxr-wheel-core-overlay">
                        <div class="nxr-wheel-core-aura"></div>
                        <div class="nxr-wheel-core-center nxr-wheel-core-brand">
                            <img class="nxr-wheel-brand-logo" src="<?php echo htmlspecialchars($wheelBrandLogoUrl,ENT_QUOTES,'UTF-8'); ?>" alt="MU Nexora" onerror="this.style.display='none';this.parentNode.classList.add('is-logo-fallback');">
                            <span class="nxr-wheel-brand-fallback" aria-hidden="true">NXR</span>
                            <small id="nxrWheelCoreSpins"><?php echo number_format((int)$state['total_spins']); ?> giros realizados</small>
                        </div>
                    </div>
                </div>
            </div>

            <form method="post" action="" id="nxrSpinForm" class="nxr-spin-form" novalidate>
                <input type="hidden" name="roulette_action" value="spin">
                <input type="hidden" name="roulette_request_token" id="nxrRequestToken" value="<?php echo htmlspecialchars($requestToken,ENT_QUOTES,'UTF-8'); ?>">
                <button type="submit" name="spin_submit" value="1" id="nxrSpinButton" class="nxr-spin-button" <?php echo $canSpin?'':'disabled'; ?>>
                    <span id="nxrSpinButtonLabel"><?php echo (int)$state['free_spins']>0?'USAR GIRO DISPONIBLE':htmlspecialchars($settings['spin_cta_label'],ENT_QUOTES,'UTF-8'); ?></span>
                    <small id="nxrSpinButtonSub"><?php echo htmlspecialchars($spinButtonSub,ENT_QUOTES,'UTF-8'); ?></small>
                </button>
            </form>

            <div class="nxr-play-status" aria-label="Estado inmediato de la ruleta">
                <div><small>GIROS</small><strong id="nxrPlayStatusSpins"><?php echo number_format((int)$state['total_spins']); ?></strong></div>
                <div><small>FRAGMENTOS</small><strong id="nxrPlayStatusFragments"><?php echo number_format((int)$progressSnapshot['fragments']); ?></strong></div>
                <div><small>PITY</small><strong id="nxrPlayStatusPity"><?php echo !empty($settings['pity_enabled'])?number_format($pityCurrent).'/'.number_format($pityThreshold):'—'; ?></strong></div>
                <div><small>PRÓXIMO HITO</small><strong id="nxrPlayStatusMilestone"><?php echo $nextMilestone?number_format((int)$nextMilestone['spins']).' giros':'Completado'; ?></strong></div>
            </div>

            <div id="nxrPrizeInspector" class="nxr-prize-inspector" aria-live="polite">
                <div class="nxr-prize-inspector-icon" id="nxrPrizeInspectorIcon"><span>?</span></div>
                <div class="nxr-prize-inspector-copy"><small>EXPLORA EL POOL</small><strong id="nxrPrizeInspectorName">Toca o pasa sobre un sector</strong><span id="nxrPrizeInspectorMeta">Verás rareza, probabilidad y recompensa real.</span><p id="nxrPrizeInspectorDescription"></p></div>
            </div>

            <details class="nxr-session-card" id="nxrSessionCard"><summary><span>TU SESIÓN</span><b id="nxrSessionHeadline">Sin giros registrados en esta sesión</b></summary><div class="nxr-session-grid"><div><small>Giros</small><strong id="nxrSessionSpins">0</strong></div><div><small>Fragmentos</small><strong id="nxrSessionFragments">0</strong></div><div><small>Mejor rareza</small><strong id="nxrSessionBest">—</strong></div><div><small>Saldo usado</small><strong id="nxrSessionSpent">0</strong></div><div><small>Saldo recuperado</small><strong id="nxrSessionReturned">0</strong></div></div></details>

            <div id="nxrResult" class="nxr-result-card <?php echo $spinResult?'is-pending-reveal rarity-'.htmlspecialchars($spinResult['prize']['rarity'],ENT_QUOTES,'UTF-8'):''; ?>" <?php echo $spinResult?'aria-hidden="true"':''; ?>>
                <?php if($spinResult) { ?>
                    <div class="nxr-result-meta"><span>GIRO #<?php echo (int)$spinResult['spin_id']; ?></span><b><?php echo htmlspecialchars($rarityLabels[$spinResult['prize']['rarity']]??$spinResult['prize']['rarity'],ENT_QUOTES,'UTF-8'); ?></b></div>
                    <h3><?php echo htmlspecialchars($spinResult['prize']['name'],ENT_QUOTES,'UTF-8'); ?></h3>
                    <p><?php echo trim((string)$spinResult['prize']['description'])!==''?htmlspecialchars($spinResult['prize']['description'],ENT_QUOTES,'UTF-8'):'El premio ya quedó registrado dentro de tu historial operativo.'; ?></p>
                    <div class="nxr-result-state">
                        <?php if($spinResult['status']==='pending_item') { ?><span>Estado</span><b>Reclamar en Arsenal</b>
                        <?php } elseif($spinResult['status']==='pending_manual') { ?><span>Estado</span><b>Entrega manual pendiente</b>
                        <?php } else { ?><span>Estado</span><b>Premio acreditado</b><?php } ?>
                    </div>
                    <?php if((int)($spinResult['fragments_earned']??0)>0) { ?><div class="nxr-result-progress"><span>Progreso</span><b>+<?php echo number_format((int)$spinResult['fragments_earned']); ?> Fragmentos NXR</b></div><?php } ?>
                    <?php if(!empty($spinResult['milestones_awarded'])) { foreach($spinResult['milestones_awarded'] as $milestone) { ?><div class="nxr-result-milestone"><span>HITO #<?php echo (int)$milestone['number']; ?> COMPLETADO</span><b><?php echo number_format((int)$milestone['spins']); ?> giros de constancia</b><small><?php echo (int)$milestone['fragments']>0?'+'.number_format((int)$milestone['fragments']).' fragmentos':''; ?><?php echo ((int)$milestone['fragments']>0 && (int)$milestone['free_spins']>0)?' · ':''; ?><?php echo (int)$milestone['free_spins']>0?'+'.number_format((int)$milestone['free_spins']).' giro'.((int)$milestone['free_spins']===1?'':'s'):''; ?></small></div><?php } } ?>
                    <?php if(!empty($spinResult['pity_triggered'])) { ?><small class="nxr-result-foot">Este giro activó tu protección de constancia.</small><?php } ?>
                <?php } else { ?>
                    <div class="nxr-result-meta"><span>RESULTADO</span><b>Esperando giro</b></div>
                    <h3>La rueda está lista</h3>
                    <p>El movimiento visual es simétrico. La probabilidad real se mantiene protegida en el motor del servidor.</p>
                    <div class="nxr-result-state"><span>Estado</span><b>Sin evento todavía</b></div>
                <?php } ?>
            </div>

            <?php if($spinResult && !empty($settings['premium_reveal'])) { ?>
            <div id="nxrPremiumReveal" class="nxr-premium-reveal rarity-<?php echo htmlspecialchars($spinResult['prize']['rarity'],ENT_QUOTES,'UTF-8'); ?>" aria-hidden="true">
                <div class="nxr-reveal-backdrop"></div><div id="nxrRevealParticles" class="nxr-reveal-particles" aria-hidden="true"></div>
                <div class="nxr-reveal-card" role="dialog" aria-modal="true" aria-labelledby="nxrRevealPrizeName">
                    <button type="button" id="nxrRevealClose" class="nxr-reveal-close" aria-label="Cerrar resultado">×</button>
                    <span class="nxr-reveal-kicker">RESULTADO CONFIRMADO · GIRO #<?php echo (int)$spinResult['spin_id']; ?></span>
                    <div id="nxrRevealIcon" class="nxr-reveal-icon"></div>
                    <span class="nxr-reveal-rarity"><?php echo htmlspecialchars($rarityLabels[$spinResult['prize']['rarity']]??$spinResult['prize']['rarity'],ENT_QUOTES,'UTF-8'); ?></span>
                    <h3 id="nxrRevealPrizeName"><?php echo htmlspecialchars($spinResult['prize']['name'],ENT_QUOTES,'UTF-8'); ?></h3>
                    <p><?php echo trim((string)$spinResult['prize']['description'])!==''?htmlspecialchars($spinResult['prize']['description'],ENT_QUOTES,'UTF-8'):'El premio ya forma parte de tu trazabilidad dentro de Nexora.'; ?></p>
                    <div class="nxr-reveal-status"><span>Estado</span><b><?php echo htmlspecialchars($resultData['status_label'],ENT_QUOTES,'UTF-8'); ?></b></div>
                    <?php if((int)($spinResult['fragments_earned']??0)>0) { ?><div class="nxr-reveal-progress"><span>PROGRESO ACUMULADO</span><strong><span class="nxr-value-with-icon">+<?php echo number_format((int)$spinResult['fragments_earned']); ?><?php echo nxrFragmentIconHtml($fragmentIconUrl,'nxr-fragment-inline'); ?></span></strong><small>Saldo de Fragmentos NXR: <?php echo number_format((int)($spinResult['fragments_balance']??$progressSnapshot['fragments'])); ?></small></div><?php } ?>
                    <?php if(!empty($spinResult['milestones_awarded'])) { ?><div class="nxr-reveal-milestones"><?php foreach($spinResult['milestones_awarded'] as $milestone) { ?><div><span>HITO #<?php echo (int)$milestone['number']; ?></span><b><?php echo number_format((int)$milestone['spins']); ?> giros completados</b></div><?php } ?></div><?php } ?>
                    <button type="button" id="nxrRevealContinue" class="nxr-reveal-continue">CONTINUAR</button>
                </div>
            </div>
            <?php } ?>
        </div>

        <?php if(!empty($settings['show_pool'])) { ?>
        <aside class="nxr-side-column">
            <section class="nxr-side-card">
                <div class="nxr-side-head"><span class="nxr-section-label">SISTEMA</span><h3>Reglas visibles</h3></div>
                <div class="nxr-rule-list">
                    <div class="nxr-rule-row"><span>Costo</span><b><?php echo number_format((int)$settings['spin_cost']); ?> <?php echo htmlspecialchars($walletLabel,ENT_QUOTES,'UTF-8'); ?></b></div>
                    <div class="nxr-rule-row"><span>Intervalo</span><b><?php echo number_format((int)$settings['cooldown_seconds']); ?> s</b></div>
                    <div class="nxr-rule-row"><span>Límite diario</span><b><?php echo (int)$settings['daily_spin_limit']>0?number_format((int)$settings['daily_spin_limit']).' giros':'Sin límite'; ?></b></div>
                    <div class="nxr-rule-row"><span>Segmentos</span><b>Simétricos</b></div>
                    <?php if(!empty($settings['progression_enabled'])) { ?><div class="nxr-rule-row"><span>Progreso por giro</span><b><span class="nxr-value-with-icon">+<?php echo number_format((int)$settings['base_fragments_per_spin']); ?><?php echo nxrFragmentIconHtml($fragmentIconUrl,'nxr-fragment-inline'); ?></span> base</b></div><?php } ?>
                </div>
                <?php if(!empty($settings['pity_enabled']) && $pityThreshold>0) { ?>
                <div class="nxr-pity-box">
                    <div class="nxr-pity-head"><div><span>Protección de constancia</span><strong id="nxrPityBoxCount"><?php echo number_format($pityCurrent); ?> / <?php echo number_format($pityThreshold); ?></strong></div><b><?php echo number_format($pityRemaining); ?> restante<?php echo $pityRemaining===1?'':'s'; ?></b></div>
                    <p>Si no aparece un premio <?php echo htmlspecialchars($rarityLabels[$settings['pity_min_rarity']]??$settings['pity_min_rarity'],ENT_QUOTES,'UTF-8'); ?> o superior antes, el sistema lo garantiza al alcanzar el umbral.</p>
                    <div class="nxr-progress"><i id="nxrPityProgress" style="width:<?php echo min(100,(($pityCurrent/max(1,$pityThreshold))*100)); ?>%"></i></div>
                </div>
                <?php } ?>
            </section>

            <section class="nxr-side-card">
                <div class="nxr-side-head"><span class="nxr-section-label">POOL</span><h3>Premios activos</h3></div>
                <?php if(!empty($poolExperience['show_featured']) && is_array($featuredPrize)) { ?>
                <div class="nxr-featured-prize rarity-<?php echo htmlspecialchars((string)$featuredPrize['rarity'],ENT_QUOTES,'UTF-8'); ?>">
                    <div class="nxr-featured-icon"><?php if($featuredVisualUrl!==''){ ?><img src="<?php echo htmlspecialchars($featuredVisualUrl,ENT_QUOTES,'UTF-8'); ?>" alt=""><?php } else { ?><span>◆</span><?php } ?></div>
                    <div class="nxr-featured-copy"><small>PREMIO DESTACADO</small><strong><?php echo htmlspecialchars((string)$featuredPrize['name'],ENT_QUOTES,'UTF-8'); ?></strong><span><?php echo number_format((float)$featuredPrize['probability'],2); ?>%<?php if((int)($featuredAvailability['global_limit']??0)>0){ ?> · <?php echo number_format((int)($featuredAvailability['global_remaining']??0)); ?> disponibles hoy<?php } ?></span></div>
                </div>
                <?php } ?>
                <p class="nxr-side-note"><?php echo !empty($settings['show_odds']) ? 'Los porcentajes muestran la probabilidad real del motor. El tamaño visual de los sectores es idéntico para mantener armonía.' : 'La rueda presenta los premios en sectores iguales. El motor mantiene sus pesos de forma independiente.'; ?></p>
                <div class="nxr-pool-list">
                    <?php foreach($prizes as $prize) { ?>
                    <div class="nxr-pool-row"><div class="nxr-pool-left"><i class="nxr-rarity-dot rarity-<?php echo htmlspecialchars($prize['rarity'],ENT_QUOTES,'UTF-8'); ?>"></i><div><b><?php echo htmlspecialchars($prize['name'],ENT_QUOTES,'UTF-8'); ?></b><small><?php echo htmlspecialchars($rarityLabels[$prize['rarity']]??$prize['rarity'],ENT_QUOTES,'UTF-8'); ?></small></div></div><?php if(!empty($settings['show_odds'])) { ?><strong><?php echo number_format((float)$prize['probability'],2); ?>%</strong><?php } ?></div>
                    <?php } ?>
                </div>
            </section>
        </aside>
        <?php } ?>
    </section>

    <?php if(!empty($settings['show_exchange']) && !empty($settings['progression_enabled'])) { ?>
    <section class="nxr-exchange-panel" id="nxrFragmentExchange">
        <div class="nxr-exchange-head">
            <div>
                <span class="nxr-section-label">PROGRESIÓN · CANJE</span>
                <h2><?php echo htmlspecialchars($settings['exchange_title'],ENT_QUOTES,'UTF-8'); ?></h2>
                <p><?php echo htmlspecialchars($settings['exchange_description'],ENT_QUOTES,'UTF-8'); ?></p>
            </div>
            <div class="nxr-exchange-balance">
                <div class="nxr-exchange-balance-icon" aria-hidden="true"><img src="<?php echo htmlspecialchars($fragmentIconUrl,ENT_QUOTES,'UTF-8'); ?>" alt=""></div>
                <div class="nxr-exchange-balance-copy">
                    <span>DISPONIBLE</span>
                    <strong><?php echo number_format((int)$progressSnapshot['fragments']); ?></strong>
                    <small><?php echo !empty($settings['exchange_enabled'])?'Catálogo activo':'Canje pausado por el staff'; ?></small>
                </div>
            </div>
        </div>

        <?php if(!$exchangeCards) { ?>
            <div class="nxr-exchange-empty"><span>CATÁLOGO EN PREPARACIÓN</span><p>Tu saldo de Fragmentos permanece registrado. Las recompensas aparecerán aquí cuando el staff publique el catálogo de este reino.</p></div>
        <?php } else { ?>
        <div class="nxr-exchange-grid">
            <?php foreach($exchangeCards as $card) { $reward=$card['reward'];
                $type=(string)$reward['reward_type'];
                $canRedeem=!empty($settings['exchange_enabled']) && !empty($card['available']) && !empty($card['can_afford']);
                $disabledReason='';
                if(empty($settings['exchange_enabled'])) $disabledReason='Canje pausado';
                elseif(empty($card['available'])) $disabledReason=($card['global_remaining']!==null && (int)$card['global_remaining']===0)?'Stock agotado':'Límite de cuenta alcanzado';
                elseif(empty($card['can_afford'])) $disabledReason='Te faltan '.number_format(max(0,(int)$reward['fragment_cost']-(int)$progressSnapshot['fragments'])).' fragmentos';
            ?>
            <article class="nxr-exchange-card type-<?php echo htmlspecialchars($type,ENT_QUOTES,'UTF-8'); ?><?php echo $canRedeem?'':' is-locked'; ?>">
                <div class="nxr-exchange-visual">
                    <?php if(!empty($card['custom_visual_url'])) { ?><img src="<?php echo htmlspecialchars($card['custom_visual_url'],ENT_QUOTES,'UTF-8'); ?>" alt="<?php echo htmlspecialchars($reward['name'],ENT_QUOTES,'UTF-8'); ?>"><?php }
                    elseif($type==='itemshop' && is_array($card['visual']) && !empty($card['visual']['url'])) { ?><img src="<?php echo htmlspecialchars($card['visual']['url'],ENT_QUOTES,'UTF-8'); ?>" alt="<?php echo htmlspecialchars($reward['name'],ENT_QUOTES,'UTF-8'); ?>"><?php }
                    elseif($type==='credits') { ?><img class="nxr-exchange-fallback-credit" src="<?php echo htmlspecialchars($wcCoinIconUrl,ENT_QUOTES,'UTF-8'); ?>" alt="Moneda WC">
                    <?php } elseif($type==='free_spins') { ?><img class="nxr-exchange-fallback-fragment" src="<?php echo htmlspecialchars($fragmentIconUrl,ENT_QUOTES,'UTF-8'); ?>" alt="Fragmento NXR">
                    <?php } elseif($type==='manual') { ?><span>STAFF</span><?php } ?>
                </div>
                <div class="nxr-exchange-card-body">
                    <div class="nxr-exchange-card-meta"><span><?php echo $type==='credits'?'SALDO':($type==='free_spins'?'GIROS':($type==='itemshop'?'ARSENAL':'ENTREGA')); ?></span><?php if($card['global_remaining']!==null){ ?><b><?php echo number_format((int)$card['global_remaining']); ?> disponibles</b><?php } else { ?><b>Stock abierto</b><?php } ?></div>
                    <h3><?php echo htmlspecialchars($reward['name'],ENT_QUOTES,'UTF-8'); ?></h3>
                    <p><?php echo trim((string)$reward['description'])!==''?htmlspecialchars($reward['description'],ENT_QUOTES,'UTF-8'):'Recompensa disponible mediante progresión de la Ruleta Nexora.'; ?></p>
                    <div class="nxr-exchange-delivery"><span>RECIBES</span><strong><?php echo htmlspecialchars($card['delivery'],ENT_QUOTES,'UTF-8'); ?></strong></div>
                    <?php if($card['account_remaining']!==null){ ?><small class="nxr-exchange-limit">Tu cuenta: <?php echo number_format((int)$card['account_remaining']); ?> canje<?php echo (int)$card['account_remaining']===1?'':'s'; ?> restante<?php echo (int)$card['account_remaining']===1?'':'s'; ?></small><?php } ?>
                </div>
                <div class="nxr-exchange-card-footer">
                    <div class="nxr-exchange-price"><small>COSTO</small><strong><span class="nxr-value-with-icon"><?php echo number_format((int)$reward['fragment_cost']); ?><?php echo nxrFragmentIconHtml($fragmentIconUrl,'nxr-fragment-inline'); ?></span></strong></div>
                    <form method="post" class="nxr-exchange-form">
                        <input type="hidden" name="roulette_action" value="redeem_fragment">
                        <input type="hidden" name="exchange_reward_id" value="<?php echo (int)$reward['id']; ?>">
                        <input type="hidden" name="exchange_request_token" value="<?php echo htmlspecialchars($exchangeToken,ENT_QUOTES,'UTF-8'); ?>">
                        <button type="submit" <?php echo $canRedeem?'':'disabled'; ?> onclick="return confirm('¿Canjear <?php echo htmlspecialchars(addslashes($reward['name']),ENT_QUOTES,'UTF-8'); ?> por <?php echo number_format((int)$reward['fragment_cost']); ?> Fragmentos NXR?');">
                            <?php echo $canRedeem?'CANJEAR':htmlspecialchars($disabledReason,ENT_QUOTES,'UTF-8'); ?>
                        </button>
                    </form>
                </div>
            </article>
            <?php } ?>
        </div>
        <?php } ?>

        <?php if($exchangeHistory) { ?>
        <div class="nxr-exchange-history">
            <div class="nxr-exchange-history-head"><div><span class="nxr-section-label">TRAZABILIDAD</span><h3>Tus últimos canjes</h3></div><small>Los canjes reservados permanecen asociados a tu cuenta</small></div>
            <div class="nxr-exchange-history-list">
                <?php foreach($exchangeHistory as $row) { $status=(string)$row['status']; ?>
                <div class="nxr-exchange-history-row">
                    <div class="nxr-exchange-history-main"><span class="nxr-exchange-history-id">#<?php echo (int)$row['id']; ?></span><div><strong><?php echo htmlspecialchars($row['reward_name'],ENT_QUOTES,'UTF-8'); ?></strong><small>-<?php echo number_format((int)$row['fragment_cost']); ?> Fragmentos NXR · <?php echo htmlspecialchars((string)$row['created_at'],ENT_QUOTES,'UTF-8'); ?></small></div></div>
                    <div class="nxr-exchange-history-state">
                        <?php if($status==='pending_item') { ?>
                            <form method="post">
                                <input type="hidden" name="roulette_action" value="claim_exchange_item">
                                <input type="hidden" name="claim_exchange_id" value="<?php echo (int)$row['id']; ?>">
                                <input type="hidden" name="exchange_request_token" value="<?php echo htmlspecialchars($exchangeToken,ENT_QUOTES,'UTF-8'); ?>">
                                <button type="submit" class="nxr-claim-button">Reclamar al baúl</button>
                            </form>
                        <?php } elseif($status==='pending_manual') { ?><span class="nxr-status-pill is-waiting">Pendiente de staff</span>
                        <?php } elseif($status==='claimed'||$status==='manual_delivered') { ?><span class="nxr-status-pill is-done">Entregado</span>
                        <?php } else { ?><span class="nxr-status-pill is-done">Acreditado</span><?php } ?>
                    </div>
                </div>
                <?php } ?>
            </div>
        </div>
        <?php } ?>
        <div class="nxr-exchange-footnote"><strong>Protección de canje:</strong> confirmar consume los Fragmentos una sola vez y crea una referencia auditable. Los ítems de Arsenal pueden requerir que la cuenta esté desconectada para escribir de forma segura en el baúl.</div>
    </section>
    <?php } ?>

    <?php if(!empty($settings['show_history'])) { ?>
    <section class="nxr-history-panel">
        <div class="nxr-panel-head nxr-panel-head--history"><div><span class="nxr-section-label">CUENTA</span><h2>Trazabilidad de la cuenta</h2></div><small>Últimos 20 movimientos registrados</small></div>
        <?php if(!$history) { ?><p class="nxr-empty">Tu historial aparecerá desde el primer giro.</p><?php } else { ?>
        <div class="nxr-history-list">
            <?php foreach($history as $row) { ?>
            <div class="nxr-history-item"><div class="nxr-history-main"><span class="nxr-history-id">#<?php echo (int)$row['id']; ?></span><i class="nxr-rarity-dot rarity-<?php echo htmlspecialchars($row['rarity'],ENT_QUOTES,'UTF-8'); ?>"></i><div class="nxr-history-copy"><strong><?php echo htmlspecialchars($row['prize_name'],ENT_QUOTES,'UTF-8'); ?></strong><small><?php echo htmlspecialchars($rarityLabels[$row['rarity']]??$row['rarity'],ENT_QUOTES,'UTF-8'); ?> · <?php echo htmlspecialchars((string)$row['created_at'],ENT_QUOTES,'UTF-8'); ?><?php echo isset($row['fragments_earned']) && (int)$row['fragments_earned']>0?' · +'.number_format((int)$row['fragments_earned']).' Fragmentos NXR':''; ?></small></div></div><div class="nxr-history-action">
                <?php if($row['status']==='pending_item') { ?><form method="post"><button type="submit" name="claim_spin_id" value="<?php echo (int)$row['id']; ?>" class="nxr-claim-button">Reclamar al baúl</button></form>
                <?php } elseif($row['status']==='pending_manual') { ?><span class="nxr-status-pill is-waiting">Pendiente de staff</span>
                <?php } elseif($row['status']==='claimed'||$row['status']==='manual_delivered') { ?><span class="nxr-status-pill is-done">Entregado</span>
                <?php } else { ?><span class="nxr-status-pill is-done">Acreditado</span><?php } ?>
            </div></div>
            <?php } ?>
        </div>
        <?php } ?>
    </section>
    <?php } ?>

    <?php if(!empty($settings['show_recent_winners'])) { ?>
    <section class="nxr-community-panel" id="nxrNetworkActivity">
        <div class="nxr-panel-head nxr-panel-head--history">
            <div><span class="nxr-section-label">RED</span><h2>Actividad reciente</h2></div>
            <small>La comunidad ve apodos públicos; el ID de cuenta nunca se muestra aquí.</small>
        </div>

        <div class="nxr-network-identity">
            <div class="nxr-network-identity-copy">
                <span class="nxr-network-eyebrow">TU IDENTIDAD EN LA RED</span>
                <strong><?php echo htmlspecialchars(is_array($networkProfile)?(string)$networkProfile['display_name']:'Aún no has elegido un apodo',ENT_QUOTES,'UTF-8'); ?></strong>
                <p>Elige cómo quieres que te reconozca la comunidad cuando aparezcas entre los ganadores. Tu usuario de acceso permanece privado.</p>
            </div>
            <?php if(is_array($networkProfile) && !empty($networkProfile['locked'])) { ?>
                <div class="nxr-network-lock"><span>APODO MODERADO</span><b><?php echo htmlspecialchars((string)$networkProfile['display_name'],ENT_QUOTES,'UTF-8'); ?></b><small>El staff bloqueó cambios desde la cuenta. Contacta soporte si necesitas una revisión.</small></div>
            <?php } else { ?>
                <form method="post" class="nxr-network-form" autocomplete="off">
                    <input type="hidden" name="roulette_action" value="save_public_nickname">
                    <input type="hidden" name="social_request_token" value="<?php echo htmlspecialchars($socialToken,ENT_QUOTES,'UTF-8'); ?>">
                    <label for="nxrPublicNickname">Apodo público</label>
                    <div class="nxr-network-form-row">
                        <input id="nxrPublicNickname" name="public_nickname" maxlength="24" minlength="3" required value="<?php echo htmlspecialchars(is_array($networkProfile)?(string)$networkProfile['display_name']:'',ENT_QUOTES,'UTF-8'); ?>" placeholder="Ej: Asterion">
                        <button type="submit">GUARDAR APODO</button>
                    </div>
                    <small>3–24 caracteres. Letras, números, espacios, guion y guion bajo. Los apodos están sujetos a moderación.</small>
                </form>
            <?php } ?>
        </div>

        <?php if(!$recent) { ?>
        <div class="nxr-network-empty"><strong>La red todavía está en silencio.</strong><span>Cuando existan nuevos giros, los ganadores aparecerán aquí por su apodo público.</span></div>
        <?php } else { ?>
        <div class="nxr-community-list nxr-community-list--winners">
            <?php foreach($recent as $row) {
                $displayName=trim((string)($row['display_name']??''));
                if($displayName==='') $displayName='Jugador Nexora';
                $initial=mb_strtoupper(mb_substr($displayName,0,1,'UTF-8'),'UTF-8');
                $rarityLabel=(string)($rarityLabels[$row['rarity']]??$row['rarity']);
            ?>
            <div class="nxr-community-item nxr-community-winner rarity-<?php echo htmlspecialchars($row['rarity'],ENT_QUOTES,'UTF-8'); ?>">
                <div class="nxr-community-avatar" aria-hidden="true"><?php echo htmlspecialchars($initial,ENT_QUOTES,'UTF-8'); ?></div>
                <div class="nxr-community-copy">
                    <strong><?php echo htmlspecialchars($displayName,ENT_QUOTES,'UTF-8'); ?></strong>
                    <span>obtuvo <b><?php echo htmlspecialchars($row['prize_name'],ENT_QUOTES,'UTF-8'); ?></b></span>
                </div>
                <div class="nxr-community-rarity"><i class="nxr-rarity-dot rarity-<?php echo htmlspecialchars($row['rarity'],ENT_QUOTES,'UTF-8'); ?>"></i><span><?php echo htmlspecialchars($rarityLabel,ENT_QUOTES,'UTF-8'); ?></span></div>
            </div>
            <?php } ?>
        </div>
        <?php } ?>
    </section>
    <?php } ?>
    <?php if(!empty($poolExperience['show_probability_modal'])) { ?>
    <div id="nxrOddsModal" class="nxr-odds-modal" aria-hidden="true">
        <div class="nxr-odds-backdrop" data-nxr-odds-close></div>
        <div class="nxr-odds-dialog" role="dialog" aria-modal="true" aria-labelledby="nxrOddsTitle">
            <button type="button" class="nxr-odds-close" data-nxr-odds-close aria-label="Cerrar">×</button>
            <span class="nxr-section-label">TRANSPARENCIA DEL MOTOR</span><h2 id="nxrOddsTitle">Probabilidades reales</h2><p>Los sectores visuales son simétricos. Estos porcentajes son los pesos reales del motor para el pool activo.</p>
            <div class="nxr-odds-grid">
                <?php foreach($segmentData as $seg){ ?>
                <article class="nxr-odds-entry rarity-<?php echo htmlspecialchars($seg['rarity'],ENT_QUOTES,'UTF-8'); ?>"><div class="nxr-odds-entry-icon"><?php if($seg['icon_url']!==''){ ?><img src="<?php echo htmlspecialchars($seg['icon_url'],ENT_QUOTES,'UTF-8'); ?>" alt=""><?php } else { ?><span>◆</span><?php } ?></div><div><strong><?php echo htmlspecialchars($seg['name'],ENT_QUOTES,'UTF-8'); ?></strong><span><?php echo htmlspecialchars($seg['rarity_label'],ENT_QUOTES,'UTF-8'); ?> · <?php echo htmlspecialchars($seg['description'],ENT_QUOTES,'UTF-8'); ?></span></div><b><?php echo number_format((float)$seg['probability'],2); ?>%</b></article>
                <?php } ?>
            </div>
        </div>
    </div>
    <?php } ?>
</div>
<script>
window.NexoraRouletteData=<?php echo json_encode(array(
    'segments'=>$segmentData,
    'resultPrizeId'=>$spinResult?(int)$spinResult['prize']['id']:0,
    'result'=>$resultData,
    'walletLabel'=>$walletLabel,
    'spinCost'=>(int)$settings['spin_cost'],
    'freeSpins'=>(int)$state['free_spins'],
    'totalSpins'=>(int)$state['total_spins'],
    'pityCurrent'=>$pityCurrent,
    'pityThreshold'=>$pityThreshold,
    'rarityLabels'=>$rarityLabels,
    'canSpin'=>$canSpin,
    'spinCtaLabel'=>$settings['spin_cta_label'],
    'spinDurationMs'=>(int)$settings['spin_duration_ms'],
    'turnsMin'=>(int)$settings['turns_min'],
    'turnsMax'=>(int)$settings['turns_max'],
    'segmentGap'=>(int)$settings['segment_gap'],
    'segmentPalette'=>$settings['segment_palette'],
    'showSegmentLabels'=>!empty($settings['show_segment_labels']),
    'pointerBounce'=>!empty($settings['pointer_bounce']),
    'winnerGlow'=>!empty($settings['winner_glow']),
    'dimNonWinners'=>!empty($settings['dim_non_winners']),
    'landingPulse'=>!empty($settings['landing_pulse']),
    'soundEnabled'=>!empty($settings['sound_enabled']),
    'soundVolume'=>(int)$settings['sound_volume'],
    'soundProfile'=>(string)($settings['sound_profile']??'nexora'),
    'soundIntensity'=>(int)($settings['sound_intensity']??70),
    'soundSpinStart'=>!empty($settings['sound_spin_start']),
    'soundLanding'=>!empty($settings['sound_landing']),
    'soundWc'=>!empty($settings['sound_wc']),
    'soundFragments'=>!empty($settings['sound_fragments']),
    'soundReentry'=>!empty($settings['sound_reentry']),
    'soundBaseUrl'=>$soundBaseUrl,
    'segmentTicks'=>!empty($settings['segment_ticks']),
    'rarityStinger'=>!empty($settings['rarity_stinger']),
    'showSegmentIcons'=>!empty($settings['show_segment_icons']),
    'premiumReveal'=>!empty($settings['premium_reveal']),
    'revealDelayMs'=>(int)$settings['reveal_delay_ms'],
    'progressionEnabled'=>!empty($settings['progression_enabled']),
    'fragments'=>(int)$progressSnapshot['fragments'],
    'fragmentIconUrl'=>$fragmentIconUrl,
    'creditsIconUrl'=>$wcCoinIconUrl,
    'spinModeDefault'=>(string)($poolExperience['default_spin_mode']??'cinematic'),
    'quickSpinMs'=>(int)($poolExperience['quick_spin_ms']??1800),
    'showProbabilityModal'=>!empty($poolExperience['show_probability_modal']),
    'campaignTitle'=>(string)($poolExperience['campaign_title']??''),
    'campaignStartsAt'=>(string)($poolExperience['campaign_starts_at']??''),
    'campaignEndsAt'=>(string)($poolExperience['campaign_ends_at']??''),
    'campaignState'=>(string)($poolExperience['campaign_state']??'active'),
    'nextMilestoneSpins'=>$nextMilestone?(int)$nextMilestone['spins']:0,
    'milestoneProgressPct'=>(float)$milestoneProgressPct,
    'accentColor'=>$settings['accent_color'],
    'accentSoftColor'=>$settings['accent_soft_color'],
    'secondaryColor'=>$settings['secondary_color'],
    'panelColor'=>$settings['panel_color'],
    'backgroundColor'=>$settings['background_color'],
),JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
</script>
<noscript><style>.nxr-result-card.is-pending-reveal{opacity:1!important;visibility:visible!important;transform:none!important;max-height:none!important}</style></noscript>
<script src="<?php echo htmlspecialchars(__PATH_TEMPLATE_JS__.'nexora-roulette.js?v=1.8.1',ENT_QUOTES,'UTF-8'); ?>"></script>
