Initial import of HEROLL source and design documents

This commit is contained in:
toshiocn
2026-10-26 16:05:39 +08:00
commit fdb55672c1
1846 changed files with 290692 additions and 0 deletions
+221
View File
@@ -0,0 +1,221 @@
const A = '../assets/original';
const screens = [
['board','UI-002','关卡棋盘','掷骰—移动—触发的主循环'],
['dice','UI-003','骰子结算','双骰结果与落点预告'],
['third-die','UI-004','第三骰选择','特殊祝福的局内决策'],
['battle','UI-005','自动战斗','自动演算,仅保留药水干预'],
['gear','UI-006','装备比较','战斗中即时换装或分解'],
['shop','UI-007','商店事件','三普通+三特殊商品'],
['tile-install','UI-008','地块安装','完成一圈后的正向成长'],
['chest','UI-009','宝箱事件','开启、领取'],
['campfire','UI-010','篝火事件','回复与增益地块'],
['smithy','UI-011','铁匠事件','强化当前装备'],
['blessing','UI-012','祝福揭示','单卡接受'],
['dig','UI-013','挖掘事件','5×5 网格与有限挖掘次数'],
['legendary','UI-014','传奇装备','高价值装备确认'],
['lotto','UI-015','乐透事件','抽取式奖励'],
['blackjack','UI-016','二十一点事件','风险收益抉择'],
['claw','UI-017','抓娃娃事件','时机型小游戏'],
['carriage','UI-018','黄金马车','一次性高价值事件'],
['dice-machine','UI-019','骰子机事件','组合结果奖励'],
['bubble','UI-020','泡泡射手','局内轻量技能事件'],
['revive','UI-021','源码祝福复生','自动结算且无广告按钮'],
['victory','UI-023','关卡胜利','奖励收束与离开'],
['defeat','UI-024','关卡失败','失败归因与离开'],
['pause','UI-025','暂停界面','继续、设置、退出']
];
const path = (cat,name) => `${A}/${cat}/${name}`;
const image = (cat,name,cls='',alt='') => `<img class="${cls}" src="${path(cat,name)}" alt="${alt}">`;
function sceneLayers(theme='volcano'){
return `<div class="scene">
${image('scene',`sharedassets4__chapter_select_back_${theme}.png`,'scene-back','原作场景后景')}
${image('scene',`sharedassets4__chapter_select_front_${theme}.png`,'scene-front','原作场景前景')}
<div class="vignette"></div>
</div>`;
}
function topHud(points=16, auto=true){
return `<div class="safe-top">
<div class="currency">${points}</div>
<div class="top-actions"><button class="auto ${auto?'on':''}">AUTO</button><button class="pause" aria-label="暂停"></button></div>
</div>`;
}
function floorTrack(floor=4){
const pct = Math.min(90, Math.max(7, floor/10*100));
return `<div class="floor-track"><div class="floor-label">${floor} / 10</div><div class="track-line"><span class="track-fill" style="height:${pct}%"></span><i class="track-dot" style="top:${100-pct}%"></i></div><div class="boss-medal"></div></div>`;
}
function slots(){
return `<div class="slots">
<div class="slot"><b>12</b>${image('gear','sharedassets3__legend_gear_sword.png','','武器')}</div>
<div class="slot ring"><b>8</b></div>
<div class="slot"><b>9</b>${image('gear','sharedassets3__legend_gear_arm.png','','手套')}</div>
<div class="slot boot"><b>7</b></div>
</div>`;
}
function bottomHud(action='ROLL', cls='', hp='742 / 1000'){
return `<div class="bottom-hud">
<div class="hp-wrap"><div class="level-badge">18</div><div class="hp-bar"><div class="hp-fill"></div><div class="hp-text">${hp}</div></div></div>
<button class="side-btn map-btn" aria-label="地图"></button>
${slots()}
<button class="side-btn potion" aria-label="使用药水">${image('hud','sharedassets3__potion_image.png','','药水')}<em>2</em></button>
<button class="primary ${cls}">${action}</button>
</div>`;
}
function tiles(){
return Array.from({length:16},(_,i)=>{
const good = [3,8,12].includes(i+1);
const file = good ? 'sharedassets3__tile_goodEvent.png' : (i%4===0?'sharedassets3__tile_corner.png':'sharedassets3__tile_normal.png');
return `<div class="tile t${i+1} ${good?'good':''}">${image('board',file,'',good?'正向事件格':'普通格')}</div>`;
}).join('');
}
function boardWorld(){
return `<div class="board-loop">
<div class="board-center"><div class="center-lava"></div>${image('battle','sharedassets3__001_boss_idle_2.png','boss','关底首领')}</div>
${tiles()}
</div>${image('tutorial_vfx','sharedassets3__Tutorial_knight.png','hero-token','玩家棋子')}`;
}
function base({action='ROLL',actionClass='',floor=4,points=16,hp='742 / 1000',theme='volcano',auto=true,content='',toast=''}){
return `<section class="game-screen">${sceneLayers(theme)}${content}${topHud(points,auto)}${floorTrack(floor)}${bottomHud(action,actionClass,hp)}${toast}</section>`;
}
function boardScreen(){ return base({content:boardWorld(),toast:'<div class="toast">前进 7 格<small>落点:普通战斗</small></div>'}); }
function diceScreen(){
return base({content:`${boardWorld()}<div class="modal-dim"></div><div class="dice-result">${image('hud','sharedassets3__dice_red_3.png','','红骰结果 3')}${image('hud','sharedassets3__dice_blue_4.png','','蓝骰结果 4')}</div><div class="dice-sum">7</div>`,action:'前进 7 格'});
}
function thirdDieScreen(){
const choices = [
['hud','sharedassets3__dice_red_3.png','攻击骰','下次战斗伤害 +20%'],
['hud','sharedassets3__dice_blue_4.png','护盾骰','本层获得 120 护盾'],
['event_blessing','sharedassets3__power_star_slot1_1.png','命运骰','移动点数额外 +3']
];
return base({content:`${boardWorld()}<div class="modal-dim"></div><div class="modal"><h2 class="modal-title">选择第三颗骰子</h2><p class="modal-copy">命运祝福已生效,本次投掷额外选择一枚骰子。</p><div class="choice-row">${choices.map((c,i)=>`<button class="choice ${i===2?'selected':''}">${image(c[0],c[1])}<b>${c[2]}</b><span>${c[3]}</span></button>`).join('')}</div></div>`,action:'确认选择'});
}
function battleContent(withDrop=true){
return `<div class="battle-stage"><div class="battle-progress"><div class="team-fill"></div><div class="vs">VS</div></div>
${image('tutorial_vfx','sharedassets3__Tutorial_knight.png','fighter hero','玩家队伍')}
${image('battle','sharedassets3__001_boss_attack_2.png','fighter enemy','敌方首领')}
<div class="damage">-248</div>
${withDrop?`<div class="drop">${image('gear','sharedassets3__legend_gear_sword.png','','掉落武器')}</div>`:''}
</div>`;
}
function battleScreen(){ return base({content:battleContent(),action:'FIGHTING…',actionClass:'disabled',floor:7,hp:'618 / 1000',auto:true}); }
function gearScreen(){
const panel=(label,level,atk,spd,isNew)=>`<div class="gear-panel ${isNew?'new':''}"><div class="gear-icon"><b>${level}</b>${image('gear','sharedassets3__legend_gear_sword.png')}</div><div class="gear-stats"><h3>${label}</h3><div class="stat"><span>攻击</span><b class="${isNew?'up':''}">${atk}</b></div><div class="stat"><span>攻速</span><b class="${isNew?'down':''}">${spd}</b></div><div class="stat"><span>品质</span><b>${isNew?'史诗':'稀有'}</b></div></div></div>`;
return base({content:`${battleContent(false)}<div class="modal-dim"></div><div class="compare">${panel('新装备',14,'+82','0.94',true)}${panel('当前装备',12,'+61','1.08',false)}</div>`,action:'装备并分解旧武器',actionClass:'green',floor:7});
}
function shopScreen(){
const goods=[
['gear','sharedassets3__legend_gear_sword.png','精钢长剑','20'],
['hud','sharedassets3__potion_image.png','回复药水','12'],
['event_blessing','sharedassets3__power_star_slot1_1.png','祝福碎片','16'],
['gear','sharedassets3__legend_gear_arm.png','战斗手套','24'],
['hud','sharedassets3__dice_blue_4.png','护盾骰','20'],
['event_chest','sharedassets3__treasure_box_special_1.png','神秘宝箱','30']
];
return base({content:`<div class="shop-stage">${image('shop','sharedassets3__ingame_shop_bg.png','shop-bg','原作商店背景')}${image('shop','sharedassets3__ingame_shop_master.png','shop-master','原作商人')}<div class="shop-title">旅行商店</div><div class="goods">${goods.map((g,i)=>`<button class="good-card ${i===1?'sold':''}"><span class="good-icon">${image(g[0],g[1])}</span><b>${g[2]}</b><span class="price">◆ ${g[3]}</span></button>`).join('')}</div></div>`,action:'EXIT',floor:6,points:46});
}
function tileInstallScreen(){
return base({content:`${boardWorld()}<div class="modal-dim"></div><div class="modal"><h2 class="modal-title">安装增益地块</h2><p class="modal-copy">完成一圈:回复 30% 最大生命,并安装 2 个增益地块。</p><div class="choice-row"><button class="choice selected">${image('board','sharedassets3__tile_goodEvent.png')}<b>治疗之泉</b><span>经过时回复 10%</span></button><button class="choice">${image('board','sharedassets3__tile_goodEvent.png')}<b>幸运宝箱</b><span>获得随机装备</span></button><button class="choice">${image('board','sharedassets3__tile_goodEvent.png')}<b>祝福神殿</b><span>三选一祝福</span></button></div></div>`,action:'安装到高亮地块',floor:5});
}
function eventFrame({title,sub,art,category,action='领取奖励',extra='',floor=5,points=33,actionClass=''}){
return base({content:`<div class="event-stage"><div class="event-title">${title}</div><div class="event-sub">${sub}</div>${art?image(category,art,'event-art',title):''}${extra}</div>`,action,actionClass,floor,points});
}
function chestScreen(){ return eventFrame({title:'神秘宝箱',sub:'开启宝箱并领取本次装备奖励。',art:'sharedassets3__treasure_box_special_1.png',category:'event_chest',action:'打开宝箱'}); }
function campfireScreen(){ return eventFrame({title:'温暖篝火',sub:'恢复 10% 最大生命,并在棋盘安装 1 个增益地块。',art:'sharedassets3__bonfire.png',category:'event_camp_smithy',action:'休息',actionClass:'green'}); }
function smithyScreen(){ return eventFrame({title:'矮人铁匠铺',sub:'选择一件已装备物品进行强化;强化存在品质跃迁概率。',art:'sharedassets3__anvil.png',category:'event_camp_smithy',action:'强化武器'}); }
function blessingScreen(){
return base({content:`<div class="event-stage"><div class="event-title">获得祝福</div><div class="event-sub">本次揭示的祝福将在本局持续生效。</div><div class="bless-cards"><button class="bless-card pick">${image('event_blessing','sharedassets3__power_star_slot1_1.png')}<b>命运之骰</b><p>每次投掷可追加第三颗骰子</p></button></div></div>`,action:'接受祝福',floor:6,points:41});
}
function digScreen(){
const cells=Array.from({length:25},(_,i)=>`<button class="dig-cell ${[7,8,13].includes(i)?'open':''} ${i===8?'dig-reward':''}">${[7,13].includes(i)?image('event_dig',i===7?'sharedassets3__debris_stone_open_2.png':'sharedassets3__debris_bone_open_3.png'):image('event_dig','sharedassets3__hero_body_tile_2.png')}</button>`).join('');
return base({content:`<div class="event-stage"><div class="event-title">遗迹挖掘</div><div class="event-sub">选择土地挖掘,找到全部宝物前不要浪费铲数。</div><div class="dig-grid">${cells}</div><div class="event-count">剩余宝物 3 · 铲数 7</div></div>`,action:'DIGGING…',actionClass:'disabled',floor:7});
}
function legendaryScreen(){
return eventFrame({title:'传奇装备!',sub:'本局唯一高阶掉落。装备后旧物品会自动分解。',art:'sharedassets3__legend_gear_bg.png',category:'gear',action:'装备「炎刃」',actionClass:'green',extra:`${image('gear','sharedassets3__legend_gear_sword.png','event-art','传奇武器')}<div class="event-count">攻击 +128 · 暴击 +12%</div>`});
}
function lottoScreen(){
return eventFrame({title:'幸运乐透',sub:'从奖池中抽取一份奖励,本事件每层仅可触发一次。',art:'sharedassets3__lottery_bg.png',category:'event_lotto',action:'抽取奖励',extra:`${image('event_lotto','sharedassets3__lottery_front.png','lotto-layer','乐透机前景')}`});
}
function blackjackScreen(){
const cards='<div class="choice-row"><button class="choice selected"><b style="font-size:54px">K</b><span>当前点数 10</span></button><button class="choice"><b style="font-size:54px">7</b><span>当前点数 17</span></button><button class="choice"><b style="font-size:54px">?</b><span>下一张牌</span></button></div>';
return base({content:`<div class="event-stage"><div class="event-title">二十一点</div><div class="event-sub">当前 17 点。继续要牌,或停牌领取 ◆ 12。</div>${cards}<div class="event-count">庄家明牌:9</div></div>`,action:'停牌并领取',floor:8,points:52});
}
function clawScreen(){
return eventFrame({title:'魔法抓取机',sub:'左右调整位置,在光标对准奖励时落爪。',art:'sharedassets3__claw_machine.png',category:'event_claw',action:'落爪',extra:`${image('event_claw','sharedassets3__claw_arm.png','event-art','机械爪')}<div class="event-count">剩余次数 2</div>`,floor:8});
}
function carriageScreen(){
return eventFrame({title:'黄金马车',sub:'路过的王室马车留下了宝物。选择金币或装备。',art:'sharedassets3__treasure_box_3.png',category:'event_chest',action:'选择传奇装备',extra:'<div class="event-count">◆ 30 或 随机史诗装备</div>',floor:8,points:61});
}
function diceMachineScreen(){
return base({content:`<div class="event-stage"><div class="event-title">命运骰子机</div><div class="event-sub">投出三个相同数字可获得大奖。</div>${image('event_dice_machine','sharedassets4__game_machine_frame.png','machine','原作骰子机')}<div class="machine-screen">${[2,2,6].map(n=>image('event_dice_machine',`sharedassets4__game_machine_dice_${n}.png`)).join('')}</div><div class="event-count">剩余次数 1</div></div>`,action:'ROLL',floor:9,points:70});
}
function bubbleScreen(){
const bubbles=Array.from({length:36},()=>'<i class="bubble-ball"></i>').join('');
return base({content:`<div class="event-stage"><div class="event-title">泡泡射手</div>${image('event_bubble','sharedassets3__bubble_shooter_bg.png','bubble-field','原作泡泡射手背景')}<div class="bubble-pack">${bubbles}</div>${image('event_bubble','sharedassets3__bubble_shooter_cannon.png','cannon','原作发射器')}<div class="event-count">剩余射击 4</div></div>`,action:'SHOOT',floor:9,points:75});
}
function reviveScreen(){
return base({content:`${battleContent(false)}<div class="modal-dim"></div><div class="revive-card"><h2>复生祝福发动</h2><p>按源码祝福规则自动恢复生命,完整播放复生反馈后继续战斗。</p><div class="countdown">无广告复活或放弃广告按钮</div></div>`,action:'FIGHTING...',floor:10,hp:'40 / 1000'});
}
function resultScreen(win=true){
return `<section class="game-screen result-screen">${image('result',win?'sharedassets7__result_bg_clear.png':'sharedassets7__result_bg_youdied.png','result-bg',win?'胜利背景':'失败背景')}<div class="result-title">${win?'STAGE CLEAR':'YOU DIED'}</div>${win?image('battle','sharedassets3__victory_knight.png','result-knight','胜利骑士'):image('battle','sharedassets3__fail_shield.png','result-knight','失败盾牌')}<div class="reward-row"><div class="reward">◆ 120</div><div class="reward">EXP<br>+48</div><div class="reward">× 1</div></div><button class="result-button">${win?'领取并离开':'返回关卡选择'}</button></section>`;
}
function pauseScreen(){
return base({content:`${boardWorld()}<div class="modal-dim"></div><div class="pause-panel"><h2>PAUSE</h2><button>继续游戏</button><button>音效与震动</button><button>战斗说明</button><button>退出本局</button></div>`,action:'ROLL',floor:4});
}
const renderers = {
board:boardScreen,dice:diceScreen,'third-die':thirdDieScreen,battle:battleScreen,gear:gearScreen,shop:shopScreen,'tile-install':tileInstallScreen,chest:chestScreen,campfire:campfireScreen,smithy:smithyScreen,blessing:blessingScreen,dig:digScreen,legendary:legendaryScreen,lotto:lottoScreen,blackjack:blackjackScreen,claw:clawScreen,carriage:carriageScreen,'dice-machine':diceMachineScreen,bubble:bubbleScreen,revive:reviveScreen,victory:()=>resultScreen(true),defeat:()=>resultScreen(false),pause:pauseScreen
};
const nav=document.querySelector('#screenNav');
const phone=document.querySelector('#phone');
let current=0;
function selectScreen(id,push=true){
const index=screens.findIndex(s=>s[0]===id);
current=index<0?0:index;
const [key,code,title,note]=screens[current];
phone.innerHTML=renderers[key]();
document.querySelector('#screenTitle').textContent=title;
document.querySelector('#screenCode').textContent=code;
document.querySelector('#screenNote').textContent=note;
document.querySelectorAll('.nav-btn').forEach((b,i)=>b.classList.toggle('active',i===current));
if(push && !document.body.classList.contains('capture')) history.replaceState(null,'',`?screen=${key}`);
}
nav.innerHTML=screens.map((s,i)=>`<button class="nav-btn" data-screen="${s[0]}"><b>${s[1]}</b>${s[2]}</button>`).join('');
nav.addEventListener('click',e=>{const btn=e.target.closest('[data-screen]');if(btn)selectScreen(btn.dataset.screen)});
document.addEventListener('keydown',e=>{if(e.key==='ArrowRight')selectScreen(screens[(current+1)%screens.length][0]);if(e.key==='ArrowLeft')selectScreen(screens[(current-1+screens.length)%screens.length][0]);});
const query=new URLSearchParams(location.search);
if(query.get('capture')==='1') document.body.classList.add('capture');
selectScreen(query.get('screen')||'board',false);
window.HEROLL_UI={screens:screens.map(s=>s[0]),selectScreen};
+29
View File
@@ -0,0 +1,29 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<title>HEROLL|关卡内 UE/UI 复刻设计</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main class="workbench">
<aside class="navigator" aria-label="界面导航">
<div class="brand">HEROLL <small>IN-RUN UE/UI</small></div>
<p>750 × 1334 · 9:16 竖屏<br>原作逆向资源复用</p>
<nav id="screenNav"></nav>
<div class="legend"><i></i> 可交互设计样稿<br><span>键盘 ← → 切换界面</span></div>
</aside>
<section class="device-stage">
<header class="stage-meta">
<div><strong id="screenTitle">关卡棋盘</strong><span id="screenCode">UI-002</span></div>
<p id="screenNote">主循环决策界面</p>
</header>
<div class="phone-frame">
<div id="phone" class="phone" role="application" aria-label="HEROLL 竖屏界面样稿"></div>
</div>
</section>
</main>
<script src="app.js"></script>
</body>
</html>
+67
View File
@@ -0,0 +1,67 @@
:root {
--ink:#11162c;
--deep:#20223d;
--panel:#343754;
--paper:#f5e7bd;
--gold:#ffd34a;
--orange:#f58d2b;
--red:#d9483f;
--green:#58c561;
--cyan:#66d9e8;
--outline:6px;
}
*{box-sizing:border-box}
html,body{margin:0;min-height:100%;background:#121525;color:#f4f1df;font-family:"Trebuchet MS","Microsoft YaHei",sans-serif}
body{overflow:hidden}
button{font:inherit}
.workbench{height:100vh;display:grid;grid-template-columns:270px 1fr;background:radial-gradient(circle at 70% 15%,#303659 0,#171a2c 46%,#0d0f1c 100%)}
.navigator{padding:30px 22px 24px;background:rgba(10,12,24,.9);border-right:1px solid #383d62;overflow:auto}
.brand{font-size:28px;font-weight:1000;letter-spacing:1px;color:var(--gold);text-shadow:3px 3px #8c392f}
.brand small{display:block;color:#f4f1df;font-size:11px;letter-spacing:2px;text-shadow:none;margin-top:2px}
.navigator>p{font-size:12px;line-height:1.65;color:#8f96b8;margin:17px 0 20px}
#screenNav{display:grid;gap:5px}
.nav-btn{width:100%;border:0;border-left:3px solid transparent;background:transparent;color:#aeb4d1;text-align:left;padding:8px 10px;cursor:pointer;border-radius:4px;font-size:12px}
.nav-btn:hover{background:#252943;color:white}.nav-btn.active{background:#333a60;color:#fff8cd;border-left-color:var(--gold)}
.nav-btn b{display:inline-block;width:47px;color:#707898;font-size:10px}
.legend{font-size:11px;line-height:1.8;color:#737b9d;margin-top:24px}.legend i{display:inline-block;width:7px;height:7px;background:var(--green);border-radius:50%;margin-right:6px}.legend span{margin-left:13px}
.device-stage{display:flex;flex-direction:column;align-items:center;justify-content:center;min-width:0;min-height:0;padding:18px}
.stage-meta{width:min(calc((100vh - 105px)*750/1334),750px);display:flex;justify-content:space-between;align-items:end;margin-bottom:10px;color:#aeb4d1}
.stage-meta div{display:flex;align-items:baseline;gap:12px}.stage-meta strong{color:#fff;font-size:15px}.stage-meta span{font-size:10px;color:var(--gold);letter-spacing:1px}.stage-meta p{font-size:11px;margin:0}
.phone-frame{height:calc(100vh - 105px);aspect-ratio:750/1334;padding:6px;background:#080a13;border:1px solid #4f567a;border-radius:19px;box-shadow:0 25px 70px #050611}
.phone{position:relative;width:100%;height:100%;overflow:hidden;background:#141b2d;border-radius:13px;container-type:size;image-rendering:pixelated;isolation:isolate}
.game-screen{position:absolute;inset:0;overflow:hidden;background:#18223a;color:white;--s:calc(100cqw / 750)}
.game-screen img{image-rendering:pixelated;user-select:none;pointer-events:none}
.safe-top{position:absolute;left:24px;right:24px;top:22px;height:72px;z-index:50;display:flex;align-items:flex-start;justify-content:space-between}
.currency{display:flex;align-items:center;min-width:118px;height:52px;padding:0 18px 0 48px;border:5px solid #11162c;border-radius:13px;background:#403e51;box-shadow:inset 0 -6px #26283d,0 4px 0 #11162c;font-size:25px;font-weight:1000;color:#fff3b2;position:relative}
.currency:before{content:"";position:absolute;left:9px;width:28px;height:28px;background:var(--gold);border:4px solid #11162c;transform:rotate(45deg);box-shadow:inset -4px -4px #e4912f}
.top-actions{display:flex;gap:11px;align-items:center}.auto{height:50px;padding:0 15px;border:5px solid #11162c;border-radius:11px;color:white;background:#4f5369;font-size:19px;font-weight:1000;box-shadow:inset 0 -6px #34364d}.auto.on{background:#4e8a51;box-shadow:inset 0 -6px #2d6034}.pause{width:53px;height:53px;border:5px solid #11162c;border-radius:12px;background:#45495e url('../assets/original/hud/sharedassets3__pause_icon.png') center/24px no-repeat;box-shadow:inset 0 -6px #292c43}
.scene{position:absolute;inset:0;overflow:hidden}.scene-back{position:absolute;width:100%;height:100%;object-fit:cover;object-position:center top;filter:saturate(.82) brightness(.73)}.scene-front{position:absolute;left:0;bottom:160px;width:100%;height:56%;object-fit:cover;object-position:center bottom;opacity:.92}
.vignette{position:absolute;inset:0;background:linear-gradient(#090b18aa 0,transparent 19%,transparent 64%,#0b0e1ee8 88%,#0b0e1e 100%);pointer-events:none}
.floor-track{position:absolute;z-index:30;right:18px;top:126px;width:62px;height:580px;display:flex;flex-direction:column;align-items:center}.floor-label{font-size:15px;font-weight:1000;text-shadow:3px 3px #11162c;white-space:nowrap}.track-line{position:relative;width:18px;flex:1;margin:9px 0;background:#22263d;border:4px solid #0d1122;border-radius:12px;box-shadow:inset 0 0 0 3px #5b6079}.track-fill{position:absolute;left:3px;right:3px;bottom:3px;height:42%;background:linear-gradient(#ffca42,#e85c32);border-radius:8px}.track-dot{position:absolute;left:50%;top:52%;width:34px;height:34px;transform:translate(-50%,-50%);border:5px solid #11162c;border-radius:50%;background:#f0e0b2}.boss-medal{width:58px;height:58px;border:5px solid #11162c;border-radius:50%;background:#822b31 url('../assets/original/board/sharedassets3__ingame_boss_icon.png') center/37px no-repeat;box-shadow:0 4px #11162c}
.board-loop{position:absolute;z-index:12;left:106px;top:207px;width:516px;height:516px;transform:rotate(45deg);border:43px solid rgba(18,21,38,.86);border-radius:34px;box-shadow:0 0 0 7px #11162c,0 18px 30px #060811aa,inset 0 0 0 7px #6a5c53}
.board-center{position:absolute;inset:59px;background:#55272e;border:6px solid #11162c;border-radius:24px;box-shadow:inset 0 0 0 8px #8d4837;overflow:hidden}.center-lava{position:absolute;inset:-20%;background:radial-gradient(circle,#ffad36 0 6%,#c84d34 7% 25%,#472534 26% 63%,#1c2038 64%)}
.boss{position:absolute;z-index:3;left:50%;top:49%;width:210px;transform:translate(-50%,-50%) rotate(-45deg);filter:drop-shadow(0 10px 0 #11162c)}
.tile{position:absolute;width:78px;height:78px;transform:rotate(-45deg);filter:drop-shadow(0 5px 0 #11162c)}.tile img{width:100%;height:100%;object-fit:contain}.tile.good{filter:drop-shadow(0 0 12px #ffe96b) drop-shadow(0 5px 0 #11162c)}
.t1{left:-18px;top:-18px}.t2{left:95px;top:-39px}.t3{left:207px;top:-39px}.t4{left:319px;top:-39px}.t5{right:-18px;top:-18px}.t6{right:-39px;top:95px}.t7{right:-39px;top:207px}.t8{right:-39px;top:319px}.t9{right:-18px;bottom:-18px}.t10{left:319px;bottom:-39px}.t11{left:207px;bottom:-39px}.t12{left:95px;bottom:-39px}.t13{left:-18px;bottom:-18px}.t14{left:-39px;top:319px}.t15{left:-39px;top:207px}.t16{left:-39px;top:95px}
.hero-token{position:absolute;z-index:18;left:133px;top:542px;width:118px;filter:drop-shadow(0 8px 0 #11162c)}
.bottom-hud{position:absolute;z-index:45;left:20px;right:20px;bottom:22px;height:235px;display:grid;grid-template-columns:100px 1fr 100px;grid-template-rows:62px 100px 67px;gap:3px 13px;align-items:center}.hp-wrap{grid-column:1/4;display:flex;align-items:center;gap:12px}.level-badge{width:56px;height:56px;display:grid;place-items:center;border:5px solid #11162c;border-radius:50%;background:#e6d8a9;color:#20223d;font-weight:1000;font-size:22px}.hp-bar{height:39px;flex:1;border:6px solid #11162c;border-radius:12px;background:#351f32;position:relative;overflow:hidden}.hp-fill{height:100%;width:74%;background:linear-gradient(#e35b54,#b9343d);box-shadow:inset 0 -7px #8d2636}.hp-text{position:absolute;inset:0;display:grid;place-items:center;font-size:18px;font-weight:1000;text-shadow:2px 2px #11162c}.side-btn{width:92px;height:92px;border:6px solid #11162c;border-radius:19px;background:#41455e;color:#fff;box-shadow:inset 0 -10px #292c44,0 5px #11162c;font-size:13px;font-weight:1000}.map-btn{grid-row:2}.map-btn:before{content:"MAP"}.potion{grid-column:3;grid-row:2;position:relative}.potion img{width:65px;height:65px;object-fit:contain}.potion em{position:absolute;right:-3px;bottom:-5px;width:31px;height:31px;display:grid;place-items:center;background:#f4e6bd;border:4px solid #11162c;border-radius:50%;color:#1f2338;font-style:normal;font-weight:1000}
.slots{grid-column:2;grid-row:2;display:grid;grid-template-columns:repeat(4,1fr);gap:7px}.slot{height:92px;border:6px solid #11162c;border-radius:13px;background:linear-gradient(#4b4e69,#2e314b);box-shadow:inset 0 -8px #23263e;position:relative;display:grid;place-items:center}.slot b{position:absolute;left:5px;top:2px;color:#f2e3b2;font-size:15px;text-shadow:2px 2px #11162c}.slot img{max-width:62px;max-height:72px;object-fit:contain}.slot.ring:after{content:"◆";font-size:44px;color:#8fd5dd;text-shadow:4px 4px #11162c}.slot.boot:after{content:"L";font-size:49px;font-weight:1000;color:#d59963;text-shadow:4px 4px #11162c;transform:skew(-8deg)}
.primary{grid-column:1/4;grid-row:3;height:66px;border:6px solid #11162c;border-radius:18px;background:linear-gradient(#ffd75b,#f28b2d);box-shadow:inset 0 -10px #ca5e2a,0 6px #11162c;color:#fff8d6;text-shadow:4px 4px #812e30;font-size:31px;font-weight:1000;letter-spacing:1px}.primary.disabled{filter:grayscale(.65);opacity:.8}.primary.danger{background:linear-gradient(#f67a5c,#b73342);box-shadow:inset 0 -10px #7f2333,0 6px #11162c}.primary.green{background:linear-gradient(#8ce26e,#45a853);box-shadow:inset 0 -10px #33753b,0 6px #11162c}
.toast{position:absolute;z-index:80;left:50%;top:112px;transform:translateX(-50%);min-width:470px;padding:16px 26px;background:#282b42e8;border:5px solid #11162c;border-radius:16px;text-align:center;font-weight:1000;font-size:23px;box-shadow:0 8px #11162c}.toast small{display:block;color:#ffd85a;margin-top:5px;font-size:15px}
.dice-result{position:absolute;z-index:70;left:50%;top:270px;transform:translateX(-50%);display:flex;gap:35px}.dice-result img{width:125px;filter:drop-shadow(0 9px 0 #11162c)}.dice-sum{position:absolute;left:50%;top:420px;transform:translateX(-50%);font-size:65px;font-weight:1000;color:#fff5c0;text-shadow:6px 6px #4f2430}
.modal-dim{position:absolute;z-index:55;inset:0;background:#080b18b8;backdrop-filter:blur(1px)}.modal{position:absolute;z-index:60;left:54px;right:54px;top:155px;bottom:254px;border:7px solid #11162c;border-radius:26px;background:linear-gradient(#3d405c,#272a43);box-shadow:inset 0 0 0 6px #77728a,0 14px #080b18;overflow:hidden;padding:30px}.modal-title{font-size:35px;font-weight:1000;text-align:center;color:#fff4c2;text-shadow:5px 5px #7b3340;margin:0 0 10px}.modal-copy{text-align:center;color:#d7d4c4;font-size:18px;line-height:1.45;margin:0}.choice-row{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:39px}.choice{height:245px;border:6px solid #11162c;border-radius:17px;background:linear-gradient(#68567a,#34364e);color:white;position:relative;padding:125px 10px 10px;text-align:center;box-shadow:inset 0 -10px #272a42}.choice img{position:absolute;left:50%;top:27px;transform:translateX(-50%);width:91px;height:91px;object-fit:contain}.choice b{display:block;color:#ffe271;font-size:21px}.choice span{font-size:13px;color:#cfd2e1}.choice.selected{outline:7px solid #ffd85c;transform:translateY(-6px)}
.event-stage{position:absolute;z-index:20;left:24px;right:88px;top:102px;bottom:262px;border:7px solid #11162c;border-radius:23px;background:linear-gradient(#303550,#1e2239);box-shadow:inset 0 0 0 5px #585b70;overflow:hidden}.event-title{position:absolute;z-index:8;left:50%;top:20px;transform:translateX(-50%);min-width:390px;padding:13px 25px;border:6px solid #11162c;border-radius:14px;background:#4e3e50;text-align:center;font-size:31px;font-weight:1000;color:#fff1b7;text-shadow:4px 4px #722f3c}.event-sub{position:absolute;z-index:8;left:60px;right:60px;top:88px;text-align:center;font-size:16px;color:#ddd8c2}.event-art{position:absolute;left:50%;top:52%;max-width:94%;max-height:66%;transform:translate(-50%,-50%);object-fit:contain;filter:drop-shadow(0 10px 0 #11162c88)}.event-count{position:absolute;z-index:9;left:50%;bottom:22px;transform:translateX(-50%);padding:7px 18px;border:5px solid #11162c;border-radius:14px;background:#f2e2b6;color:#282a43;font-size:19px;font-weight:1000}
.battle-stage{position:absolute;z-index:15;left:24px;right:84px;top:102px;bottom:262px;overflow:hidden}.battle-progress{position:absolute;left:45px;right:32px;top:22px;height:52px;border:6px solid #11162c;border-radius:19px;background:#2d3047;overflow:hidden}.team-fill{height:100%;width:58%;background:linear-gradient(90deg,#4ab4b9,#77d6d5);border-right:6px solid #11162c}.vs{position:absolute;left:54%;top:-4px;width:58px;height:58px;display:grid;place-items:center;transform:translateX(-50%);border:6px solid #11162c;border-radius:50%;background:#f1dca7;color:#34354d;font-weight:1000}.fighter{position:absolute;filter:drop-shadow(0 12px 0 #11162c)}.fighter.hero{left:31px;bottom:128px;width:225px}.fighter.enemy{right:34px;bottom:117px;width:315px;transform:scaleX(-1)}.damage{position:absolute;right:83px;top:285px;font-size:49px;font-weight:1000;color:#fff1a5;text-shadow:5px 5px #8b2d39;transform:rotate(-7deg)}.drop{position:absolute;right:22px;bottom:70px;width:90px;height:90px;border:6px solid #11162c;border-radius:15px;background:#72549b;display:grid;place-items:center;box-shadow:0 0 22px #d8adff}.drop img{max-width:62px;max-height:70px}
.compare{position:absolute;z-index:63;left:38px;right:88px;top:112px;display:grid;gap:14px}.gear-panel{height:210px;border:7px solid #11162c;border-radius:20px;background:#343650;box-shadow:inset 0 -12px #24273e;display:grid;grid-template-columns:164px 1fr;padding:18px}.gear-panel.new{outline:5px solid #ffd95d}.gear-icon{height:164px;border:6px solid #11162c;border-radius:15px;background:#6e4f92;display:grid;place-items:center;position:relative}.gear-icon img{max-width:105px;max-height:140px}.gear-icon b{position:absolute;left:8px;top:5px;font-size:25px}.gear-stats{padding:4px 20px}.gear-stats h3{margin:0 0 10px;color:#fff0ad;font-size:24px}.stat{height:40px;display:flex;justify-content:space-between;border-bottom:2px solid #555a70;align-items:center}.up{color:#69dd79}.down{color:#ff6d68}
.shop-stage{position:absolute;z-index:20;left:24px;right:88px;top:105px;bottom:262px;border:7px solid #11162c;border-radius:23px;background:#262a43;overflow:hidden}.shop-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.shop-master{position:absolute;right:4px;top:43px;height:288px}.shop-title{position:absolute;left:50%;top:17px;transform:translateX(-50%);font-size:35px;font-weight:1000;color:#fff1b5;text-shadow:4px 4px #772f3b}.goods{position:absolute;left:27px;right:27px;bottom:42px;display:grid;grid-template-columns:repeat(3,1fr);gap:14px}.good-card{height:184px;border:6px solid #11162c;border-radius:15px;background:#f0dfb3;color:#2a2c43;padding:9px;text-align:center;box-shadow:inset 0 -9px #c29f72;position:relative}.good-card .good-icon{height:92px;display:grid;place-items:center}.good-card img{max-height:86px;max-width:82px}.good-card b{display:block;font-size:16px}.price{position:absolute;left:10px;right:10px;bottom:8px;border:4px solid #11162c;border-radius:8px;background:#4a4960;color:#ffdf68;font-weight:1000;padding:4px}.sold{filter:grayscale(1);opacity:.55}.sold:after{content:"SOLD";position:absolute;inset:58px 8px auto;transform:rotate(-13deg);font-size:31px;color:#b12d3c;font-weight:1000;text-shadow:2px 2px #fff0c0}
.dig-grid{position:absolute;z-index:5;left:93px;right:93px;top:145px;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:5px}.dig-cell{min-width:0;width:100%;padding:0;overflow:hidden;aspect-ratio:1;border:4px solid #11162c;background:#8f603e;position:relative}.dig-cell img{width:100%;height:100%;object-fit:cover}.dig-cell.open{background:#3d2e31;box-shadow:inset 0 0 0 6px #261f2b}.dig-cell.dig-reward:after{content:"◆";position:absolute;inset:0;display:grid;place-items:center;color:#ffe05c;font-size:38px;text-shadow:3px 3px #7b313e}
.bubble-field{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.bubble-pack{position:absolute;left:75px;right:75px;top:135px;display:flex;flex-wrap:wrap;justify-content:center}.bubble-ball{width:58px;height:58px;margin:-2px 2px;border:5px solid #11162c;border-radius:50%;background:#e85d57;box-shadow:inset -8px -8px #9d303d}.bubble-ball:nth-child(3n){background:#52b7d0;box-shadow:inset -8px -8px #2e758d}.bubble-ball:nth-child(3n+1){background:#f0cc50;box-shadow:inset -8px -8px #a67a2f}.cannon{position:absolute;left:50%;bottom:38px;width:116px;transform:translateX(-50%);filter:drop-shadow(0 7px #11162c)}
.machine{position:absolute;left:50%;top:155px;transform:translateX(-50%);width:430px;filter:drop-shadow(0 12px 0 #11162c)}.machine-screen{position:absolute;z-index:2;left:50%;top:267px;transform:translateX(-50%);width:260px;display:flex;justify-content:center;gap:10px}.machine-screen img{width:70px}.lotto-layer{position:absolute;left:50%;top:58%;transform:translate(-50%,-50%);max-width:87%;max-height:62%;filter:drop-shadow(0 10px #11162c)}
.bless-cards{position:absolute;left:36px;right:36px;top:145px;display:grid;grid-template-columns:repeat(3,1fr);gap:14px}.bless-card{height:376px;border:6px solid #11162c;border-radius:22px;background:#574a68;padding:18px 10px;text-align:center;box-shadow:inset 0 -12px #302d46}.bless-card img{width:118px;height:175px;object-fit:contain}.bless-card b{display:block;color:#ffe36e;font-size:19px}.bless-card p{font-size:13px;color:#ddd9c9}.bless-card.pick{outline:6px solid #ffdb5d;transform:translateY(-8px)}
.revive-card{position:absolute;z-index:63;left:70px;right:70px;top:217px;padding:36px 30px 31px;border:8px solid #11162c;border-radius:29px;background:linear-gradient(#55536d,#292c45);box-shadow:inset 0 0 0 7px #8d8192,0 16px #080b18;text-align:center}.revive-card h2{font-size:43px;color:#fff0b3;text-shadow:5px 5px #792f3b;margin:0 0 13px}.revive-card p{font-size:19px;line-height:1.55;color:#dedac9}.revive-card .countdown{font-size:25px;color:#ffcc55;font-weight:1000}.revive-actions{display:grid;grid-template-columns:1fr 1fr;gap:15px;margin-top:22px}.small-action{height:75px;border:6px solid #11162c;border-radius:16px;background:#4d526c;color:#fff;font-size:20px;font-weight:1000;box-shadow:inset 0 -9px #30344d}.small-action.ad{background:#d58033;box-shadow:inset 0 -9px #95472d}
.result-screen{background:#171a2c}.result-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.result-knight{position:absolute;left:50%;top:265px;width:380px;transform:translateX(-50%);filter:drop-shadow(0 14px #11162c)}.result-title{position:absolute;left:0;right:0;top:125px;text-align:center;font-size:57px;color:#fff0a8;text-shadow:7px 7px #7d2e3c;font-weight:1000}.reward-row{position:absolute;left:75px;right:75px;bottom:290px;display:flex;justify-content:center;gap:19px}.reward{width:120px;height:120px;border:7px solid #11162c;border-radius:18px;background:#423f57;display:grid;place-items:center;color:#ffe372;font-size:29px;font-weight:1000;box-shadow:inset 0 -12px #282b42}.result-button{position:absolute;left:55px;right:55px;bottom:93px;height:78px;border:7px solid #11162c;border-radius:19px;background:linear-gradient(#ffd45a,#e9822f);color:#fff8cf;text-shadow:4px 4px #822f34;font-size:29px;font-weight:1000;box-shadow:inset 0 -10px #b64f29,0 7px #11162c}
.pause-panel{position:absolute;z-index:65;left:70px;right:70px;top:200px;padding:35px;border:8px solid #11162c;border-radius:28px;background:#3e415a;box-shadow:inset 0 0 0 6px #737184,0 15px #080b18}.pause-panel h2{text-align:center;color:#fff0b2;font-size:40px;margin:0 0 24px;text-shadow:5px 5px #782e3c}.pause-panel button{width:100%;height:78px;margin:8px 0;border:6px solid #11162c;border-radius:16px;background:#5b6077;color:white;font-size:23px;font-weight:1000;box-shadow:inset 0 -9px #34374f}.pause-panel button:first-of-type{background:#56ad60;box-shadow:inset 0 -9px #34703c}.pause-panel button:last-of-type{color:#ff9b8c}
.floor-up{position:absolute;z-index:70;left:60px;right:60px;top:212px;padding:30px;border:7px solid #11162c;border-radius:25px;background:#343751ee;box-shadow:0 14px #080b18;text-align:center}.floor-up h2{font-size:39px;color:#fff0ad;margin:0 0 18px;text-shadow:5px 5px #7a2f3c}.floor-up ul{text-align:left;margin:0 auto;width:82%;font-size:20px;line-height:1.7;color:#e1dcc6}.floor-up li::marker{color:#ffd559}
.tap-hint{position:absolute;z-index:90;left:50%;bottom:260px;transform:translateX(-50%);font-size:14px;color:#d4d7e8;animation:pulse 1.5s infinite}@keyframes pulse{50%{opacity:.45}}
@media(max-width:920px){.workbench{grid-template-columns:1fr}.navigator,.stage-meta{display:none}.device-stage{padding:0}.phone-frame{height:100vh;max-width:100vw;border:0;border-radius:0;padding:0}.phone{border-radius:0}}
body.capture .workbench{display:block;background:#000}body.capture .navigator,body.capture .stage-meta{display:none}body.capture .device-stage{padding:0;display:block}body.capture .phone-frame{width:750px;height:1334px;padding:0;border:0;border-radius:0}body.capture .phone{border-radius:0}