充值活动/币商

This commit is contained in:
170-carry 2026-04-29 23:08:47 +08:00
parent d19b96059f
commit 1fc21860a2
30 changed files with 3107 additions and 2 deletions

View File

@ -0,0 +1,171 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" />
<title>Recharge Agency</title>
<style>
:root {
--page-width: 512px;
--brown-990: #290e00;
--panel-brown: #5e3513;
--gold-line: #f7dd92;
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
min-height: 100%;
background: var(--brown-990);
font-family:
-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial,
sans-serif;
}
body {
color: #fff7df;
padding-bottom: env(safe-area-inset-bottom);
}
.page {
width: min(100%, var(--page-width));
aspect-ratio: 1080 / 2410;
margin: 0 auto;
overflow: hidden;
background: var(--brown-990);
}
.canvas {
position: relative;
width: 100%;
height: 100%;
background: var(--brown-990);
overflow: hidden;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.hero-scene {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 70.9959%;
overflow: hidden;
-webkit-mask: url("../../assets/recharge-agency-list/mask.svg") 0 0 / 100% 100% no-repeat;
mask: url("../../assets/recharge-agency-list/mask.svg") 0 0 / 100% 100% no-repeat;
}
.hero-layer {
position: absolute;
display: block;
max-width: none;
pointer-events: none;
user-select: none;
object-fit: cover;
}
.hero-layer.top-glow {
left: -16.3889%;
top: -2.9807%;
width: 132.7778%;
height: 45.7043%;
}
.hero-layer.palace {
left: 0;
top: -30.0994%;
width: 100%;
height: 133.2554%;
}
.hero-layer.figure {
left: 0;
top: -12.858%;
width: 100%;
height: 104.0327%;
}
.title-ribbon {
position: absolute;
left: 1.8519%;
top: 56.722%;
width: 96.2037%;
height: 4.6888%;
display: block;
max-width: none;
pointer-events: none;
user-select: none;
}
.content-panel {
position: absolute;
left: 5.3704%;
top: 63.0705%;
width: 89.1667%;
height: 11.4108%;
border: 1px solid var(--gold-line);
border-radius: 2.9076% / 10.1818%;
background: var(--panel-brown);
}
.bottom-frame {
position: absolute;
left: 1.8056%;
top: 91%;
width: 96.1574%;
height: 2.4066%;
display: block;
max-width: none;
pointer-events: none;
user-select: none;
}
</style>
</head>
<body>
<main class="page" aria-labelledby="page-title">
<div class="canvas" data-node-id="220:1781">
<h1 id="page-title" class="sr-only">Recharge Agency</h1>
<div class="hero-scene" data-node-id="220:1782">
<img class="hero-layer top-glow" src="../../assets/recharge-agency-list/top-glow.png" alt="" />
<img class="hero-layer palace" src="../../assets/recharge-agency-list/palace-hall.png" alt="" />
<img class="hero-layer figure" src="../../assets/recharge-agency-list/title-figure.png" alt="" />
</div>
<img class="title-ribbon" src="../../assets/recharge-agency-list/title-ribbon.png" alt="Recharge Agency" />
<section class="content-panel" aria-label="Recharge agency list"></section>
<svg class="bottom-frame" aria-hidden="true" viewBox="0 0 1038.5 58" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 58L9 49V28L34 8H193.5L200 17.5H840.5L845.5 8H1005.5L1031 28.5V49L1038.5 58V25.5L1010 0H840.5L834.5 11.5H204L197 0H30L0 25.5V58Z" fill="url(#bottom-frame-gradient)" />
<defs>
<linearGradient id="bottom-frame-gradient" x1="0" y1="29" x2="1038.5" y2="29" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFCC5A" />
<stop offset="0.1342" stop-color="#FAE47E" />
<stop offset="0.721154" stop-color="#FAE47E" />
<stop offset="1" stop-color="#FFCC5A" />
</linearGradient>
</defs>
</svg>
</div>
</main>
</body>
</html>

View File

@ -0,0 +1,677 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" />
<title>Recharge Reward</title>
<style>
:root {
--scale: 0.4;
--canvas-width: 1080px;
--canvas-height: 3411px;
--page-bg: #290e00;
--gold-text: #f6e0b2;
--asset-root: "../../assets/recharge";
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
min-height: 100%;
background: var(--page-bg);
font-family:
"Source Han Sans SC", "PingFang SC", "Helvetica Neue", Arial, sans-serif;
}
body {
color: var(--gold-text);
padding-bottom: env(safe-area-inset-bottom);
}
.page {
width: calc(var(--canvas-width) * var(--scale));
max-width: 100vw;
height: calc(var(--canvas-height) * var(--scale));
margin: 0 auto;
overflow: hidden;
background: var(--page-bg);
}
.canvas {
position: relative;
width: var(--canvas-width);
height: var(--canvas-height);
transform: scale(var(--scale));
transform-origin: left top;
overflow: hidden;
background: var(--page-bg);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.asset {
position: absolute;
display: block;
max-width: none;
pointer-events: none;
user-select: none;
}
.hero {
position: absolute;
left: 0;
top: -29px;
width: 1080px;
height: 1027px;
overflow: hidden;
}
.hero-bg {
position: absolute;
left: -11px;
top: -158px;
width: 1101px;
height: 1468px;
-webkit-mask-image: linear-gradient(180deg, #000 0%, #000 75%, rgba(0, 0, 0, 0) 100%);
mask-image: linear-gradient(180deg, #000 0%, #000 75%, rgba(0, 0, 0, 0) 100%);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
.hero-bg img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.hero-title {
left: 8px;
top: 64px;
width: 1058px;
height: 790px;
object-fit: cover;
z-index: 1;
}
.price-frame {
position: absolute;
overflow: visible;
}
.price-frame .price-fill {
position: absolute;
left: 1.76%;
right: 1.76%;
top: 6%;
height: 84%;
overflow: hidden;
}
.price-frame .price-fill img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: bottom;
display: block;
}
.price-frame .price-shade {
position: absolute;
left: 1.76%;
right: 1.76%;
top: 29%;
height: 65%;
overflow: hidden;
transform: scaleY(-1);
-webkit-mask-image: url("../../assets/recharge/price-button-mask.png");
mask-image: url("../../assets/recharge/price-button-mask.png");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: 0 -1px;
mask-position: 0 -1px;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.price-frame .price-shade img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: bottom;
display: block;
}
.countdown-frame {
position: absolute;
left: 43px;
top: 836px;
width: 994px;
height: 350px;
background:
linear-gradient(180deg, rgba(84, 27, 7, 0.92), rgba(42, 10, 2, 0.96)) padding-box,
linear-gradient(90deg, #ffe8bc, #a9562b 13%, #ffd59a 49%, #a9562b 87%, #ffe8bc) border-box;
border: 8px solid transparent;
box-shadow:
inset 0 0 0 4px rgba(104, 38, 17, 0.96),
inset 0 0 44px rgba(255, 190, 104, 0.12);
}
.countdown-frame .frame-stretch {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: fill;
display: block;
opacity: 0.74;
}
.countdown-item {
position: absolute;
width: 113px;
height: 177px;
text-align: center;
color: var(--gold-text);
}
.countdown-item img {
position: absolute;
left: 0;
top: 0;
width: 113px;
height: 131px;
display: block;
}
.countdown-value {
position: absolute;
left: 0;
top: 39px;
width: 113px;
font-size: 46px;
line-height: 46px;
font-weight: 500;
}
.countdown-label {
position: absolute;
left: 0;
top: 141px;
width: 113px;
font-size: 28px;
line-height: 36px;
font-weight: 500;
}
.panel {
position: absolute;
left: 15px;
width: 1050px;
pointer-events: none;
}
.panel-edge {
position: absolute;
left: 0;
width: 1050px;
height: 191px;
object-fit: fill;
}
.panel-edge.bottom {
transform: scaleY(-1);
}
.panel-middle {
position: absolute;
left: 15.9px;
width: 1020px;
height: 236px;
object-fit: fill;
}
.profile-backdrop {
position: absolute;
left: 58px;
top: 1279px;
width: 967px;
height: 560px;
overflow: hidden;
}
.profile-backdrop img {
position: absolute;
left: 0;
top: -265px;
width: 967px;
height: 1290px;
object-fit: cover;
opacity: 0.09;
}
.ornate-square {
position: absolute;
pointer-events: none;
user-select: none;
}
.ornate-square .square-fill {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: fill;
}
.ornate-square .corner {
position: absolute;
width: var(--corner-size);
height: var(--corner-size);
object-fit: contain;
}
.ornate-square .corner.tl {
left: calc(var(--corner-size) * -0.04);
top: calc(var(--corner-size) * -0.04);
}
.ornate-square .corner.tr {
right: calc(var(--corner-size) * -0.04);
top: calc(var(--corner-size) * -0.04);
transform: scaleX(-1);
}
.ornate-square .corner.bl {
left: calc(var(--corner-size) * -0.04);
bottom: calc(var(--corner-size) * -0.04);
transform: scaleY(-1);
}
.ornate-square .corner.br {
right: calc(var(--corner-size) * -0.04);
bottom: calc(var(--corner-size) * -0.04);
transform: scale(-1);
}
.ornate-square .center-gem {
position: absolute;
left: 50%;
width: var(--gem-width);
height: var(--gem-height);
transform: translateX(-50%);
object-fit: contain;
}
.ornate-square .center-gem.top {
top: calc(var(--gem-height) * -0.14);
transform: translateX(-50%) scaleY(-1);
}
.ornate-square .center-gem.bottom {
bottom: calc(var(--gem-height) * -0.14);
}
.avatar-crop {
position: absolute;
left: 411px;
top: 1341px;
width: 257px;
height: 257px;
overflow: hidden;
}
.avatar-crop img {
position: absolute;
left: -43px;
top: -22px;
width: 322px;
height: 430px;
object-fit: cover;
}
.avatar-frame {
left: 389px;
top: 1319px;
width: 301px;
height: 301px;
--corner-size: 56px;
--gem-width: 75px;
--gem-height: 45px;
}
.reward-frame-lg {
width: 360px;
height: 360px;
--corner-size: 62px;
--gem-width: 0;
--gem-height: 0;
}
.reward-frame-sm {
width: 240px;
height: 240px;
--corner-size: 42px;
--gem-width: 0;
--gem-height: 0;
}
.section-badge {
width: 340px;
height: 182px;
object-fit: fill;
}
.section-title,
.figure-text {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
color: var(--gold-text);
font-weight: 500;
text-align: center;
white-space: nowrap;
}
.section-title {
width: 340px;
height: 44px;
font-size: 36px;
line-height: 36px;
}
.profile-name {
left: 436px;
top: 1630px;
width: 207px;
height: 36px;
font-size: 36px;
line-height: 36px;
}
.profile-id {
left: 460px;
top: 1676px;
width: 158px;
height: 36px;
font-size: 24px;
line-height: 36px;
}
.profile-total {
left: 307px;
top: 1729px;
width: 464px;
height: 36px;
font-size: 36px;
line-height: 36px;
}
.reward-icon {
position: absolute;
object-fit: contain;
display: block;
pointer-events: none;
user-select: none;
}
.reward-price {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
width: 284px;
height: 100px;
color: var(--gold-text);
font-size: 36px;
line-height: 36px;
font-weight: 500;
text-align: center;
white-space: nowrap;
}
.reward-price span {
position: relative;
z-index: 1;
padding-top: 2px;
}
.reward-price .price-fill,
.reward-price .price-shade {
display: none;
}
.reward-price .price-frame::before {
content: "";
position: absolute;
left: 5px;
right: 5px;
top: 28px;
height: 50px;
border: 5px solid transparent;
background:
linear-gradient(180deg, #2f0b03 0%, #4b1808 55%, #2b0802 100%) padding-box,
linear-gradient(90deg, #fff1c4, #c06b3e 16%, #ffe5aa 50%, #c06b3e 84%, #fff1c4) border-box;
box-shadow:
inset 0 0 0 2px rgba(103, 40, 18, 0.92),
inset 0 0 18px rgba(255, 182, 91, 0.16);
}
.reward-price .price-frame::after {
content: "";
position: absolute;
left: 10px;
right: 10px;
top: 33px;
height: 1px;
background: rgba(255, 234, 181, 0.75);
}
</style>
</head>
<body>
<main class="page" aria-labelledby="page-title">
<div class="canvas" data-node-id="5:692">
<h1 id="page-title" class="sr-only">Recharge Reward</h1>
<div class="hero" data-node-id="5:693">
<div class="hero-bg">
<img src="../../assets/recharge/hero-bg.png" alt="" />
</div>
<img class="asset hero-title" src="../../assets/recharge/hero-title.png" alt="Recharge Reward" />
</div>
<div class="countdown-frame" aria-hidden="true" data-node-id="5:747">
<img class="frame-stretch" src="../../assets/recharge/price-button-fill.png" alt="" />
</div>
<div class="countdown-item" style="left: 185px; top: 926px;" data-node-id="5:748">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-label">Days</div>
</div>
<div class="countdown-item" style="left: 387px; top: 926px;" data-node-id="5:752">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-label">Hours</div>
</div>
<div class="countdown-item" style="left: 588px; top: 926px;" data-node-id="5:756">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-label">Minutes</div>
</div>
<div class="countdown-item" style="left: 787px; top: 926px;" data-node-id="5:760">
<img src="../../assets/recharge/countdown-box.svg" alt="" />
<div class="countdown-value">01</div>
<div class="countdown-label">Seconds</div>
</div>
<div class="profile-backdrop" data-node-id="5:694">
<img src="../../assets/recharge/profile-panel-bg.png" alt="" />
</div>
<section class="panel" style="top: 1223px; height: 658px;" aria-label="Recharge profile" data-node-id="5:697">
<img class="panel-edge" style="top: 0;" src="../../assets/recharge/panel-edge.png" alt="" />
<img class="panel-middle" style="top: 191px;" src="../../assets/recharge/panel-middle.png" alt="" />
<img class="panel-middle" style="top: 316px;" src="../../assets/recharge/panel-middle.png" alt="" />
<img class="panel-edge bottom" style="top: 467px;" src="../../assets/recharge/panel-edge.png" alt="" />
</section>
<div class="avatar-crop" data-node-id="5:703">
<img src="../../assets/recharge/avatar-photo.png" alt="" />
</div>
<div class="ornate-square avatar-frame" aria-hidden="true" data-node-id="5:706">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="center-gem top" src="../../assets/recharge/reward-frame-center.png" alt="" />
<img class="center-gem bottom" src="../../assets/recharge/reward-frame-center.png" alt="" />
</div>
<div class="figure-text profile-name" data-node-id="5:707">nanfangjian</div>
<div class="figure-text profile-id" data-node-id="5:709">ID12345678</div>
<div class="figure-text profile-total" data-node-id="5:708">Accumlated Recharge:5998</div>
<section aria-label="Recharge 100 two rewards" data-node-id="5:710">
<div class="panel" style="top: 1937px; height: 758px;" aria-hidden="true">
<img class="panel-edge" style="top: 0;" src="../../assets/recharge/panel-edge.png" alt="" />
<img class="panel-middle" style="top: 191px;" src="../../assets/recharge/panel-middle.png" alt="" />
<img class="panel-middle" style="top: 316px;" src="../../assets/recharge/panel-middle.png" alt="" />
<img class="panel-middle" style="top: 427px;" src="../../assets/recharge/panel-middle.png" alt="" />
<img class="panel-edge bottom" style="top: 567px;" src="../../assets/recharge/panel-edge.png" alt="" />
</div>
<img class="asset section-badge" style="left: 370px; top: 1891px;" src="../../assets/recharge/section-badge.png" alt="" />
<div class="section-title" style="left: 370px; top: 1960px;" data-node-id="5:718">Recharge $100</div>
<div class="ornate-square reward-frame-lg" style="left: 118px; top: 2088px;" aria-hidden="true">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<div class="ornate-square reward-frame-lg" style="left: 602px; top: 2088px;" aria-hidden="true">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<img class="reward-icon" style="left: 148px; top: 2118px; width: 300px; height: 300px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 632px; top: 2118px; width: 300px; height: 300px;" src="../../assets/recharge/reward-icon.png" alt="" />
<div class="reward-price" style="left: 156px; top: 2458px;" data-node-id="5:725">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
</div>
<div class="reward-price" style="left: 640px; top: 2458px;" data-node-id="5:726">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
</div>
</section>
<section aria-label="Recharge 100 three rewards" data-node-id="5:727">
<div class="panel" style="top: 2751px; height: 618px;" aria-hidden="true">
<img class="panel-edge" style="top: 0;" src="../../assets/recharge/panel-edge.png" alt="" />
<img class="panel-middle" style="top: 191px;" src="../../assets/recharge/panel-middle.png" alt="" />
<img class="panel-middle" style="top: 316px;" src="../../assets/recharge/panel-middle.png" alt="" />
<img class="panel-edge bottom" style="top: 427px;" src="../../assets/recharge/panel-edge.png" alt="" />
</div>
<img class="asset section-badge" style="left: 370px; top: 2705px;" src="../../assets/recharge/section-badge.png" alt="" />
<div class="section-title" style="left: 370px; top: 2774px;" data-node-id="5:734">Recharge $100</div>
<div class="ornate-square reward-frame-sm" style="left: 118px; top: 2902px;" aria-hidden="true">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<div class="ornate-square reward-frame-sm" style="left: 420px; top: 2902px;" aria-hidden="true">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<div class="ornate-square reward-frame-sm" style="left: 722px; top: 2902px;" aria-hidden="true">
<img class="square-fill" src="../../assets/recharge/reward-frame-fill.png" alt="" />
<img class="corner tl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner tr" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner bl" src="../../assets/recharge/reward-frame-corners.png" alt="" />
<img class="corner br" src="../../assets/recharge/reward-frame-corners.png" alt="" />
</div>
<img class="reward-icon" style="left: 138px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 440px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" />
<img class="reward-icon" style="left: 742px; top: 2922px; width: 200px; height: 200px;" src="../../assets/recharge/reward-icon.png" alt="" />
<div class="reward-price" style="left: 96px; top: 3152px;" data-node-id="5:744">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
</div>
<div class="reward-price" style="left: 398px; top: 3152px;" data-node-id="5:745">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
</div>
<div class="reward-price" style="left: 700px; top: 3152px;" data-node-id="5:746">
<div class="price-frame" style="left: 0; top: 0; width: 284px; height: 100px;" aria-hidden="true">
<div class="price-fill"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
<div class="price-shade"><img src="../../assets/recharge/price-button-fill.png" alt="" /></div>
</div>
<span>$100</span>
</div>
</section>
</div>
</main>
<script>
window.__H5_ROUTE_PATH__ = "/activity/recharge";
(function () {
var root = document.documentElement;
var maxWidth = 432;
var canvasWidth = 1080;
function updateScale() {
var width = Math.min(window.innerWidth || maxWidth, maxWidth);
root.style.setProperty("--scale", String(width / canvasWidth));
}
updateScale();
window.addEventListener("resize", updateScale, { passive: true });
window.addEventListener("orientationchange", updateScale, { passive: true });
})();
</script>
</body>
</html>

View File

@ -729,7 +729,7 @@ function renderRankRows(container) {
<img src="${DEFAULT_AVATAR}" alt="" />
</div>
<div class="rank-name">No ranking data yet</div>
<div class="rank-score">0</div>
<div class="rank-score">0 person</div>
<div class="rank-reward">0</div>
</article>
`
@ -946,7 +946,7 @@ function normalizeRankList(list) {
rank,
name: userName,
avatar: trimValue(item?.avatar) || DEFAULT_AVATAR,
inviteCountText: `${formatMetric(inviteCount)}`,
inviteCountText: `${formatMetric(inviteCount)} person`,
rewardText: formatMetric(rewardGoldCoins),
score: scoreParts.join(" · "),
};

View File

@ -0,0 +1,11 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 1038.5 58" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector 4" d="M0 58L9 49V28L34 8H193.5L200 17.5H840.5L845.5 8H1005.5L1031 28.5V49L1038.5 58V25.5L1010 0H840.5L834.5 11.5H204L197 0H30L0 25.5V58Z" fill="url(#paint0_linear_0_5)"/>
<defs>
<linearGradient id="paint0_linear_0_5" x1="0" y1="29" x2="1038.5" y2="29" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFCC5A"/>
<stop offset="0.1342" stop-color="#FAE47E"/>
<stop offset="0.721154" stop-color="#FAE47E"/>
<stop offset="1" stop-color="#FFCC5A"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 669 B

View File

@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 1080 1711" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect id="Rectangle 33" width="1080" height="1711" fill="url(#paint0_linear_0_4)"/>
<defs>
<linearGradient id="paint0_linear_0_4" x1="540" y1="0" x2="540" y2="1621.44" gradientUnits="userSpaceOnUse">
<stop offset="0.65" stop-color="#D9D9D9"/>
<stop offset="1" stop-color="#737373" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 MiB

View File

@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 301 301" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect id="Rectangle 43" width="301" height="301" fill="var(--fill-0, #D9D9D9)"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 113 131" fill="none" xmlns="http://www.w3.org/2000/svg">
<foreignObject x="-8" y="-8" width="129" height="147"><div xmlns="http://www.w3.org/1999/xhtml" style="backdrop-filter:blur(4px);clip-path:url(#bgblur_0_0_4_clip_path);height:100%;width:100%"></div></foreignObject><path id="Rectangle 52" data-figma-bg-blur-radius="8" d="M90 2C101.598 2 111 11.402 111 23V108C111 119.598 101.598 129 90 129H23C11.402 129 2 119.598 2 108V23C2 11.402 11.402 2 23 2H90Z" fill="var(--fill-0, #7E4134)" stroke="url(#paint0_linear_0_4)" stroke-width="4"/>
<defs>
<clipPath id="bgblur_0_0_4_clip_path" transform="translate(8 8)"><path d="M90 2C101.598 2 111 11.402 111 23V108C111 119.598 101.598 129 90 129H23C11.402 129 2 119.598 2 108V23C2 11.402 11.402 2 23 2H90Z"/>
</clipPath><linearGradient id="paint0_linear_0_4" x1="4" y1="4" x2="55.7064" y2="146.357" gradientUnits="userSpaceOnUse">
<stop stop-color="#E8A96B"/>
<stop offset="0.288462" stop-color="#FDE3B8"/>
<stop offset="0.6875" stop-color="#DF944B"/>
<stop offset="1" stop-color="#FDE3B8"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 1080 1021.92" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect id="Rectangle 33" width="1080" height="1021.92" fill="url(#paint0_linear_0_21)"/>
<defs>
<linearGradient id="paint0_linear_0_21" x1="540" y1="0" x2="540" y2="968.434" gradientUnits="userSpaceOnUse">
<stop offset="0.65" stop-color="#D9D9D9"/>
<stop offset="1" stop-color="#737373" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

View File

@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 274 66" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect id="Rectangle 44" width="274" height="66" fill="url(#paint0_linear_0_26)"/>
<defs>
<linearGradient id="paint0_linear_0_26" x1="67.0122" y1="-1.08643e-08" x2="66.6626" y2="66" gradientUnits="userSpaceOnUse">
<stop stop-color="#D9D9D9" stop-opacity="0"/>
<stop offset="1" stop-color="#737373"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

View File

@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 240 240" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect id="Rectangle 43" width="240" height="240" fill="var(--fill-0, #D9D9D9)"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

View File

@ -0,0 +1,122 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<title>Recharge Center</title>
<link rel="stylesheet" href="./style.css?v=20260429-0100" />
</head>
<body>
<div class="recharge-center" aria-label="Recharge Center" data-i18n-aria="page_label" data-loading="true">
<div class="hero-bg" aria-hidden="true"></div>
<nav class="title-bar">
<button class="back-button" type="button" aria-label="Back" data-i18n-aria="back">
<svg viewBox="0 0 32 32" aria-hidden="true">
<path d="M20 8 12 16l8 8" />
</svg>
</button>
<h1 data-i18n="title">Recharge Center</h1>
<div class="language-switcher">
<button class="language-button" type="button" aria-label="Change language" data-i18n-aria="language_button_aria" aria-expanded="false">EN</button>
<div class="language-menu" hidden>
<button type="button" data-lang="en">EN</button>
<button type="button" data-lang="ar">AR</button>
<button type="button" data-lang="tr">TR</button>
<button type="button" data-lang="id">ID</button>
</div>
</div>
</nav>
<main class="content">
<section class="card search-card">
<div class="section-head">
<div>
<div class="section-title" data-i18n="search_title">Recharge user</div>
<div class="section-subtitle" data-i18n="search_subtitle">Search by user ID</div>
</div>
<button class="icon-button" type="button" data-help-open aria-label="Help" data-i18n-aria="help">
<svg viewBox="0 0 24 24" aria-hidden="true">
<circle cx="12" cy="12" r="9" />
<path d="M9.5 9a2.7 2.7 0 0 1 5.2.9c0 1.9-2.7 2.2-2.7 4.1" />
<path d="M12 17h.01" />
</svg>
</button>
</div>
<form class="search-form" id="searchForm" autocomplete="off">
<input id="accountInput" type="text" inputmode="text" data-i18n-placeholder="search_placeholder" placeholder="Enter user ID" />
<button id="searchButton" type="submit" data-i18n="search">Search</button>
</form>
<div class="form-status" id="searchStatus" role="status" hidden></div>
</section>
<section class="card profile-card" id="targetCard" hidden>
<div class="avatar-shell">
<img class="avatar-image" id="targetAvatar" alt="" hidden />
<span class="avatar-fallback" id="targetAvatarFallback">U</span>
</div>
<div class="profile-copy">
<div class="role-pill" data-i18n="target_user">Target user</div>
<div class="name" id="targetName">-</div>
<div class="meta" id="targetUid">UID: -</div>
</div>
<button class="mini-action" type="button" data-change-target data-i18n="change">Change</button>
</section>
<section class="card country-card" id="countryCard" hidden>
<div class="section-head">
<div>
<div class="section-title" data-i18n="select_country">Select a country</div>
<div class="section-subtitle" id="countrySubtitle">-</div>
</div>
</div>
<div class="country-list" id="countryList"></div>
</section>
<section class="card payment-card" id="paymentCard" hidden>
<div class="section-head">
<div>
<div class="section-title" data-i18n="payment_methods">Payment methods</div>
<div class="section-subtitle" data-i18n="select_package">Select a package</div>
</div>
</div>
<div class="payment-status" id="paymentStatus" role="status" hidden></div>
<div class="channel-list" id="channelList"></div>
</section>
</main>
<div class="help-modal" id="helpModal" hidden>
<div class="modal-backdrop" data-help-close></div>
<section class="modal-dialog" role="dialog" aria-modal="true" aria-labelledby="helpTitle">
<div class="modal-head">
<h2 id="helpTitle" data-i18n="help">Help</h2>
<button class="modal-close" type="button" aria-label="Close" data-i18n-aria="close" data-help-close>&times;</button>
</div>
<div class="help-content">
<h3 data-i18n="faq_title">FAQ</h3>
<p data-i18n="faq_question_1">How to recharge?</p>
<p data-i18n="faq_answer_1">Enter the user's ID, choose a package, then select a payment method.</p>
<p data-i18n="faq_question_2">How to check recharge result?</p>
<p data-i18n="faq_answer_2">After payment, return to the app and check the user's wallet balance.</p>
</div>
</section>
</div>
<div class="home-indicator" aria-hidden="true"></div>
<div class="loading-mask" id="loadingMask" role="status" aria-live="polite" aria-busy="true">
<div class="runner-stick" aria-hidden="true">
<span class="runner-head"></span>
<span class="runner-body"></span>
<span class="runner-arm runner-arm-front"></span>
<span class="runner-arm runner-arm-back"></span>
<span class="runner-leg runner-leg-front"></span>
<span class="runner-leg runner-leg-back"></span>
<span class="runner-ground"></span>
</div>
<div class="loading-copy">loading....</div>
</div>
<div class="toast" id="toast" role="status" aria-live="polite" hidden></div>
</div>
<script src="./script.js?v=20260429-0100" defer></script>
</body>
</html>

View File

@ -0,0 +1,163 @@
# Original Vue Recharge Center Logic
## Routes
- `/recharge`
- Clears the persisted `targetUser` store on mount.
- Lets the user input a target account / user ID.
- Searches the target user before entering the payment page.
- Opens a help modal with recharge instructions.
- `/recharge-pay-way`
- Reads the target user from the persisted `targetUser` store.
- Loads payment application, target region/country, commodity packages, and payment channels.
- Places a recharge order and redirects to a third-party payment page.
## State
- `targetUser`
- Persisted Pinia store.
- `setTargetUser(profile)` after `/recharge` search succeeds.
- `clearTargetUser()` on `/recharge` mount and after Airwallex order redirect starts.
- `selectedCountry`
- Country store value used by `/recharge-pay-way`.
- First returned country is selected when the store is empty.
- `countryList`
- Country store list populated from `/order/web/pay/user-profile`.
- `applicationId`
- Fixed value in original Vue: `1963531459019739137`.
- `type`
- `FREIGHT_GOLD_SUPER` when `targetUser.isSuperFreightAgent`.
- `FREIGHT_GOLD` when `targetUser.isFreightAgent`.
- `GOLD` otherwise.
## APIs
### Search target user
`GET /user/user-profile/open-search?account=<account>`
Usage:
- Called from `/recharge` search button.
- Success condition in Vue: `status && body.id`.
- Success action: save `body` to `targetUser`, then route to `/recharge-pay-way`.
- Failure action: toast `User info not found`.
Reusable fields:
- `id`
- `account`
- `userNickname`
- `name`
- `userAvatar`
- `ownSpecialId.account`
- `isFreightAgent`
- `isSuperFreightAgent`
### Get payment application
`GET /order/web/pay/application/{applicationId}`
Usage:
- Called by `/recharge-pay-way`.
- Original code reads `body.appCode`.
Reusable fields:
- `id`
- `appName`
- `appCode`
- `androidLink`
- `iosLink`
### Get target recharge profile and countries
`GET /order/web/pay/user-profile`
Query params:
- `sysOrigin=<appCode>`
- `account=<targetUser.account>`
- `type=GOLD | FREIGHT_GOLD | FREIGHT_GOLD_SUPER`
Usage:
- Called after payment application is loaded.
- Backend resolves user region and available pay countries.
- Original Vue sets `countryList`, selects the first country if none is selected, and stores `regionId`.
Reusable fields:
- `userProfile.id`
- `userProfile.userAvatar`
- `userProfile.userNickname`
- `userProfile.account`
- `userProfile.sysOrigin`
- `countryList[].id`
- `countryList[].countryId`
- `countryList[].country.countryName`
- `countryList[].country.aliasName`
- `countryList[].country.nationalFlag`
- `regionId`
### Get commodities and channels
`GET /order/web/pay/commodity`
Query params:
- `applicationId=1963531459019739137`
- `payCountryId=<selected country id>`
- `regionId=<regionId>`
- `type=GOLD | FREIGHT_GOLD | FREIGHT_GOLD_SUPER`
Usage:
- Called after country/profile data is ready.
- Original Vue renders all returned channels, and each channel shows the same commodity grid.
Reusable fields:
- `application`
- `commodity[].id`
- `commodity[].content`
- `commodity[].awardContent`
- `commodity[].amountUsd`
- `commodity[].amount`
- `commodity[].currency`
- `channels[].channel.channelCode`
- `channels[].channel.channelName`
- `channels[].channel.channelIcon`
- `channels[].details.channelCode`
- `channels[].details.factoryChannel`
- `channels[].details.factoryMinLimit`
- `channels[].details.factoryMaxLimit`
### Place recharge order
`POST /order/web/pay/recharge`
Body:
```json
{
"applicationId": "1963531459019739137",
"payCountryId": "<selected country id>",
"goodsId": "<commodity id>",
"userId": "<target user id>",
"channelCode": "<channel.channelCode>"
}
```
Usage:
- Called when the user taps a commodity under a payment channel.
- If `body.factoryCode === "AIRWALLEX"`, original Vue loads Airwallex Elements and calls `redirectToCheckout`.
- If `body.requestUrl` exists, original Vue redirects with `location.href = decodeURIComponent(requestUrl)`.
Reusable fields:
- `orderId`
- `tradeNo`
- `factoryCode`
- `factoryChannelCode`
- `currency`
- `requestUrl`
- `expand.id`
- `expand.client_secret`
## New H5 implementation notes
- New page lives at `h5/hyapp/recharge-center`.
- It keeps the existing hyapp center architecture: static `index.html`, `style.css`, `script.js`.
- It uses URL `token` for Java API authorization and sends the same H5 request headers used by the existing hyapp center pages.
- It merges the original `/recharge` and `/recharge-pay-way` flows into one page, so it does not depend on Vue router or Pinia `targetUser`.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,859 @@
:root {
--page-bg: #f6f7f7;
--card-bg: rgba(255, 255, 255, 0.96);
--text: #25282e;
--muted: #8f9196;
--line: #eef0f2;
--mint: #43e7d8;
--green: #25d878;
--danger: #e85b5b;
--shadow: 0 8px 22px rgba(36, 46, 60, 0.055);
}
* {
box-sizing: border-box;
}
html,
body {
width: 100%;
min-height: 100%;
margin: 0;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
body {
display: flex;
justify-content: center;
background: #111;
color: var(--text);
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
button,
input {
font: inherit;
}
button {
border: 0;
padding: 0;
background: transparent;
color: inherit;
}
[hidden] {
display: none !important;
}
.recharge-center {
position: relative;
width: 100%;
max-width: 430px;
min-height: 100vh;
overflow: hidden;
background: var(--page-bg);
}
.recharge-center[data-loading="true"] .title-bar,
.recharge-center[data-loading="true"] .content,
.recharge-center[data-loading="true"] .home-indicator {
visibility: hidden;
}
.hero-bg {
position: absolute;
inset: 0 0 auto;
height: 215px;
background:
radial-gradient(circle at 72% 4%, rgba(209, 255, 248, 0.98) 0, rgba(209, 255, 248, 0.88) 23%, rgba(209, 255, 248, 0) 48%),
radial-gradient(circle at 14% 20%, rgba(185, 250, 244, 0.78) 0, rgba(185, 250, 244, 0) 35%),
linear-gradient(151deg, #ccf7ef 0%, #ebfffa 58%, rgba(242, 255, 252, 0.7) 100%);
clip-path: polygon(0 0, 100% 0, 100% 76%, 70% 47%, 40% 58%, 0 78%);
}
.title-bar,
.content,
.home-indicator {
position: relative;
z-index: 1;
}
.title-bar {
display: grid;
grid-template-columns: 44px minmax(0, 1fr) 56px;
align-items: center;
z-index: 12;
min-height: 56px;
padding: 8px 14px 6px;
}
.back-button,
.language-button,
.icon-button {
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
color: #2c3036;
}
.back-button {
width: 38px;
height: 38px;
}
.back-button svg,
.icon-button svg {
fill: none;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
}
.back-button svg {
width: 30px;
height: 30px;
stroke-width: 2.4;
}
.title-bar h1 {
min-width: 0;
margin: 0;
overflow: hidden;
color: #24282e;
font-size: 19px;
font-weight: 900;
line-height: 1.2;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
}
.language-switcher {
position: relative;
display: flex;
justify-content: flex-end;
}
.language-button {
width: auto;
min-width: 42px;
height: 32px;
padding: 0 10px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.55);
font-size: 12px;
font-weight: 900;
}
.language-menu {
position: absolute;
top: 38px;
right: 0;
z-index: 30;
display: grid;
gap: 4px;
min-width: 74px;
padding: 8px;
border: 1px solid rgba(34, 196, 180, 0.18);
border-radius: 8px;
background: #fff;
box-shadow: 0 12px 24px rgba(22, 31, 42, 0.12);
}
.language-menu button {
min-height: 30px;
border-radius: 6px;
font-size: 12px;
font-weight: 850;
}
.language-menu button.is-active {
background: #e7fbf8;
color: #0aa397;
}
.content {
display: grid;
gap: 12px;
padding: 8px 14px 32px;
}
.card {
border-radius: 8px;
background: var(--card-bg);
box-shadow: var(--shadow);
}
.search-card,
.country-card,
.payment-card {
display: grid;
gap: 14px;
padding: 16px;
}
.section-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.section-title {
color: #24282e;
font-size: 16px;
font-weight: 900;
line-height: 1.2;
}
.section-subtitle {
margin-top: 6px;
color: #93959a;
font-size: 12px;
font-weight: 800;
line-height: 1.2;
}
.icon-button {
width: 34px;
height: 34px;
flex: 0 0 34px;
background: #e7fbf8;
color: #0aa397;
}
.icon-button svg {
width: 21px;
height: 21px;
stroke-width: 2.2;
}
.search-form {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
}
.search-form input {
width: 100%;
min-width: 0;
height: 44px;
border: 1px solid #e4eeee;
border-radius: 8px;
outline: 0;
padding: 0 12px;
background: #fbfdfd;
color: #24282e;
font-size: 14px;
font-weight: 800;
}
.search-form input:focus {
border-color: rgba(21, 189, 169, 0.7);
box-shadow: 0 0 0 3px rgba(21, 189, 169, 0.12);
}
.search-form button,
.package-button,
.mini-action {
min-height: 44px;
border-radius: 8px;
background: linear-gradient(135deg, #30dfb4, #15bda9);
color: #fff;
font-size: 14px;
font-weight: 950;
box-shadow: 0 8px 18px rgba(21, 189, 169, 0.24);
}
.search-form button {
min-width: 88px;
padding: 0 14px;
}
.search-form button:disabled,
.package-button:disabled,
.mini-action:disabled {
opacity: 0.55;
}
.form-status,
.payment-status {
padding: 10px 12px;
border-radius: 8px;
background: #f1fbf9;
color: #0b958a;
font-size: 12px;
font-weight: 850;
line-height: 1.3;
}
.form-status.is-error,
.payment-status.is-error {
background: #fff3f3;
color: var(--danger);
}
.profile-card {
display: flex;
align-items: center;
min-height: 104px;
padding: 16px;
}
.avatar-shell {
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
width: 70px;
height: 70px;
flex: 0 0 70px;
border-radius: 50%;
background: linear-gradient(145deg, #d9fff5, #43e7d8);
}
.avatar-image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.avatar-fallback {
color: #0b5f56;
font-size: 26px;
font-weight: 950;
}
.profile-copy {
min-width: 0;
flex: 1;
margin-left: 16px;
}
.role-pill {
display: inline-flex;
align-items: center;
min-height: 22px;
padding: 0 9px;
border-radius: 999px;
background: #e7fbf8;
color: #0b958a;
font-size: 11px;
font-weight: 900;
}
.name {
margin-top: 7px;
overflow: hidden;
color: #25282e;
font-size: 20px;
font-weight: 900;
line-height: 1.15;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta {
margin-top: 6px;
overflow: hidden;
color: var(--muted);
font-size: 13px;
font-weight: 750;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.mini-action {
min-width: 78px;
min-height: 36px;
margin-left: 10px;
padding: 0 12px;
font-size: 12px;
}
.country-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
gap: 10px;
}
.country-chip {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
min-height: 46px;
padding: 8px 10px;
border: 1px solid #e4eeee;
border-radius: 8px;
background: #fbfdfd;
}
.country-chip.is-active {
border-color: rgba(21, 189, 169, 0.6);
background: #ecfffb;
box-shadow: inset 0 0 0 1px rgba(21, 189, 169, 0.14);
}
.country-flag {
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
width: 28px;
height: 28px;
flex: 0 0 28px;
border-radius: 50%;
background: #e7fbf8;
color: #0b958a;
font-size: 11px;
font-weight: 950;
}
.country-flag img {
width: 100%;
height: 100%;
object-fit: cover;
}
.country-name {
min-width: 0;
overflow: hidden;
color: #464951;
font-size: 13px;
font-weight: 900;
line-height: 1.2;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
}
.channel-list {
display: grid;
gap: 12px;
}
.channel-card {
display: grid;
gap: 12px;
padding: 13px;
border: 1px solid #eef0f2;
border-radius: 8px;
background: #fbfcfc;
}
.channel-head {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
}
.channel-icon {
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
width: 38px;
height: 38px;
flex: 0 0 38px;
border-radius: 8px;
background: #e9fbf4;
color: #1f9d66;
font-size: 14px;
font-weight: 950;
}
.channel-icon img {
width: 100%;
height: 100%;
object-fit: cover;
}
.channel-name {
min-width: 0;
overflow: hidden;
color: #25282e;
font-size: 15px;
font-weight: 950;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.package-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 9px;
}
.package-button {
display: grid;
justify-items: center;
gap: 5px;
min-width: 0;
min-height: 92px;
padding: 10px 6px;
background: #fff;
color: #25282e;
border: 1px solid #eef0f2;
box-shadow: none;
}
.coin-mark {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 50%;
background: linear-gradient(145deg, #ffe694, #ffc93f);
color: #8b5d00;
font-weight: 950;
}
.package-content,
.package-price {
max-width: 100%;
overflow-wrap: anywhere;
text-align: center;
line-height: 1.15;
}
.package-content {
color: #4a4f58;
font-size: 12px;
font-weight: 850;
}
.package-price {
color: #181d24;
font-size: 14px;
font-weight: 950;
}
.empty-state {
padding: 14px;
border-radius: 8px;
background: #f7fbfa;
color: #8b8d92;
font-size: 13px;
font-weight: 850;
text-align: center;
}
.help-modal {
position: fixed;
inset: 0;
z-index: 40;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.modal-backdrop {
position: absolute;
inset: 0;
background: rgba(15, 23, 42, 0.42);
}
.modal-dialog {
position: relative;
z-index: 1;
display: grid;
gap: 12px;
width: min(100%, 360px);
max-height: 80vh;
overflow: hidden;
border-radius: 12px;
background: #fff;
box-shadow: 0 20px 46px rgba(15, 23, 42, 0.22);
}
.modal-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 16px 16px 0;
}
.modal-head h2 {
margin: 0;
color: #24282e;
font-size: 18px;
font-weight: 950;
line-height: 1.2;
}
.modal-close {
width: 30px;
height: 30px;
border-radius: 50%;
background: #f2f6f6;
color: #4b5563;
font-size: 22px;
line-height: 1;
}
.help-content {
display: grid;
gap: 8px;
overflow-y: auto;
padding: 0 16px 18px;
-webkit-overflow-scrolling: touch;
}
.help-content h3,
.help-content p {
margin: 0;
}
.help-content h3 {
color: #24282e;
font-size: 15px;
font-weight: 950;
}
.help-content p {
color: #5d626b;
font-size: 13px;
font-weight: 750;
line-height: 1.4;
}
.home-indicator {
width: 134px;
height: 5px;
margin: 10px auto 8px;
border-radius: 999px;
background: #111;
}
.loading-mask {
position: fixed;
inset: 0;
z-index: 60;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 14px;
background: rgba(246, 247, 247, 0.92);
}
.runner-stick {
position: relative;
width: 74px;
height: 58px;
color: #16b86d;
}
.runner-stick span {
position: absolute;
display: block;
background: currentColor;
}
.runner-head {
top: 0;
left: 28px;
width: 18px;
height: 18px;
border-radius: 50%;
animation: runner-bob 0.5s linear infinite;
}
.runner-body {
top: 18px;
left: 36px;
width: 5px;
height: 23px;
border-radius: 999px;
transform-origin: top center;
animation: runner-body 0.5s linear infinite;
}
.runner-arm,
.runner-leg {
left: 36px;
width: 5px;
border-radius: 999px;
transform-origin: top center;
}
.runner-arm {
top: 21px;
height: 22px;
}
.runner-leg {
top: 39px;
height: 24px;
}
.runner-arm-front {
animation: runner-arm-front 0.5s linear infinite;
}
.runner-arm-back {
animation: runner-arm-back 0.5s linear infinite;
}
.runner-leg-front {
animation: runner-leg-front 0.5s linear infinite;
}
.runner-leg-back {
animation: runner-leg-back 0.5s linear infinite;
}
.runner-ground {
left: 7px;
bottom: 0;
width: 58px;
height: 4px;
border-radius: 999px;
opacity: 0.35;
animation: runner-ground 0.5s linear infinite;
}
.loading-copy {
color: #0b958a;
font-size: 13px;
font-weight: 950;
letter-spacing: 0;
}
.toast {
position: fixed;
left: 50%;
bottom: calc(28px + env(safe-area-inset-bottom));
z-index: 70;
max-width: min(330px, calc(100vw - 48px));
transform: translateX(-50%);
padding: 10px 14px;
border-radius: 999px;
background: rgba(20, 27, 34, 0.92);
color: #fff;
font-size: 13px;
font-weight: 850;
line-height: 1.25;
text-align: center;
}
body.modal-open {
overflow: hidden;
}
[dir="rtl"] .language-menu {
right: auto;
left: 0;
}
[dir="rtl"] .profile-copy {
margin-right: 16px;
margin-left: 0;
}
[dir="rtl"] .mini-action {
margin-right: 10px;
margin-left: 0;
}
[dir="rtl"] .country-name {
text-align: right;
}
@keyframes runner-bob {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(4px);
}
}
@keyframes runner-body {
0%,
100% {
transform: rotate(-8deg);
}
50% {
transform: rotate(8deg);
}
}
@keyframes runner-arm-front {
0%,
100% {
transform: rotate(60deg);
}
50% {
transform: rotate(-55deg);
}
}
@keyframes runner-arm-back {
0%,
100% {
transform: rotate(-55deg);
}
50% {
transform: rotate(60deg);
}
}
@keyframes runner-leg-front {
0%,
100% {
transform: rotate(-50deg);
}
50% {
transform: rotate(48deg);
}
}
@keyframes runner-leg-back {
0%,
100% {
transform: rotate(48deg);
}
50% {
transform: rotate(-50deg);
}
}
@keyframes runner-ground {
0% {
transform: translateX(7px) scaleX(0.75);
}
100% {
transform: translateX(-7px) scaleX(1);
}
}
@media (max-width: 360px) {
.title-bar {
grid-template-columns: 40px minmax(0, 1fr) 50px;
padding-right: 10px;
padding-left: 10px;
}
.content {
padding-right: 10px;
padding-left: 10px;
}
.package-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}