744 lines
18 KiB
Vue
744 lines
18 KiB
Vue
<script setup lang="ts">
|
|
import { ref, computed, watch, onUnmounted } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import api from '../../api';
|
|
import { usePlayerProfile } from '../../composables/usePlayerProfile';
|
|
import { formatMoney, parseAmount } from '../../utils/localeDisplay';
|
|
import { teamFlagUrl } from '../../utils/teamFlag';
|
|
import BetSuccessOverlay from '../BetSuccessOverlay.vue';
|
|
import ConfirmDialog from '../ConfirmDialog.vue';
|
|
import { buildBetPlaceConfirmMessage } from '../../utils/betPlaceConfirmMessage';
|
|
|
|
export interface OutrightPick {
|
|
selectionId: string;
|
|
oddsVersion: string;
|
|
teamCode: string;
|
|
teamName: string;
|
|
odds: string;
|
|
eventTitle: string;
|
|
}
|
|
|
|
interface SelectionOddsRow {
|
|
id: string;
|
|
odds: string;
|
|
oddsVersion: string;
|
|
status: string;
|
|
marketStatus: string;
|
|
marketShowOnPlayer: boolean;
|
|
matchStatus: string;
|
|
}
|
|
|
|
type OddsDelta = {
|
|
oldOdds: number;
|
|
newOdds: number;
|
|
newVersion: string;
|
|
suspended: boolean;
|
|
};
|
|
|
|
const props = defineProps<{
|
|
open: boolean;
|
|
pick: OutrightPick | null;
|
|
}>();
|
|
|
|
const emit = defineEmits<{ close: [] }>();
|
|
|
|
const { t, locale } = useI18n();
|
|
const { refreshProfile } = usePlayerProfile();
|
|
|
|
const step = ref<'form' | 'success'>('form');
|
|
const stake = ref(1);
|
|
const loading = ref(false);
|
|
const error = ref('');
|
|
const balance = ref(0);
|
|
const successBalance = ref(0);
|
|
const successStake = ref(0);
|
|
const showSuccess = ref(false);
|
|
const showPlaceConfirm = ref(false);
|
|
const placeConfirmMessage = ref('');
|
|
const currentOdds = ref('');
|
|
const currentOddsVersion = ref('');
|
|
const oddsDelta = ref<OddsDelta | null>(null);
|
|
const ODDS_POLL_MS = 5000;
|
|
let oddsPollTimer: ReturnType<typeof setInterval> | null = null;
|
|
|
|
const flagUrl = computed(() =>
|
|
props.pick ? teamFlagUrl(props.pick.teamCode, props.pick.teamName) : null,
|
|
);
|
|
|
|
const balanceText = computed(() => formatMoney(balance.value, locale.value));
|
|
|
|
const effectiveOdds = computed(() => {
|
|
if (oddsDelta.value && !oddsDelta.value.suspended) return oddsDelta.value.newOdds;
|
|
const n = parseFloat(currentOdds.value);
|
|
return Number.isFinite(n) ? n : 0;
|
|
});
|
|
|
|
const oddsNum = computed(() => effectiveOdds.value);
|
|
|
|
const estReturn = computed(() => {
|
|
const s = Number(stake.value);
|
|
if (!s || s <= 0 || !oddsNum.value) return 0;
|
|
return s * oddsNum.value;
|
|
});
|
|
|
|
const estReturnText = computed(() => formatMoney(estReturn.value, locale.value));
|
|
|
|
const hasPendingOddsChanges = computed(() => Boolean(oddsDelta.value && !oddsDelta.value.suspended));
|
|
const hasSuspendedSelection = computed(() => Boolean(oddsDelta.value?.suspended));
|
|
|
|
const oddsWarningText = computed(() => {
|
|
if (hasSuspendedSelection.value) return t('bet.odds_suspended');
|
|
if (hasPendingOddsChanges.value) return t('bet.odds_changed');
|
|
return '';
|
|
});
|
|
|
|
const submitButtonLabel = computed(() => {
|
|
if (loading.value) return t('bet.placing');
|
|
if (hasPendingOddsChanges.value) return t('bet.accept_changes_place');
|
|
return t('bet.place_bet_short');
|
|
});
|
|
|
|
function syncPickState() {
|
|
if (!props.pick) return;
|
|
currentOdds.value = props.pick.odds;
|
|
currentOddsVersion.value = props.pick.oddsVersion;
|
|
oddsDelta.value = null;
|
|
}
|
|
|
|
function acceptPendingOdds() {
|
|
if (!oddsDelta.value || oddsDelta.value.suspended) return;
|
|
currentOdds.value = oddsDelta.value.newOdds.toFixed(2);
|
|
currentOddsVersion.value = oddsDelta.value.newVersion;
|
|
oddsDelta.value = null;
|
|
}
|
|
|
|
function stopOddsPolling() {
|
|
if (oddsPollTimer) {
|
|
clearInterval(oddsPollTimer);
|
|
oddsPollTimer = null;
|
|
}
|
|
}
|
|
|
|
async function pollSelectionOdds() {
|
|
if (!props.pick || !props.open || step.value !== 'form') return;
|
|
|
|
try {
|
|
const { data } = await api.get('/player/selections/odds', {
|
|
params: { ids: props.pick.selectionId },
|
|
});
|
|
const row: SelectionOddsRow | undefined = data.data?.items?.[0];
|
|
if (!row) return;
|
|
|
|
const suspended =
|
|
row.status !== 'OPEN' ||
|
|
row.marketStatus !== 'OPEN' ||
|
|
row.marketShowOnPlayer === false ||
|
|
row.matchStatus !== 'PUBLISHED';
|
|
const newOdds = parseFloat(row.odds);
|
|
const versionChanged = row.oddsVersion !== currentOddsVersion.value;
|
|
const baseOdds = parseFloat(currentOdds.value);
|
|
const oddsChanged = Number.isFinite(newOdds) && Math.abs(newOdds - baseOdds) > 0.0001;
|
|
|
|
if (suspended || versionChanged || oddsChanged) {
|
|
oddsDelta.value = {
|
|
oldOdds: oddsDelta.value?.oldOdds ?? baseOdds,
|
|
newOdds: Number.isFinite(newOdds) ? newOdds : baseOdds,
|
|
newVersion: row.oddsVersion,
|
|
suspended,
|
|
};
|
|
} else {
|
|
oddsDelta.value = null;
|
|
}
|
|
} catch {
|
|
/* silent retry on next tick */
|
|
}
|
|
}
|
|
|
|
function startOddsPolling() {
|
|
stopOddsPolling();
|
|
void pollSelectionOdds();
|
|
oddsPollTimer = setInterval(() => {
|
|
void pollSelectionOdds();
|
|
}, ODDS_POLL_MS);
|
|
}
|
|
|
|
watch(
|
|
() => props.open,
|
|
async (v) => {
|
|
if (!v) {
|
|
stopOddsPolling();
|
|
oddsDelta.value = null;
|
|
return;
|
|
}
|
|
step.value = 'form';
|
|
stake.value = 1;
|
|
error.value = '';
|
|
syncPickState();
|
|
try {
|
|
const { data } = await api.get('/player/profile');
|
|
balance.value = parseAmount(data.data?.wallet?.availableBalance);
|
|
} catch {
|
|
balance.value = 0;
|
|
}
|
|
startOddsPolling();
|
|
},
|
|
);
|
|
|
|
watch(
|
|
() => props.pick?.selectionId,
|
|
() => {
|
|
if (!props.open) return;
|
|
syncPickState();
|
|
if (props.open) void pollSelectionOdds();
|
|
},
|
|
);
|
|
|
|
onUnmounted(() => {
|
|
stopOddsPolling();
|
|
});
|
|
|
|
function close() {
|
|
emit('close');
|
|
}
|
|
|
|
function genRequestId() {
|
|
return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
}
|
|
|
|
function setStake(amount: number) {
|
|
stake.value = Math.max(0.01, Math.round(amount * 100) / 100);
|
|
}
|
|
|
|
function setMaxStake() {
|
|
if (balance.value > 0) setStake(balance.value);
|
|
}
|
|
|
|
function validateSubmit(): boolean {
|
|
if (!props.pick || stake.value <= 0) return false;
|
|
if (stake.value > balance.value) {
|
|
error.value = t('bet.outright_insufficient');
|
|
return false;
|
|
}
|
|
if (hasSuspendedSelection.value) {
|
|
error.value = t('bet.odds_suspended');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function onSubmitClick() {
|
|
if (!props.pick) return;
|
|
if (!validateSubmit()) return;
|
|
if (hasPendingOddsChanges.value) {
|
|
acceptPendingOdds();
|
|
}
|
|
placeConfirmMessage.value = buildBetPlaceConfirmMessage(t, {
|
|
mode: 'single',
|
|
items: [
|
|
{
|
|
selectionId: props.pick.selectionId,
|
|
oddsVersion: currentOddsVersion.value,
|
|
matchId: '',
|
|
matchName: props.pick.eventTitle,
|
|
marketId: '',
|
|
marketName: props.pick.eventTitle,
|
|
selectionName: `${props.pick.teamName} - ${props.pick.eventTitle}`,
|
|
odds: oddsNum.value,
|
|
marketType: 'OUTRIGHT',
|
|
lineValue: null,
|
|
allowSingle: true,
|
|
allowParlay: false,
|
|
},
|
|
],
|
|
totalStake: stake.value,
|
|
totalReturn: estReturn.value,
|
|
formatMoney: (amount) => formatMoney(amount, locale.value),
|
|
getStake: () => stake.value,
|
|
getOdds: () => oddsNum.value,
|
|
});
|
|
showPlaceConfirm.value = true;
|
|
}
|
|
|
|
async function executeSubmit() {
|
|
if (!props.pick || stake.value <= 0) return;
|
|
|
|
loading.value = true;
|
|
error.value = '';
|
|
try {
|
|
await api.post('/player/bets/single', {
|
|
selectionId: props.pick.selectionId,
|
|
oddsVersion: currentOddsVersion.value,
|
|
stake: stake.value,
|
|
requestId: genRequestId(),
|
|
});
|
|
successStake.value = stake.value;
|
|
successBalance.value = balance.value - stake.value;
|
|
balance.value = successBalance.value;
|
|
step.value = 'success';
|
|
showSuccess.value = true;
|
|
void refreshProfile();
|
|
} catch (e: unknown) {
|
|
const err = e as { response?: { data?: { error?: string; code?: string } } };
|
|
if (err.response?.data?.code === 'ODDS_CHANGED') {
|
|
await pollSelectionOdds();
|
|
error.value = t('bet.odds_changed');
|
|
return;
|
|
}
|
|
error.value = err.response?.data?.error || t('bet.outright_bet_failed');
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function confirmSubmit() {
|
|
showPlaceConfirm.value = false;
|
|
await executeSubmit();
|
|
}
|
|
|
|
function formatOdds(odds: string) {
|
|
const n = parseFloat(odds);
|
|
return Number.isFinite(n) ? n.toFixed(2) : odds;
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="open && pick" class="overlay" @click.self="close">
|
|
<div class="modal" role="dialog" aria-modal="true">
|
|
<button type="button" class="close-x" :aria-label="t('bet.cancel')" @click="close">✕</button>
|
|
|
|
<template v-if="step === 'form'">
|
|
<p class="hint">{{ t('bet.outright_enter_stake') }}</p>
|
|
|
|
<div class="hero">
|
|
<img v-if="flagUrl" :src="flagUrl" alt="" class="flag" />
|
|
<p class="team">{{ pick.teamName }}</p>
|
|
<span
|
|
class="odds-badge"
|
|
:class="{
|
|
'odds-badge--up': oddsDelta && !oddsDelta.suspended && oddsDelta.newOdds >= oddsDelta.oldOdds,
|
|
'odds-badge--down': oddsDelta && !oddsDelta.suspended && oddsDelta.newOdds < oddsDelta.oldOdds,
|
|
'odds-badge--suspended': oddsDelta?.suspended,
|
|
}"
|
|
>
|
|
<template v-if="oddsDelta && !oddsDelta.suspended">
|
|
@ {{ oddsDelta.oldOdds.toFixed(2) }} -> {{ oddsDelta.newOdds.toFixed(2) }}
|
|
</template>
|
|
<template v-else>
|
|
@ {{ formatOdds(currentOdds || pick.odds) }}
|
|
</template>
|
|
</span>
|
|
</div>
|
|
|
|
<p class="event-title">{{ pick.eventTitle }}</p>
|
|
|
|
<p v-if="oddsWarningText" class="odds-warning">{{ oddsWarningText }}</p>
|
|
|
|
<div class="balance-row">
|
|
<span class="balance-label">{{ t('bet.outright_balance') }}</span>
|
|
<span class="balance-value">{{ balanceText }}</span>
|
|
</div>
|
|
|
|
<label class="stake-label">{{ t('bet.stake_label') }}</label>
|
|
<input
|
|
v-model.number="stake"
|
|
type="number"
|
|
class="stake-input"
|
|
min="0.01"
|
|
step="0.01"
|
|
inputmode="decimal"
|
|
:placeholder="t('bet.stake_placeholder')"
|
|
/>
|
|
|
|
<div class="quick-stakes">
|
|
<button type="button" class="chip" @click="setStake(50)">50</button>
|
|
<button type="button" class="chip" @click="setStake(100)">100</button>
|
|
<button type="button" class="chip" @click="setStake(500)">500</button>
|
|
<button type="button" class="chip" @click="setMaxStake">{{ t('bet.stake_max') }}</button>
|
|
</div>
|
|
|
|
<p class="est-return">
|
|
{{ t('history.est_return') }}: <span class="est-value">{{ estReturnText }}</span>
|
|
</p>
|
|
|
|
<p v-if="error" class="error">{{ error }}</p>
|
|
|
|
<div class="actions">
|
|
<button type="button" class="btn-cancel" :disabled="loading" @click="close">
|
|
{{ t('bet.cancel') }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="btn-confirm"
|
|
:disabled="loading || stake <= 0 || hasSuspendedSelection"
|
|
@click="onSubmitClick"
|
|
>
|
|
{{ submitButtonLabel }}
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<div class="success-icon">✓</div>
|
|
<h3 class="success-title">{{ t('bet.outright_success') }}</h3>
|
|
|
|
<div class="hero hero--compact">
|
|
<img v-if="flagUrl" :src="flagUrl" alt="" class="flag" />
|
|
<p class="team">{{ pick.teamName }}</p>
|
|
<span class="odds-badge">@ {{ formatOdds(pick.odds) }}</span>
|
|
</div>
|
|
|
|
<p class="event-title">{{ pick.eventTitle }}</p>
|
|
|
|
<div class="summary">
|
|
<div class="summary-row">
|
|
<span>{{ t('bet.outright_stake_amount') }}</span>
|
|
<span>{{ formatMoney(successStake, locale) }}</span>
|
|
</div>
|
|
<div class="summary-row">
|
|
<span>{{ t('bet.outright_balance') }}</span>
|
|
<span class="balance-value">{{ formatMoney(successBalance, locale) }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" class="btn-done" @click="close">
|
|
{{ t('bet.outright_done') }}
|
|
</button>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
<BetSuccessOverlay :show="showSuccess" @done="showSuccess = false" />
|
|
|
|
<ConfirmDialog
|
|
v-model:visible="showPlaceConfirm"
|
|
:title="t('bet.place_confirm_title')"
|
|
:message="placeConfirmMessage"
|
|
:confirm-text="t('bet.place_bet')"
|
|
:cancel-text="t('common.cancel')"
|
|
:loading="loading"
|
|
@confirm="confirmSubmit"
|
|
/>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 200;
|
|
background: rgba(0, 0, 0, 0.72);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 20px;
|
|
backdrop-filter: blur(4px);
|
|
}
|
|
|
|
.modal {
|
|
position: relative;
|
|
width: 100%;
|
|
max-width: 300px;
|
|
background: url('../../assets/images/generated/outright-bet-modal-frame-v2.webp') center / 100% 100% no-repeat;
|
|
border: 0;
|
|
border-radius: 0;
|
|
padding: 30px 24px 24px;
|
|
text-align: center;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.close-x {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
width: 36px;
|
|
height: 36px;
|
|
border: 0;
|
|
border-radius: 0;
|
|
background: url('../../assets/images/generated/modal-close-gold-v1.webp') center / contain no-repeat;
|
|
color: transparent;
|
|
font-size: 0;
|
|
line-height: 1;
|
|
}
|
|
|
|
.close-x:active {
|
|
background-image: url('../../assets/images/generated/modal-close-gold-pressed-v1.webp');
|
|
}
|
|
|
|
.hint {
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
color: var(--text-muted);
|
|
margin-bottom: 12px;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.hero {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.hero--compact {
|
|
margin-top: 4px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.flag {
|
|
width: 48px;
|
|
height: 32px;
|
|
object-fit: cover;
|
|
border-radius: 4px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
|
|
}
|
|
|
|
.team {
|
|
font-size: 20px;
|
|
font-weight: 900;
|
|
color: var(--primary-light);
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
.odds-badge {
|
|
display: inline-block;
|
|
padding: 3px 10px;
|
|
background: rgba(198, 40, 40, 0.85);
|
|
border: 1px solid rgba(255, 120, 120, 0.35);
|
|
color: #fff;
|
|
font-size: 13px;
|
|
font-weight: 800;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.odds-badge--up {
|
|
background: rgba(22, 101, 52, 0.9);
|
|
border-color: rgba(110, 231, 160, 0.35);
|
|
}
|
|
|
|
.odds-badge--down {
|
|
background: rgba(153, 27, 27, 0.92);
|
|
border-color: rgba(255, 139, 139, 0.4);
|
|
}
|
|
|
|
.odds-badge--suspended {
|
|
background: rgba(120, 83, 14, 0.9);
|
|
border-color: rgba(255, 184, 77, 0.35);
|
|
}
|
|
|
|
.odds-warning {
|
|
margin: 0 0 10px;
|
|
padding: 8px 10px;
|
|
border-radius: 6px;
|
|
background: rgba(244, 162, 97, 0.12);
|
|
border: 1px solid rgba(244, 162, 97, 0.28);
|
|
color: var(--primary-light);
|
|
font-size: 12px;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
.event-title {
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
margin-bottom: 12px;
|
|
line-height: 1.4;
|
|
padding: 0 4px;
|
|
}
|
|
|
|
.balance-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 8px 10px;
|
|
margin-bottom: 12px;
|
|
background: rgba(0, 0, 0, 0.35);
|
|
border: 1px solid var(--border);
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.balance-label {
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.balance-value {
|
|
font-size: 14px;
|
|
font-weight: 800;
|
|
color: var(--primary-light);
|
|
}
|
|
|
|
.stake-label {
|
|
display: block;
|
|
text-align: left;
|
|
font-size: 11px;
|
|
color: var(--text-muted);
|
|
font-weight: 600;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.stake-input {
|
|
width: 100%;
|
|
padding: 11px 12px;
|
|
margin-bottom: 8px;
|
|
border-radius: 6px;
|
|
border: 1px solid var(--border);
|
|
background: #0a0a0a;
|
|
color: var(--text);
|
|
font-size: 18px;
|
|
font-weight: 800;
|
|
text-align: center;
|
|
outline: none;
|
|
}
|
|
|
|
.stake-input:focus {
|
|
border-color: var(--border-gold-soft);
|
|
box-shadow: 0 0 0 1px rgba(212, 175, 55, 0.15);
|
|
}
|
|
|
|
.stake-input::placeholder {
|
|
color: #555;
|
|
font-weight: 500;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.quick-stakes {
|
|
display: flex;
|
|
gap: 6px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.chip {
|
|
flex: 1;
|
|
padding: 6px 4px;
|
|
border-radius: 6px;
|
|
border: 1px solid var(--border);
|
|
background: #141414;
|
|
color: var(--text-muted);
|
|
font-size: 11px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.chip:active {
|
|
border-color: var(--border-gold-soft);
|
|
color: var(--primary-light);
|
|
background: rgba(212, 175, 55, 0.08);
|
|
}
|
|
|
|
.est-return {
|
|
font-size: 12px;
|
|
color: var(--text-muted);
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.est-value {
|
|
color: var(--primary-light);
|
|
font-weight: 800;
|
|
}
|
|
|
|
.error {
|
|
color: var(--danger);
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.actions {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1.2fr;
|
|
gap: 8px;
|
|
}
|
|
|
|
.btn-cancel {
|
|
height: 46px;
|
|
padding: 10px 12px;
|
|
border: 0;
|
|
border-radius: 0;
|
|
background: url('../../assets/images/generated/pc-betslip-btn-secondary-v1.webp') center / 100% 100% no-repeat;
|
|
color: var(--text-muted);
|
|
font-size: 14px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.btn-cancel:active {
|
|
background-image: url('../../assets/images/generated/pc-betslip-btn-secondary-pressed-v1.webp');
|
|
}
|
|
|
|
.btn-confirm {
|
|
height: 46px;
|
|
padding: 10px 12px;
|
|
border: 0;
|
|
border-radius: 0;
|
|
background: url('../../assets/images/generated/pc-betslip-btn-primary-v1.webp') center / 100% 100% no-repeat;
|
|
color: #100d04;
|
|
font-size: 14px;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.btn-confirm:active {
|
|
background-image: url('../../assets/images/generated/pc-betslip-btn-primary-pressed-v1.webp');
|
|
}
|
|
|
|
.btn-cancel:disabled,
|
|
.btn-confirm:disabled {
|
|
opacity: 0.45;
|
|
}
|
|
|
|
.success-icon {
|
|
width: 44px;
|
|
height: 44px;
|
|
margin: 0 auto 8px;
|
|
border-radius: 50%;
|
|
border: 2px solid rgba(46, 158, 94, 0.8);
|
|
background: rgba(46, 158, 94, 0.12);
|
|
color: #4ade80;
|
|
font-size: 24px;
|
|
font-weight: 900;
|
|
line-height: 40px;
|
|
}
|
|
|
|
.success-title {
|
|
font-size: 16px;
|
|
font-weight: 800;
|
|
color: var(--primary-light);
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.summary {
|
|
margin: 12px 0 14px;
|
|
padding: 10px;
|
|
background: rgba(0, 0, 0, 0.35);
|
|
border: 1px solid var(--border);
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.summary-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
font-size: 13px;
|
|
color: var(--text-muted);
|
|
padding: 4px 0;
|
|
}
|
|
|
|
.summary-row + .summary-row {
|
|
margin-top: 4px;
|
|
padding-top: 8px;
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
|
|
.btn-done {
|
|
width: 100%;
|
|
height: 46px;
|
|
padding: 11px 12px;
|
|
border: 0;
|
|
border-radius: 0;
|
|
background: url('../../assets/images/generated/pc-betslip-btn-primary-v1.webp') center / 100% 100% no-repeat;
|
|
color: #100d04;
|
|
font-size: 14px;
|
|
font-weight: 800;
|
|
}
|
|
|
|
.btn-done:active {
|
|
background-image: url('../../assets/images/generated/pc-betslip-btn-primary-pressed-v1.webp');
|
|
}
|
|
</style>
|