GG / index.html
Mycc's picture
Update index.html
2e74d41 verified
Raw History Blame Contribute Delete
118 kB
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Святилище Роновы — Genshin Roulette</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/cormorant@latest/cyrillic-500-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/cormorant@latest/cyrillic-700-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/cormorant@latest/latin-500-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/cormorant@latest/latin-700-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/cormorant-unicase@latest/cyrillic-700-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/cormorant-unicase@latest/latin-700-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/cyrillic-400-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/cyrillic-500-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/cyrillic-600-normal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-400-normal.css">
<style>
:root{
--void:#000000; --obsidian:#0D0D0D; --obsidian2:#121214;
--crimson:#A30000; --ember:#C41E2F; --flame:#FF3040; --flame-soft:rgba(255,48,64,.55);
--platinum:#E5E5E5; --silver:#B3B3B3; --dim:#7d7d82; --faint:#4a4a50;
--line:rgba(160,160,170,.13); --line-red:rgba(163,0,0,.5);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--void);color:var(--platinum);font-family:'Inter',ui-sans-serif,system-ui,sans-serif;min-height:100vh;overflow-x:hidden;}
body.dimmed #app-root{opacity:.35;filter:saturate(.6);transition:all .3s;}
.f-display{font-family:'Cormorant Unicase','Cormorant',serif;letter-spacing:.14em;text-transform:uppercase;}
.f-serif{font-family:'Cormorant',serif;}
::selection{background:rgba(163,0,0,.55);color:#fff;}
/* ==================== БЕЗДНА: ФОН ==================== */
.abyss{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none;background:radial-gradient(ellipse at 50% 55%,#0a0507 0%,#000 72%);}
.abyss-glow{position:absolute;inset:0;background:radial-gradient(900px 620px at 50% 58%,rgba(163,0,0,.16),transparent 62%),radial-gradient(500px 340px at 50% 58%,rgba(196,30,47,.09),transparent 70%);animation:abyssBreath 9s ease-in-out infinite;}
@keyframes abyssBreath{0%,100%{opacity:.75;transform:scale(1);}50%{opacity:1;transform:scale(1.06);}}
.abyss-rings{position:absolute;left:50%;top:58%;width:0;height:0;will-change:transform;}
.abyss-rings svg{position:absolute;left:50%;top:50%;}
.ring-a{width:min(92vmin,880px);height:min(92vmin,880px);margin:calc(min(92vmin,880px)/-2) 0 0 calc(min(92vmin,880px)/-2);animation:spin 160s linear infinite;opacity:.10;}
.ring-b{width:min(64vmin,620px);height:min(64vmin,620px);margin:calc(min(64vmin,620px)/-2) 0 0 calc(min(64vmin,620px)/-2);animation:spinRev 110s linear infinite;opacity:.12;}
.ring-c{width:min(38vmin,380px);height:min(38vmin,380px);margin:calc(min(38vmin,380px)/-2) 0 0 calc(min(38vmin,380px)/-2);animation:spin 70s linear infinite;opacity:.08;}
@keyframes spin{to{transform:rotate(360deg);}}
@keyframes spinRev{to{transform:rotate(-360deg);}}
#ember-canvas{position:fixed;inset:0;z-index:1;pointer-events:none;}
#eyes-layer{position:fixed;inset:0;z-index:3;pointer-events:none;}
/* ==================== ОЧИ БЕЗДНЫ ==================== */
.abyss-eye{position:absolute;pointer-events:none;opacity:.22;transition:opacity .3s;will-change:transform,opacity;}
/* ==================== ЗЕРНО ==================== */
.grain{position:fixed;inset:-100%;z-index:2000;pointer-events:none;opacity:.05;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");animation:grainMove 7s steps(10) infinite;}
@keyframes grainMove{0%{transform:translate(0,0)}10%{transform:translate(-5%,-8%)}20%{transform:translate(-12%,3%)}30%{transform:translate(6%,-14%)}40%{transform:translate(-4%,12%)}50%{transform:translate(-10%,6%)}60%{transform:translate(12%,0)}70%{transform:translate(0,10%)}80%{transform:translate(3%,14%)}90%{transform:translate(-8%,8%)}100%{transform:translate(0,0)}}
/* ==================== ВУАЛЬ ПРИЗЫВА ==================== */
#summon-veil{position:fixed;inset:0;z-index:1500;pointer-events:none;opacity:0;transition:opacity .3s ease;background:radial-gradient(circle at 50% 50%,rgba(120,0,8,.35) 0%,rgba(0,0,0,.97) 62%);display:flex;align-items:center;justify-content:center;}
#summon-veil.active{opacity:1;}
.veil-pupil{width:170px;height:170px;border-radius:50%;background:#000;box-shadow:0 0 60px 30px rgba(163,0,0,.55),0 0 140px 90px rgba(0,0,0,.9);}
#summon-veil.active .veil-pupil{animation:pupilClose .62s cubic-bezier(.6,0,.4,1) forwards;}
@keyframes pupilClose{0%{transform:scale(.15);}45%{transform:scale(1);}100%{transform:scale(.04);opacity:.9;}}
/* ==================== ТРИКВЕТР ==================== */
.tq{display:inline-block;color:var(--silver);}
.divider{display:flex;align-items:center;gap:12px;margin:14px auto 10px;max-width:380px;}
.divider .d-line{flex:1;height:1px;background:linear-gradient(90deg,transparent,rgba(160,160,170,.4),transparent);}
.divider .tq{width:18px;height:18px;color:var(--ember);filter:drop-shadow(0 0 5px rgba(196,30,47,.6));animation:tqPulse 3.2s ease-in-out infinite;}
@keyframes tqPulse{0%,100%{opacity:.6;transform:scale(1) rotate(0deg);}50%{opacity:1;transform:scale(1.12) rotate(8deg);}}
/* ==================== ПАНЕЛИ ==================== */
.panel{background:rgba(13,13,13,.78);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border:1px solid var(--line);border-radius:6px;position:relative;box-shadow:0 18px 50px rgba(0,0,0,.65),inset 0 1px 0 rgba(255,255,255,.04);}
.panel::before{content:"";position:absolute;inset:0;pointer-events:none;border-radius:6px;background-image:linear-gradient(var(--ember),var(--ember)),linear-gradient(var(--ember),var(--ember)),linear-gradient(var(--ember),var(--ember)),linear-gradient(var(--ember),var(--ember)),linear-gradient(var(--ember),var(--ember)),linear-gradient(var(--ember),var(--ember)),linear-gradient(var(--ember),var(--ember)),linear-gradient(var(--ember),var(--ember));background-repeat:no-repeat;background-position:top left,top left,top right,top right,bottom left,bottom left,bottom right,bottom right;background-size:20px 1px,1px 20px,20px 1px,1px 20px,20px 1px,1px 20px,20px 1px,1px 20px;opacity:.55;}
.modal-panel{background:rgba(13,13,13,.72);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);border:1px solid rgba(163,0,0,.35);border-radius:6px;box-shadow:0 24px 80px rgba(0,0,0,.8),0 0 60px rgba(163,0,0,.12),inset 0 1px 0 rgba(255,255,255,.04);}
/* ==================== SIDEBAR ==================== */
.sidebar{position:fixed;left:0;top:0;bottom:0;width:282px;z-index:50;background:linear-gradient(180deg,rgba(10,10,11,.94),rgba(6,6,7,.96));backdrop-filter:blur(12px);border-right:1px solid var(--line);display:flex;flex-direction:column;transition:transform .3s ease;}
.sidebar::after{content:"";position:absolute;top:0;right:-1px;bottom:0;width:1px;background:linear-gradient(180deg,transparent,rgba(163,0,0,.55) 30%,rgba(163,0,0,.55) 70%,transparent);}
.sidebar-nav{flex-grow:1;overflow-y:auto;padding:20px 16px;}
.sidebar-nav::-webkit-scrollbar{width:4px}
.sidebar-nav::-webkit-scrollbar-thumb{background:#3a0a0e;border-radius:2px}
/* --- ЖИВОЙ ЛОГОТИП (БОЛЬШОЙ) --- */
.brand{padding:30px 20px 26px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:18px;cursor:default;position:relative;overflow:hidden;}
.brand::after{content:"";position:absolute;bottom:-40px;left:50%;transform:translateX(-50%);width:300px;height:80px;background:radial-gradient(ellipse,rgba(163,0,0,.3),transparent 70%);pointer-events:none;}
.brand-sigil{width:104px;height:104px;flex-shrink:0;color:var(--ember);filter:drop-shadow(0 0 16px rgba(196,30,47,.6));transition:filter .4s,transform .5s;}
.brand:hover .brand-sigil{filter:drop-shadow(0 0 28px rgba(255,48,64,.95));transform:scale(1.04);}
.brand-sigil svg{width:100%;height:100%;overflow:visible;}
.sg-ringA{animation:spin 40s linear infinite;transform-origin:60px 60px;}
.sg-ringB{animation:spinRev 26s linear infinite;transform-origin:60px 60px;}
.sg-tq{animation:tqGlow 3.5s ease-in-out infinite, spin 60s linear infinite;transform-origin:60px 60px;}
@keyframes tqGlow{0%,100%{opacity:.7;}50%{opacity:1;}}
.sg-eye{animation:sgBlink 7s infinite;transform-origin:60px 60px;}
@keyframes sgBlink{0%,90%,100%{transform:scaleY(1);}93%{transform:scaleY(.05);}96%{transform:scaleY(1);}}
.sg-iris{animation:irisPulse 3s ease-in-out infinite;}
@keyframes irisPulse{0%,100%{opacity:.85;}50%{opacity:1;}}
.brand-text h1{margin:0;font-family:'Cormorant Unicase',serif;font-weight:700;font-size:1.5rem;letter-spacing:.3em;color:var(--platinum);text-shadow:0 0 18px rgba(196,30,47,.5);}
.brand-text p{margin:4px 0 0;font-family:'Cormorant Unicase',serif;font-size:.95rem;letter-spacing:.5em;color:var(--flame);text-shadow:0 0 10px rgba(255,48,64,.6);animation:tqGlow 3s ease-in-out infinite;}
.sidebar-section{margin-bottom:26px;}
.sidebar-section-title{font-family:'Cormorant Unicase',serif;font-size:.62rem;letter-spacing:.3em;color:var(--dim);text-transform:uppercase;margin-bottom:12px;padding:0 6px;display:flex;align-items:center;gap:10px;}
.sidebar-section-title::before,.sidebar-section-title::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,transparent,var(--line),transparent);}
/* ==================== КНОПКИ ==================== */
.btn-metal{position:relative;display:flex;align-items:center;justify-content:center;gap:10px;width:100%;padding:11px 14px;margin-bottom:6px;background:linear-gradient(180deg,#17171a,#0b0b0d);border:1px solid #2a2a2e;border-radius:3px;color:#c9c9cf;font-family:'Inter',sans-serif;font-size:.85rem;font-weight:500;letter-spacing:.04em;cursor:pointer;transition:all .22s ease;text-align:center;box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 2px 8px rgba(0,0,0,.5);}
.btn-metal svg{width:17px;height:17px;flex-shrink:0;opacity:.8;}
.btn-metal:hover{border-color:rgba(196,30,47,.55);color:#fff;box-shadow:inset 0 0 14px rgba(163,0,0,.22),0 0 14px rgba(163,0,0,.2);}
.btn-metal:active{transform:translateY(1px);}
.btn-metal.active{background:linear-gradient(180deg,#1d060a,#0c0204);border-color:rgba(255,48,64,.45);color:#ffb3b8;box-shadow:inset 0 0 16px rgba(163,0,0,.35),0 0 16px rgba(163,0,0,.22);}
.btn-metal.active::after{content:"";position:absolute;bottom:-1px;left:14%;right:14%;height:1px;background:linear-gradient(90deg,transparent,var(--flame),transparent);box-shadow:0 0 8px var(--flame-soft);animation:tqGlow 2s ease-in-out infinite;}
.btn-metal.flash{animation:btnFlash .4s ease;}
@keyframes btnFlash{0%{box-shadow:0 0 0 rgba(255,48,64,0);}30%{box-shadow:0 0 26px rgba(255,48,64,.8),inset 0 0 20px rgba(255,48,64,.4);}100%{box-shadow:0 0 0 rgba(255,48,64,0);}}
.mode-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;}
.mode-grid .btn-metal,.type-grid .btn-metal{padding:10px 4px;font-size:.72rem;letter-spacing:.06em;margin-bottom:0;font-family:'Cormorant Unicase',serif;font-weight:700;}
.type-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;}
.rv-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:'Cormorant Unicase',serif;text-transform:uppercase;letter-spacing:.2em;font-weight:700;background:linear-gradient(180deg,#17171a,#0a0a0c);color:#d5d5da;border:1px solid #2c2c30;border-radius:3px;padding:11px 22px;font-size:.8rem;cursor:pointer;transition:all .25s ease;overflow:hidden;box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 3px 10px rgba(0,0,0,.55);}
.rv-btn:hover{border-color:rgba(196,30,47,.6);color:#fff;box-shadow:inset 0 0 16px rgba(163,0,0,.25),0 0 18px rgba(163,0,0,.28);transform:translateY(-1px);}
.rv-btn-danger{border-color:#3a0a0e;color:#e08a90;background:linear-gradient(180deg,#1a0508,#0d0204);}
.rv-btn-danger:hover{color:#ff8b93;border-color:var(--flame);box-shadow:0 0 18px rgba(255,48,64,.35);}
.rv-btn-sm{padding:8px 16px;font-size:.68rem;}
.rv-btn:disabled{opacity:.5;cursor:not-allowed;transform:none;}
.rv-iconbtn{width:38px;height:38px;border-radius:3px;display:inline-flex;align-items:center;justify-content:center;background:linear-gradient(180deg,#161618,#0b0b0d);border:1px solid #2a2a2e;color:var(--silver);cursor:pointer;transition:all .25s;font-size:1.1rem;}
.rv-iconbtn:hover{border-color:rgba(196,30,47,.6);color:var(--flame);box-shadow:0 0 14px rgba(163,0,0,.3);}
.rv-iconbtn svg{width:17px;height:17px;}
.rv-input{width:100%;background:rgba(10,10,12,.8);border:1px solid #2a2a2e;border-radius:3px;padding:10px 14px;color:var(--platinum);font-family:'Inter',sans-serif;font-size:.85rem;transition:all .25s;}
.rv-input:focus{outline:none;border-color:rgba(255,48,64,.5);box-shadow:0 0 14px rgba(163,0,0,.25);}
select.rv-input option{background:#0d0d0f;color:var(--platinum);}
.rv-label{font-family:'Cormorant Unicase',serif;letter-spacing:.14em;text-transform:uppercase;color:var(--ember);font-weight:700;}
.rv-sub{color:var(--dim);}
/* ==================== ГЛАВНАЯ КНОПКА ==================== */
.summon-btn{position:relative;font-family:'Cormorant Unicase',serif;font-weight:700;font-size:1.25rem;letter-spacing:.34em;text-indent:.34em;color:#cfcfd4;padding:20px 64px;border-radius:4px;cursor:pointer;background:linear-gradient(180deg,#1c1c1f 0%,#0c0c0e 55%,#141416 100%);border:1px solid #333338;box-shadow:inset 0 1px 0 rgba(255,255,255,.07),inset 0 -6px 14px rgba(0,0,0,.7),0 10px 30px rgba(0,0,0,.75);text-shadow:0 1px 0 #000,0 0 8px rgba(180,180,190,.15);transition:color .3s,border-color .3s;}
.summon-btn .sx{display:inline-block;color:#6d6d74;transition:color .3s,text-shadow .3s;margin:0 6px;}
.summon-btn:hover{color:#fff;border-color:#5c0f14;animation:summonPulse 1.7s ease-in-out infinite;}
.summon-btn:hover .sx{color:var(--flame);text-shadow:0 0 14px rgba(255,48,64,.9);animation:sxSpin 1.2s linear infinite;}
@keyframes sxSpin{to{transform:rotate(180deg);}}
@keyframes summonPulse{0%,100%{box-shadow:inset 0 1px 0 rgba(255,255,255,.07),inset 0 0 18px rgba(163,0,0,.28),0 10px 30px rgba(0,0,0,.75),0 0 22px rgba(163,0,0,.22);}50%{box-shadow:inset 0 1px 0 rgba(255,255,255,.07),inset 0 0 30px rgba(163,0,0,.45),0 10px 30px rgba(0,0,0,.75),0 0 42px rgba(255,48,64,.4);}}
.summon-btn:active{transform:translateY(2px) scale(.99);}
.summon-btn:disabled{opacity:.55;cursor:wait;animation:none;}
.warn-msg{color:var(--flame);font-size:.8rem;text-align:center;margin-top:12px;min-height:1.2em;text-shadow:0 0 10px rgba(255,48,64,.4);}
/* ==================== MAIN ==================== */
.main-wrap{margin-left:282px;min-height:100vh;display:flex;flex-direction:column;position:relative;z-index:10;}
.topbar{display:none;padding:12px 18px;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line);background:rgba(8,8,9,.85);backdrop-filter:blur(10px);position:sticky;top:0;z-index:45;}
.main-content{flex-grow:1;padding:36px 40px;max-width:1120px;width:100%;margin:0 auto;}
.stage-head{text-align:center;margin-bottom:26px;}
.stage-title{font-family:'Cormorant Unicase',serif;font-weight:700;font-size:2rem;letter-spacing:.22em;text-transform:uppercase;color:var(--platinum);margin:0;text-shadow:0 0 26px rgba(163,0,0,.55);}
.stage-desc{color:var(--dim);font-size:.82rem;letter-spacing:.08em;margin:0;}
.pane{min-height:340px;display:flex;flex-direction:column;align-items:center;justify-content:center;}
.pane-empty{text-align:center;color:var(--faint);}
.pane-empty .tq{width:44px;height:44px;opacity:.4;animation:tqPulse 4s ease-in-out infinite;}
.pane-empty p{margin-top:14px;font-size:.85rem;letter-spacing:.1em;}
.stage-actions{display:flex;flex-direction:column;align-items:center;margin-top:30px;}
.pane-actions{display:flex;gap:12px;margin-top:22px;flex-wrap:wrap;justify-content:center;}
/* ==================== КАРТЫ ==================== */
.cards-row{display:flex;flex-wrap:wrap;justify-content:center;gap:16px;perspective:1200px;}
.gcard-wrap{perspective:1000px;transition:transform .25s ease;}
.gcard{position:relative;width:132px;height:188px;transform-style:preserve-3d;transition:transform .75s cubic-bezier(.35,.1,.3,1.1);}
.gcard-wrap.wide .gcard{width:min(600px,86vw);height:auto;min-height:320px;transition-duration:.9s;}
.gcard.flipped{transform:rotateY(180deg);}
.gcard.instant{transition:none;}
.gface{backface-visibility:hidden;-webkit-backface-visibility:hidden;border-radius:5px;overflow:hidden;}
.gface-rune{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:linear-gradient(155deg,#141416 0%,#08080a 45%,#101013 100%);border:1px solid #2c2c31;box-shadow:inset 0 0 30px rgba(0,0,0,.8),inset 0 1px 0 rgba(255,255,255,.06),0 8px 20px rgba(0,0,0,.6);}
.gface-rune::after{content:"";position:absolute;inset:0;background:linear-gradient(120deg,transparent 30%,rgba(255,255,255,.045) 46%,transparent 60%);pointer-events:none;}
.gface-rune .tq{width:56px;height:56px;color:#8a8e94;opacity:.9;filter:drop-shadow(0 0 7px rgba(150,150,160,.3));animation:tqPulse 3.5s ease-in-out infinite;}
.gface-rune .rune-x{font-family:'Cormorant Unicase',serif;color:#3d3d42;font-size:.85rem;letter-spacing:.5em;}
.gface-content{position:absolute;inset:0;transform:rotateY(180deg);background:linear-gradient(180deg,#101012,#0a0a0c);border:1px solid rgba(163,0,0,.4);box-shadow:inset 0 0 26px rgba(163,0,0,.12),0 8px 24px rgba(0,0,0,.6);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:12px;text-align:center;}
.gcard-wrap.wide .gface-rune{position:relative;}
.gcard-wrap.wide .gface-content{overflow-y:auto;}
.gcard-wrap.wide .gface-content::-webkit-scrollbar{width:5px}
.gcard-wrap.wide .gface-content::-webkit-scrollbar-thumb{background:#3a0a0e}
.gcard-wrap.pop-in{animation:cardPop .4s cubic-bezier(.3,1.4,.5,1) both;}
@keyframes cardPop{0%{opacity:0;transform:translateY(18px) scale(.85);}100%{opacity:1;transform:none;}}
.char-face-img{width:86px;height:86px;border-radius:50%;object-fit:cover;border:2px solid var(--ember);box-shadow:0 0 16px rgba(163,0,0,.5),inset 0 0 8px rgba(0,0,0,.6);margin-bottom:8px;}
.char-face-name{font-size:.72rem;font-weight:600;color:var(--platinum);width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:.03em;}
.char-face-el{display:flex;align-items:center;gap:5px;margin-top:5px;font-size:.6rem;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);}
.char-face-el img{width:13px;height:13px;border-radius:50%;}
.boss-face-img{width:112px;height:112px;border-radius:50%;object-fit:cover;border:2px solid var(--ember);box-shadow:0 0 22px rgba(163,0,0,.55);margin-bottom:10px;}
.boss-face-name{font-family:'Cormorant',serif;font-weight:700;font-size:.95rem;color:var(--platinum);line-height:1.3;}
.boss-face-hint{font-size:.62rem;color:var(--dim);letter-spacing:.14em;text-transform:uppercase;margin-top:7px;}
.player-group{width:100%;margin-bottom:22px;padding:18px 16px 20px;border:1px solid var(--line);border-radius:5px;background:linear-gradient(180deg,rgba(163,0,0,.05),rgba(163,0,0,.015));position:relative;}
.player-group::before{content:"";position:absolute;top:-1px;left:16px;right:16px;height:1px;background:linear-gradient(90deg,transparent,rgba(196,30,47,.7),transparent);}
.player-group-title{font-family:'Cormorant Unicase',serif;text-align:center;letter-spacing:.3em;text-transform:uppercase;font-size:.72rem;color:var(--ember);margin-bottom:14px;font-weight:700;}
.player-group-title.host{color:#d4af37;text-shadow:0 0 12px rgba(212,175,55,.4);}
/* ==================== КОНТРАКТ ==================== */
.contract{width:100%;padding:10px 6px;text-align:center;}
.contract-level{display:inline-flex;align-items:center;gap:10px;font-family:'Cormorant Unicase',serif;font-size:.68rem;letter-spacing:.3em;text-transform:uppercase;color:var(--silver);margin-bottom:14px;}
.contract-level .lvl{padding:3px 12px;border:1px solid var(--line-red);border-radius:2px;color:var(--flame);background:rgba(163,0,0,.12);}
.contract-name{font-family:'Cormorant',serif;font-weight:700;font-size:1.7rem;color:var(--platinum);margin:0 0 10px;text-shadow:0 0 22px rgba(163,0,0,.5);letter-spacing:.04em;}
.contract-text{font-family:'Cormorant',serif;font-size:1.06rem;line-height:1.65;color:#cfcfd4;max-width:520px;margin:0 auto;}
.contract-block{margin-top:20px;text-align:left;}
.contract-block-title{display:flex;align-items:center;gap:10px;font-family:'Cormorant Unicase',serif;font-size:.62rem;letter-spacing:.28em;text-transform:uppercase;color:var(--ember);margin-bottom:10px;}
.contract-block-title::before,.contract-block-title::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,transparent,rgba(163,0,0,.5),transparent);}
.task-row{display:flex;gap:10px;align-items:flex-start;padding:9px 12px;margin-bottom:6px;background:rgba(163,0,0,.06);border-left:2px solid var(--ember);font-size:.82rem;color:#d8d8dc;line-height:1.45;}
.task-row.host{border-left-color:#d4af37;}
.task-row b{font-family:'Cormorant Unicase',serif;font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--flame);white-space:nowrap;padding-top:1px;}
.task-row.host b{color:#d4af37;}
.handicap-row{display:flex;gap:10px;padding:9px 12px;margin-bottom:6px;background:rgba(0,0,0,.4);border:1px dashed rgba(160,160,170,.25);font-size:.8rem;color:var(--silver);align-items:center;}
.handicap-row .tq{width:14px;height:14px;color:var(--faint);flex-shrink:0;}
.curse-pts{display:inline-flex;align-items:center;gap:6px;font-family:'Cormorant Unicase',serif;font-size:.72rem;letter-spacing:.16em;padding:4px 14px;border-radius:2px;border:1px solid;margin-top:16px;}
.pts-1{color:#9a9aa0;border-color:#3a3a40;background:rgba(80,80,88,.1);}
.pts-3{color:#ff9a6a;border-color:#6e2a10;background:rgba(163,60,0,.12);text-shadow:0 0 10px rgba(255,120,60,.4);}
.pts-5{color:#ff5560;border-color:#7a0d14;background:rgba(163,0,0,.18);text-shadow:0 0 14px rgba(255,48,64,.7);animation:flameFlicker 1.8s ease-in-out infinite;}
@keyframes flameFlicker{0%,100%{box-shadow:0 0 8px rgba(163,0,0,.3);}50%{box-shadow:0 0 22px rgba(255,48,64,.55);}}
/* чёрный туман для макс. уровня */
.smoke-wrap{position:relative;}
.smoke-wrap::before,.smoke-wrap::after{content:"";position:absolute;inset:-14px;border-radius:8px;pointer-events:none;background:radial-gradient(circle at 30% 70%,rgba(0,0,0,.55),transparent 60%),radial-gradient(circle at 70% 30%,rgba(0,0,0,.45),transparent 60%);animation:smokeMove 6s ease-in-out infinite;z-index:0;}
.smoke-wrap::after{animation-delay:-3s;opacity:.7;}
@keyframes smokeMove{0%,100%{transform:translate(0,0) scale(1);}50%{transform:translate(7px,-9px) scale(1.06);}}
/* ==================== ЛЕТОПИСЬ ==================== */
.chron-item{border:1px solid var(--line);border-radius:5px;padding:16px;background:rgba(10,10,12,.6);transition:all .3s;}
.chron-item .chron-head{display:flex;align-items:center;gap:12px;margin-bottom:10px;}
.chron-title{font-family:'Cormorant Unicase',serif;font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;color:var(--silver);flex-grow:1;}
.chron-date{font-size:.62rem;color:var(--faint);letter-spacing:.06em;white-space:nowrap;}
.ch-status{width:32px;height:32px;flex-shrink:0;position:relative;display:flex;align-items:center;justify-content:center;}
.ch-status .tq{width:26px;height:26px;transition:all .4s;}
.st-active .ch-status .tq{color:var(--flame);animation:tqPulse 1.4s ease-in-out infinite;}
.st-success{border-color:rgba(180,190,205,.4)!important;box-shadow:0 0 18px rgba(163,0,0,.15);}
.st-success .ch-status .tq{color:#ff2030;filter:drop-shadow(0 0 7px rgba(255,32,48,.8));}
.st-fail{opacity:.72;}
.st-fail .ch-status .tq{color:#3f3f44;filter:grayscale(1);}
.st-fail .ch-status::after{content:"";position:absolute;left:2px;right:2px;top:50%;height:2px;background:linear-gradient(90deg,transparent,#000 20%,#1a1a1a 50%,#000 80%,transparent);transform:rotate(-38deg);box-shadow:0 0 4px rgba(0,0,0,.9);}
.status-btns{display:flex;gap:6px;}
.status-btns button{padding:5px 10px;font-size:.62rem;letter-spacing:.1em;font-family:'Cormorant Unicase',serif;text-transform:uppercase;background:#101012;border:1px solid #2c2c31;color:var(--dim);border-radius:2px;cursor:pointer;transition:all .2s;}
.status-btns button:hover{color:#fff;border-color:var(--ember);}
.status-btns button.sel-ok{color:#7dff9b;border-color:rgba(80,200,120,.5);}
.status-btns button.sel-fail{color:#ff7580;border-color:rgba(255,48,64,.5);}
.chron-cards{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;}
.mini-char{width:74px;text-align:center;}
.mini-char img{width:56px;height:56px;border-radius:50%;object-fit:cover;border:2px solid var(--ember);box-shadow:0 0 10px rgba(163,0,0,.4);}
.mini-char p{font-size:.6rem;margin-top:4px;color:var(--silver);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.flame-high{border-color:rgba(255,48,64,.45)!important;box-shadow:0 0 24px rgba(163,0,0,.25),inset 0 0 20px rgba(163,0,0,.06);}
.flame-high .chron-title{color:#ffb3b8;}
/* ==================== НАСТРОЙКИ ==================== */
.settings-tab{padding:9px 18px;border-radius:3px;background:transparent;border:1px solid transparent;color:var(--dim);font-family:'Cormorant Unicase',serif;font-weight:700;font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;cursor:pointer;transition:all .2s;white-space:nowrap;}
.settings-tab.active{background:#141416;border-color:var(--line-red);color:var(--flame);}
.settings-tab:hover:not(.active){color:var(--silver);}
.player-char-card{position:relative;cursor:pointer;border:1px solid var(--line);border-radius:4px;background:rgba(14,14,16,.8);padding:8px 4px;text-align:center;transition:all .22s;}
.player-char-card.selected{border-color:rgba(255,48,64,.55);box-shadow:0 0 14px rgba(163,0,0,.3),inset 0 0 12px rgba(163,0,0,.15);}
.player-char-card:hover{border-color:rgba(196,30,47,.4);transform:translateY(-2px);}
.player-char-card img.avatar{width:44px;height:44px;border-radius:50%;object-fit:cover;border:2px solid transparent;transition:border-color .2s;}
.player-char-card.selected img.avatar{border-color:var(--flame);}
.player-char-card p{font-size:.58rem;margin-top:5px;color:var(--silver);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.player-char-card .remove-btn{position:absolute;top:-6px;right:-6px;background:linear-gradient(135deg,#c22,#5c0a12);color:#fff;border-radius:50%;width:18px;height:18px;display:flex;align-items:center;justify-content:center;font-size:.8rem;opacity:0;transition:opacity .2s;box-shadow:0 2px 8px rgba(0,0,0,.5);}
.player-char-card:hover .remove-btn{opacity:1;}
.boss-toggle{display:flex;align-items:center;padding:9px 12px;margin-bottom:6px;border:1px solid var(--line);border-radius:3px;transition:all .2s;font-size:.8rem;}
.boss-toggle:hover{background:rgba(163,0,0,.07);border-color:rgba(196,30,47,.35);}
.boss-toggle input{margin-right:10px;width:15px;height:15px;accent-color:var(--crimson);cursor:pointer;}
.boss-toggle label{cursor:pointer;flex:1;color:#c8c8ce;}
/* ==================== МУЗЫКА / ФУТЕР ==================== */
.music-control{position:fixed;bottom:20px;right:20px;z-index:90;display:flex;align-items:center;gap:10px;}
.music-btn{width:42px;height:42px;border-radius:3px;background:rgba(13,13,15,.85);backdrop-filter:blur(10px);border:1px solid #2c2c31;color:var(--ember);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .25s;}
.music-btn:hover{border-color:var(--flame);box-shadow:0 0 16px rgba(163,0,0,.4);color:var(--flame);}
.music-btn svg{width:18px;height:18px;}
.volume-slider{width:96px;height:3px;-webkit-appearance:none;appearance:none;background:rgba(163,0,0,.3);border-radius:2px;outline:none;opacity:0;transition:opacity .3s;}
.music-control:hover .volume-slider{opacity:1;}
.volume-slider::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;border-radius:2px;background:var(--flame);cursor:pointer;box-shadow:0 0 8px rgba(255,48,64,.6);}
.volume-slider::-moz-range-thumb{width:12px;height:12px;border-radius:2px;background:var(--flame);border:none;cursor:pointer;}
.app-footer{margin-top:auto;padding:30px 24px 34px;border-top:1px solid var(--line);text-align:center;position:relative;}
.app-footer::before{content:"";position:absolute;top:-1px;left:22%;right:22%;height:1px;background:linear-gradient(90deg,transparent,rgba(196,30,47,.7),transparent);}
.footer-author{font-family:'Cormorant Unicase',serif;font-size:1rem;letter-spacing:.4em;text-indent:.4em;color:var(--ember);text-transform:uppercase;margin:14px 0 10px;cursor:pointer;transition:all .25s;}
.footer-author:hover{color:var(--platinum);text-shadow:0 0 16px rgba(255,48,64,.9);}
.footer-disclaimer{font-size:.68rem;color:var(--faint);max-width:480px;margin:0 auto;line-height:1.7;letter-spacing:.04em;}
.loader{width:46px;height:46px;border:2px solid rgba(163,0,0,.25);border-top-color:var(--flame);border-radius:50%;animation:rot 1s linear infinite;}
@keyframes rot{to{transform:rotate(360deg);}}
.hidden{display:none!important;}
.custom-scrollbar::-webkit-scrollbar{height:6px;width:6px;}
.custom-scrollbar::-webkit-scrollbar-track{background:rgba(0,0,0,.3);}
.custom-scrollbar::-webkit-scrollbar-thumb{background:#3a0a0e;border-radius:3px;}
.custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#6e1218;}
.mobile-menu-btn{display:none;}
@media(max-width:1023px){
.sidebar{transform:translateX(-100%);width:266px;}
.sidebar.open{transform:translateX(0);}
.main-wrap{margin-left:0;}
.topbar{display:flex;}
.mobile-menu-btn{display:inline-flex;}
.main-content{padding:22px 16px;}
.summon-btn{padding:16px 30px;font-size:1rem;}
.stage-title{font-size:1.4rem;}
}
@media(prefers-reduced-motion:reduce){
.abyss-eye,.grain{display:none;}
*{animation-duration:.01s!important;}
}
</style>
</head>
<body>
<!-- ==================== БЕЗДНА ==================== -->
<div class="abyss" aria-hidden="true">
<div class="abyss-glow"></div>
<div class="abyss-rings" id="abyss-rings">
<svg class="ring-a" viewBox="0 0 200 200"><circle cx="100" cy="100" r="96" fill="none" stroke="#a30000" stroke-width=".6" stroke-dasharray="2 9"/><circle cx="100" cy="100" r="88" fill="none" stroke="#666" stroke-width=".3" stroke-dasharray="30 14"/></svg>
<svg class="ring-b" viewBox="0 0 200 200"><circle cx="100" cy="100" r="95" fill="none" stroke="#8a8a92" stroke-width=".4" stroke-dasharray="1 6"/><circle cx="100" cy="100" r="70" fill="none" stroke="#a30000" stroke-width=".5" stroke-dasharray="14 20"/></svg>
<svg class="ring-c" viewBox="0 0 200 200"><circle cx="100" cy="100" r="92" fill="none" stroke="#a30000" stroke-width=".5" stroke-dasharray="3 5"/></svg>
</div>
</div>
<canvas id="ember-canvas" aria-hidden="true"></canvas>
<div id="eyes-layer" aria-hidden="true"></div>
<div class="grain" aria-hidden="true"></div>
<div id="summon-veil" aria-hidden="true"><div class="veil-pupil"></div></div>
<!-- Промпт музыки -->
<div id="audio-prompt" class="fixed inset-0 z-[1600] bg-black/95 backdrop-blur-md flex flex-col items-center justify-center cursor-pointer transition-opacity duration-500">
<div id="prompt-sigil" style="width:130px;height:130px;color:var(--ember);margin-bottom:26px;filter:drop-shadow(0 0 20px rgba(196,30,47,.75));"></div>
<h2 class="f-display" style="font-size:1.6rem;font-weight:700;margin:0 0 8px;text-shadow:0 0 24px rgba(163,0,0,.7);">Святилище Роновы</h2>
<p style="color:var(--dim);font-size:.9rem;letter-spacing:.1em;">Коснитесь пустоты — и она ответит звуком</p>
</div>
<!-- Музыка -->
<div class="music-control">
<input type="range" class="volume-slider" id="volume-slider" min="0" max="100" value="50">
<button class="music-btn" id="music-toggle" title="Музыка">
<svg id="music-icon-on" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"/></svg>
<svg id="music-icon-off" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="display:none;"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2"/></svg>
</button>
</div>
<audio id="bg-music" src="hoyo_.mp3" loop preload="auto"></audio>
<audio id="boom-sound" src="boom.mp3" preload="auto"></audio>
<div id="app-root">
<div class="main-wrap">
<!-- ==================== SIDEBAR ==================== -->
<aside class="sidebar" id="sidebar">
<div class="brand">
<div class="brand-sigil" id="brand-sigil"></div>
<div class="brand-text">
<h1>Святилище</h1>
<p>Ро·но·вы</p>
</div>
</div>
<nav class="sidebar-nav">
<div class="sidebar-section">
<div class="sidebar-section-title">Режим сеанса</div>
<div class="mode-grid" id="player-count-selector">
<button class="btn-metal active" data-val="1">Соло</button>
<button class="btn-metal" data-val="2">Дуо</button>
<button class="btn-metal" data-val="3">Трио</button>
<button class="btn-metal" data-val="4">Кооп</button>
</div>
<div class="mt-3 text-center" style="font-size:.68rem;letter-spacing:.12em;color:var(--faint);">
ПЕРСОНАЖЕЙ В РИТУАЛЕ: <span id="total-chars" style="color:var(--flame);font-weight:600;">4</span>
</div>
</div>
<div class="sidebar-section">
<div class="sidebar-section-title">Ритуал</div>
<div id="category-selector">
<button class="btn-metal active" data-cat="team">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
Призыв Отряда
</button>
<button class="btn-metal" data-cat="boss">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/></svg>
Призыв Босса
</button>
<button class="btn-metal" data-cat="challenge">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/></svg>
Контракт Роновы
</button>
</div>
</div>
<div class="sidebar-section hidden" id="boss-sub-settings">
<div class="sidebar-section-title">Лик Жертвы</div>
<div class="type-grid" id="boss-type-selector">
<button class="btn-metal active" data-type="world">Мир</button>
<button class="btn-metal" data-type="weekly">Неделя</button>
<button class="btn-metal" data-type="legend">Легенда</button>
</div>
</div>
<div class="sidebar-section">
<div class="sidebar-section-title">Святилище</div>
<button class="btn-metal" id="history-toggle">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
Летопись Контрактов
</button>
<button class="btn-metal" id="settings-toggle">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
Настройки
</button>
<button class="btn-metal" id="about-toggle">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.6" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
О проекте
</button>
</div>
</nav>
<div style="padding:14px 18px;border-top:1px solid var(--line);font-size:.58rem;letter-spacing:.2em;color:var(--faint);text-align:center;font-family:'Cormorant Unicase',serif;">
ТЕНИ НАБЛЮДАЮТ
</div>
</aside>
<!-- TOPBAR mobile -->
<div class="topbar">
<button class="rv-iconbtn mobile-menu-btn" id="mobile-menu-btn">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg>
</button>
<span class="f-display" style="font-size:.8rem;color:var(--ember);" id="topbar-title">Призыв Отряда</span>
<span style="width:38px;"></span>
</div>
<!-- ==================== MAIN ==================== -->
<main class="main-content">
<div class="panel" style="padding:40px 34px 44px;">
<div class="stage-head">
<h2 class="stage-title" id="stage-title">Призыв Отряда</h2>
<div class="divider"><span class="d-line"></span><span class="tq tq-sep"></span><span class="d-line"></span></div>
<p class="stage-desc" id="stage-desc"></p>
</div>
<div id="stage-body" style="min-height:380px;">
<div class="pane" id="pane-team"><div id="team-area" style="width:100%;"></div>
<div class="pane-actions hidden" id="actions-team">
<button class="rv-btn" id="save-team-btn">✕&nbsp; Записать в контракт &nbsp;✕</button>
<button class="rv-btn rv-btn-sm" id="reroll-team-btn">Перебросить</button>
</div>
</div>
<div class="pane hidden" id="pane-boss"><div id="boss-area" style="width:100%;display:flex;justify-content:center;"></div>
<div class="pane-actions hidden" id="actions-boss">
<button class="rv-btn" id="save-boss-btn">✕&nbsp; Записать в контракт &nbsp;✕</button>
<button class="rv-btn rv-btn-sm" id="reroll-boss-btn">Перебросить</button>
</div>
</div>
<div class="pane hidden" id="pane-challenge"><div id="challenge-area" style="width:100%;display:flex;justify-content:center;"></div>
<div class="pane-actions hidden" id="actions-challenge">
<button class="rv-btn" id="save-challenge-btn">✕&nbsp; Записать в контракт &nbsp;✕</button>
<button class="rv-btn rv-btn-sm" id="reroll-challenge-btn">Перебросить</button>
</div>
</div>
</div>
<div class="stage-actions">
<button id="spin-btn" class="summon-btn"><span class="sx">✕</span>ПРИЗВАТЬ<span class="sx">✕</span></button>
<p class="warn-msg" id="warn-msg"></p>
</div>
</div>
</main>
<!-- ==================== FOOTER ==================== -->
<footer class="app-footer">
<div class="divider" style="margin-bottom:0;"><span class="d-line"></span><span class="tq tq-sep"></span><span class="d-line"></span></div>
<p class="footer-author" id="author-link">Mycc</p>
<p class="footer-disclaimer">
Это фанатский проект. Не аффилирован и не одобрен HoYoverse.<br>
Genshin Impact — товарный знак miHoYo / HoYoverse. Развлекательный контент.
</p>
</footer>
</div>
</div>
<!-- ==================== МОДАЛКА: НАСТРОЙКИ ==================== -->
<div id="settings-modal" class="fixed inset-0 z-[100] flex justify-center items-center hidden p-4" style="background:rgba(0,0,0,.55);backdrop-filter:blur(6px);">
<div class="modal-panel w-full max-w-4xl shadow-2xl relative flex flex-col p-6 md:p-8 transform transition-all duration-300 scale-95 opacity-0" id="settings-modal-content" style="height:86vh;">
<div class="flex justify-between items-center mb-5">
<h2 class="f-display" style="font-size:1.3rem;font-weight:700;color:var(--platinum);margin:0;">Настройки Святилища</h2>
<button id="settings-close" class="rv-iconbtn">×</button>
</div>
<div class="flex gap-2 mb-5 pb-4 overflow-x-auto custom-scrollbar" style="border-bottom:1px solid var(--line);">
<button class="settings-tab active" data-tab="chars">Персонажи</button>
<button class="settings-tab" data-tab="bosses">Боссы</button>
<button class="settings-tab" data-tab="general">Общие</button>
</div>
<div class="flex-grow overflow-y-auto custom-scrollbar pr-2">
<div id="tab-general" class="settings-tab-result hidden">
<label class="block rv-label" style="font-size:.75rem;margin-bottom:10px;">Скорость ритуала</label>
<select id="animation-speed" class="rv-input" style="max-width:300px;">
<option value="fast">Быстрая</option>
<option value="medium" selected>Средняя</option>
<option value="slow">Медленная</option>
</select>
<p class="rv-sub" style="font-size:.75rem;margin-top:18px;line-height:1.7;">Все настройки и результаты ритуалов сохраняются в вашем браузере. Алтарь запомнит, на чём вы остановились, даже если вы закроете вкладку.</p>
</div>
<div id="tab-chars" class="settings-tab-result">
<p class="rv-sub" style="font-size:.78rem;margin:0 0 14px;">Отметьте персонажей, которыми владеете. Если никто не отмечен — ритуал использует всех.</p>
<input type="text" id="character-search" placeholder="Поиск по имени..." class="rv-input mb-4">
<div id="player-characters-selection" class="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-2"></div>
<div class="text-center mt-6">
<button id="clear-player-characters" class="rv-btn rv-btn-danger rv-btn-sm hidden">Снять все отметки</button>
</div>
</div>
<div id="tab-bosses" class="settings-tab-result hidden">
<select id="boss-category-select" class="rv-input mb-4">
<option value="world-bosses">Мировые боссы</option>
<option value="weekly-bosses">Еженедельные боссы</option>
<option value="local-legends">Местные легенды</option>
</select>
<div id="bosses-settings-container" class="grid grid-cols-1 md:grid-cols-2 gap-x-3"></div>
</div>
</div>
</div>
</div>
<!-- ==================== МОДАЛКА: ЛЕТОПИСЬ ==================== -->
<div id="history-modal" class="fixed inset-0 z-[100] flex justify-center items-center hidden p-4" style="background:rgba(0,0,0,.55);backdrop-filter:blur(6px);">
<div class="modal-panel w-full max-w-5xl shadow-2xl relative flex flex-col p-6 md:p-8 transform transition-all duration-300 scale-95 opacity-0" id="history-modal-content" style="height:86vh;">
<div class="flex justify-between items-center mb-5">
<h2 class="f-display" style="font-size:1.3rem;font-weight:700;color:var(--platinum);margin:0;">Летопись Контрактов</h2>
<div class="flex gap-2">
<button id="clear-history-button" class="rv-btn rv-btn-danger rv-btn-sm hidden">Сжечь летопись</button>
<button id="history-close" class="rv-iconbtn">×</button>
</div>
</div>
<div id="history-content" class="flex-grow overflow-y-auto custom-scrollbar pr-2 flex flex-col gap-4">
<p id="history-placeholder" class="text-center rv-sub" style="font-style:italic;">Летопись пуста... заключите свой первый контракт.</p>
</div>
</div>
</div>
<!-- ==================== МОДАЛКА: О ПРОЕКТЕ ==================== -->
<div id="about-modal" class="fixed inset-0 z-[100] flex justify-center items-center hidden p-4" style="background:rgba(0,0,0,.55);backdrop-filter:blur(6px);">
<div class="modal-panel w-full max-w-2xl shadow-2xl relative p-6 md:p-10 transform transition-all duration-300 scale-95 opacity-0" id="about-modal-content">
<div class="text-center mb-6">
<div id="about-sigil" style="width:80px;height:80px;margin:0 auto 16px;color:var(--ember);filter:drop-shadow(0 0 14px rgba(196,30,47,.6));"></div>
<h2 class="f-display" style="font-size:1.5rem;font-weight:700;margin:0 0 4px;">О проекте</h2>
<div class="divider"><span class="d-line"></span><span class="tq tq-sep"></span><span class="d-line"></span></div>
</div>
<div class="space-y-4 rv-sub" style="line-height:1.75;font-size:.88rem;">
<p><strong style="color:var(--platinum);">Святилище Роновы</strong> — развлекательный фанатский инструмент для сообщества Genshin Impact: случайные отряды, боссы и контракты-испытания трёх уровней Проклятия, чтобы вдохнуть новую жизнь в привычный геймплей.</p>
<p>Создано <strong style="color:var(--flame);">Mycc</strong> — с любовью к мрачной мифологии Тейвата. Ронова, Тень Смерти, чей взор следит за вами из углов этого алтаря, стала духовным покровителем проекта.</p>
<p style="font-size:.72rem;color:var(--faint);">Это развлекательный контент. Весь прогресс хранится локально в вашем браузере и никуда не передаётся.</p>
</div>
<div class="text-center mt-8">
<button id="about-close" class="rv-btn">Закрыть</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
/* ==================== ДАННЫЕ ==================== */
const LOCAL_CHARACTERS=[
{name:"Альбедо",icon:"pic/albedo.png",element:"Geo"},{name:"Аль-Хайтам",icon:"pic/alhaitham.png",element:"Dendro"},{name:"Алой",icon:"pic/aloy.png",element:"Cryo"},{name:"Эмбер",icon:"pic/amber.png",element:"Pyro"},{name:"Аратаки Итто",icon:"pic/arataki_itto.png",element:"Geo"},{name:"Арлекино",icon:"pic/arlecchino.png",element:"Pyro"},{name:"Бай Чжу",icon:"pic/baizhu.png",element:"Dendro"},{name:"Барбара",icon:"pic/barbara.png",element:"Hydro"},{name:"Бэй Доу",icon:"pic/beidou.png",element:"Electro"},{name:"Беннет",icon:"pic/bennett.png",element:"Pyro"},{name:"Кандакия",icon:"pic/candace.png",element:"Hydro"},{name:"Шарлотта",icon:"pic/charlotte.png",element:"Cryo"},{name:"Часка",icon:"pic/chasca.png",element:"Anemo"},{name:"Тиори",icon:"pic/chiori.png",element:"Geo"},{name:"Чун Юнь",icon:"pic/chongyun.png",element:"Cryo"},{name:"Ситлали",icon:"pic/citlali.png",element:"Cryo"},{name:"Клоринда",icon:"pic/clorinde.png",element:"Electro"},{name:"Коллеи",icon:"pic/collei.png",element:"Dendro"},{name:"Сайно",icon:"pic/cyno.png",element:"Electro"},{name:"Дэхья",icon:"pic/dehya.png",element:"Pyro"},{name:"Дилюк",icon:"pic/diluc.png",element:"Pyro"},{name:"Диона",icon:"pic/diona.png",element:"Cryo"},{name:"Дори",icon:"pic/dori.png",element:"Electro"},{name:"Эмилия",icon:"pic/emilie.png",element:"Dendro"},{name:"Эскофье",icon:"pic/escoffier.png",element:"Cryo"},{name:"Эола",icon:"pic/eula.png",element:"Cryo"},{name:"Фарузан",icon:"pic/faruzan.png",element:"Anemo"},{name:"Фишль",icon:"pic/fischl.png",element:"Electro"},{name:"Фремине",icon:"pic/freminet.png",element:"Cryo"},{name:"Фурина",icon:"pic/furina.png",element:"Hydro"},{name:"Га Мин",icon:"pic/gaming.png",element:"Pyro"},{name:"Гань Юй",icon:"pic/ganyu.png",element:"Cryo"},{name:"Горо",icon:"pic/gorou.png",element:"Geo"},{name:"Ху Тао",icon:"pic/hu_tao.png",element:"Pyro"},{name:"Ифу",icon:"pic/ifa.png",element:"Anemo"},{name:"Иансан",icon:"pic/iansan.png",element:"Electro"},{name:"Джинн",icon:"pic/jean.png",element:"Anemo"},{name:"Кадзуха",icon:"pic/kaedehara_kazuha.png",element:"Anemo"},{name:"Кэйа",icon:"pic/kaeya.png",element:"Cryo"},{name:"Качина",icon:"pic/Kachina.webp",element:"Geo"},{name:"Аяка",icon:"pic/kamisato_ayaka.png",element:"Cryo"},{name:"Аято",icon:"pic/kamisato_ayato.png",element:"Hydro"},{name:"Кавэх",icon:"pic/kaveh.png",element:"Dendro"},{name:"Кэ Цин",icon:"pic/keqing.png",element:"Electro"},{name:"Кинич",icon:"pic/kinich.png",element:"Dendro"},{name:"Кирара",icon:"pic/kirara.png",element:"Dendro"},{name:"Кли",icon:"pic/klee.png",element:"Pyro"},{name:"Сара",icon:"pic/kujou_sara.png",element:"Electro"},{name:"Шинобу",icon:"pic/kuki_shinobu.png",element:"Electro"},{name:"Лань Янь",icon:"pic/lan_yan.png",element:"Anemo"},{name:"Лейла",icon:"pic/layla.png",element:"Cryo"},{name:"Лиза",icon:"pic/lisa.png",element:"Electro"},{name:"Линнет",icon:"pic/lynette.png",element:"Anemo"},{name:"Лини",icon:"pic/lyney.png",element:"Pyro"},{name:"Мавуика",icon:"pic/mavuika.png",element:"Pyro"},{name:"Мика",icon:"pic/mika.png",element:"Cryo"},{name:"Мона",icon:"pic/mona.png",element:"Hydro"},{name:"Муалани",icon:"pic/mualani.png",element:"Hydro"},{name:"Нахида",icon:"pic/nahida.png",element:"Dendro"},{name:"Навия",icon:"pic/navia.png",element:"Geo"},{name:"Нёвиллет",icon:"pic/neuvillette.png",element:"Hydro"},{name:"Нилу",icon:"pic/nilou.png",element:"Hydro"},{name:"Нин Гуан",icon:"pic/ningguang.png",element:"Geo"},{name:"Ноэлль",icon:"pic/noelle.png",element:"Geo"},{name:"Оророн",icon:"pic/ororon.png",element:"Electro"},{name:"Ци Ци",icon:"pic/qiqi.png",element:"Cryo"},{name:"Райдэн",icon:"pic/raiden_shogun.png",element:"Electro"},{name:"Рэйзор",icon:"pic/razor.png",element:"Electro"},{name:"Розалья",icon:"pic/rosaria.png",element:"Cryo"},{name:"Кокоми",icon:"pic/sangonomiya_kokomi.png",element:"Hydro"},{name:"Саю",icon:"pic/sayu.png",element:"Anemo"},{name:"Сетос",icon:"pic/sethos.png",element:"Electro"},{name:"Шэнь Хэ",icon:"pic/shenhe.png",element:"Cryo"},{name:"Хэйдзо",icon:"pic/shikanoin_heizo.png",element:"Anemo"},{name:"Сиджвин",icon:"pic/sigewinne.png",element:"Hydro"},{name:"Сахароза",icon:"pic/sucrose.png",element:"Anemo"},{name:"Тарталья",icon:"pic/tartaglia.png",element:"Hydro"},{name:"Тома",icon:"pic/thoma.png",element:"Pyro"},{name:"Тигнари",icon:"pic/tighnari.png",element:"Dendro"},{name:"Вареса",icon:"pic/varesa.png",element:"Electro"},{name:"Венти",icon:"pic/venti.png",element:"Anemo"},{name:"Странник",icon:"pic/wanderer.png",element:"Anemo"},{name:"Ризли",icon:"pic/wriothesley.png",element:"Cryo"},{name:"Сяо",icon:"pic/xiao.png",element:"Anemo"},{name:"Сян Линь",icon:"pic/xiangling.png",element:"Pyro"},{name:"Сянь Юнь",icon:"pic/xianyun.png",element:"Anemo"},{name:"Шилонен",icon:"pic/xilonen.png",element:"Geo"},{name:"Син Цю",icon:"pic/xingqiu.png",element:"Hydro"},{name:"Синь Янь",icon:"pic/xinyan.png",element:"Pyro"},{name:"Яэ Мико",icon:"pic/yae_miko.png",element:"Electro"},{name:"Янь Фэй",icon:"pic/yanfei.png",element:"Pyro"},{name:"Яо Яо",icon:"pic/yaoyao.png",element:"Dendro"},{name:"Е Лань",icon:"pic/yelan.png",element:"Hydro"},{name:"Ёимия",icon:"pic/yoimiya.png",element:"Pyro"},{name:"Юнь Цзинь",icon:"pic/yun_jin.png",element:"Geo"},{name:"Паймон",icon:"pic/paimon.png",element:"Anemo"},{name:"ГГ (Анемо)",icon:"pic/traveler.webp",element:"Anemo"},{name:"ГГ (Гео)",icon:"pic/traveler.webp",element:"Geo"},{name:"ГГ (Электро)",icon:"pic/traveler.webp",element:"Electro"},{name:"ГГ (Дендро)",icon:"pic/traveler.webp",element:"Dendro"},{name:"ГГ (Гидро)",icon:"pic/traveler.webp",element:"Hydro"},{name:"Мидзуки",icon:"pic/yumemizuki_mizuki.png",element:"Anemo"},{name:"Чжун Ли",icon:"pic/zhongli.png",element:"Geo"},{name:"Скирк",icon:"pic/skirk.png",element:"Cryo"},{name:"Далия",icon:"pic/daliya.png",element:"Hydro"},{name:"Инеффа",icon:"pic/ineffa.png",element:"Electro"},{name:"Лаума",icon:"pic/lauma_icon.webp",element:"Dendro"},{name:"Айно",icon:"pic/aino_icon.webp",element:"Hydro"},{name:"Флинс",icon:"pic/flins_icon.webp",element:"Electro"},{name:"Нефер",icon:"pic/Nefer.webp",element:"Dendro"},{name:"Ягода",icon:"pic/YAgoda.webp",element:"Anemo"},{name:"Дурин",icon:"pic/Durin.webp",element:"Pyro"},{name:"Иллуги",icon:"pic/Illuga.png",element:"Geo"},{name:"Цзы Бай",icon:"pic/zibai.png",element:"Geo"},{name:"Коломбина",icon:"pic/Columbina.png",element:"Hydro"},{name:"Варка",icon:"pic/varka.png",element:"Anemo"},{name:"Прюн",icon:"pic/prune.png",element:"Anemo"},{name:"Линнея",icon:"pic/linneya.png",element:"Geo"},{name:"Николь",icon:"pic/nikol.png",element:"Pyro"},{name:"Лохэн",icon:"pic/lohen.png",element:"Cryo"},{name:"Сандроне",icon:"pic/sandrone.png",element:"Cryo"},{name:"Алёша",icon:"pic/alyesha.png",element:"Electro"},{name:"ГГ (Крио)",icon:"pic/traveler.webp",element:"Cryo"},{name:"Одетта",icon:"pic/odetta.png",element:"Cryo"},{name:"Весна",icon:"pic/vesna.png",element:"Anemo"},{name:"Водяница",icon:"pic/vodyanitsa.png",element:"Hydro"}];
const WORLD_BOSSES=[
{name:"Сверхтяжёлый сухопутный крейсер",icon:"pic/WorldBoss/Sverkhtyazhyelyy-sukhoputnyy-kreyser.webp"},{name:"Повелитель морозной ночи",icon:"pic/WorldBoss/Povelitel-moroznoy-nochi.webp"},{name:"Лучезарный мотылёк-призрак",icon:"pic/WorldBoss/Luchezarnyy-motylyek_prizrak.webp"},{name:"Железный утёнок",icon:"pic/WorldBoss/ZHeleznyy-utyenok.webp"},{name:"Автоматон: Надсмотрщик",icon:"pic/WorldBoss/Secret-Source-Automaton-Overseer-Device.webp"},{name:"Статуя лавового дракона",icon:"pic/WorldBoss/Statuya-lavovogo-drakona.webp"},{name:"Говорящая с духами отшельница",icon:"pic/WorldBoss/Govoryashchaya-s-dukhami-otshelnitsa.webp"},{name:"Сумрачная папилла",icon:"pic/WorldBoss/Sumrachnaya-papilla.webp"},{name:"Автоматон: Конфигуратор",icon:"pic/WorldBoss/Avtomaton-tainstvennogo-istochnika.webp"},{name:"Прожорливый Горный король",icon:"pic/WorldBoss/Prozhorlivyy-gornyy-korol-yumkazavr.webp"},{name:"Кукузавр-тиран",icon:"pic/WorldBoss/Prozhorlivyi_-Gornyi_-korol_yumkazavr.webp"},{name:"Легат големов",icon:"pic/WorldBoss/Kapitan-golemov.webp"},{name:"Суаньни-отшельник",icon:"pic/WorldBoss/Suanni_otshelnik.webp"},{name:"Гидротульпа",icon:"pic/WorldBoss/Probuzhdyennaya-zhizn.webp"},{name:"Экспериментальный генератор",icon:"pic/WorldBoss/Eksperimentalnyy-generator-polya.webp"},{name:"Морской конёк жемчужины",icon:"pic/WorldBoss/Morskoy-konyek-tysyacheletney-zhemchuzhiny.webp"},{name:"Император огня и железа",icon:"pic/WorldBoss/Imperator-ognya-i-zheleza.webp"},{name:"Сюита ледяного ветра",icon:"pic/WorldBoss/Syuita-ledyanogo-vetra.webp"},{name:"Чудовищный креститель",icon:"pic/WorldBoss/CHudovishchnyy-krestitel.webp"},{name:"Унут Сетеха",icon:"pic/WorldBoss/Unut-Setekha.webp"},{name:"Дендро Гипостазис",icon:"pic/WorldBoss/Dendro-Gipostazis.png"},{name:"Алгоритм полуизвечной матрицы",icon:"pic/WorldBoss/Poluvechnaya-matritsa-upravleniya.webp"},{name:"Дракон вечных бедствий",icon:"pic/WorldBoss/Drakon-vechnykh-bedstviy.webp"},{name:"Электро папоротник",icon:"pic/WorldBoss/Elektro-paporotnik.webp"},{name:"Пернатый плесенник",icon:"pic/WorldBoss/Pernatyy-plesennik.webp"},{name:"Змей руин",icon:"pic/WorldBoss/Zmey-ruin.webp"},{name:"Стая вишапов глубин",icon:"pic/WorldBoss/Staya-vishapov-glubin.webp"},{name:"Золотой волчий вожак",icon:"pic/WorldBoss/Golden-Wolflord.png"},{name:"Гидро Гипостазис",icon:"pic/WorldBoss/Gidro-Gipostazis.png"},{name:"Манифестация грома",icon:"pic/WorldBoss/Elektro-Okeanid.png"},{name:"Бесконечный механический массив",icon:"pic/WorldBoss/Beskonechnyy-mekhanicheskiy-massiv.png"},{name:"Пиро гипостазис",icon:"pic/WorldBoss/Piro-gipostazis.png"},{name:"Магу Кенки",icon:"pic/WorldBoss/Magu-Kenki.webp"},{name:"Крио гипостазис",icon:"pic/WorldBoss/Cryo_Hypostasis.webp"},{name:"Древний геовишап",icon:"pic/WorldBoss/Drevniy-geovishap.webp"},{name:"Гео гипостазис",icon:"pic/WorldBoss/UI_MonsterIcon_Effigy_Rock.png"},{name:"Электро гипостазис",icon:"pic/WorldBoss/UI_MonsterIcon_Effigy_Electric.png"},{name:"Анемо гипостазис",icon:"pic/WorldBoss/UI_MonsterIcon_Effigy_Wind.png"},{name:"Крио папоротник",icon:"pic/WorldBoss/UI_MonsterIcon_cryo_regisvine.png"},{name:"Пиро орхидея",icon:"pic/WorldBoss/UI_MonsterIcon_Regisvine_Fire.png"},{name:"Океанид",icon:"pic/WorldBoss/Okeanid.webp"},{name:"Лучезарный лунный геккон",icon:"pic/WorldBoss/Luchezarnyi_-lunnyi_-gekkon.webp"},{name:"Повелитель скрытых глубин",icon:"pic/WorldBoss/Povelitel-skrytykh-glubin-SHyepot-koshmarov.webp"},{name:"Созерцатель: Падший страж",icon:"pic/WorldBoss/Sozertsatel-Padshiy-strazh.webp"},{name:"Бессмертный конструкт",icon:"pic/WorldBoss/Bessmertnyy-konstrukt.webp"},{name:"Крылатая химера-лев",icon:"pic/WorldBoss/Krylataya-khimera_lev.webp"}];
const WEEKLY_BOSSES=[
{name:"Игра перед вратами",icon:"pic/Allweeklybosses/Igra-pered-vratami.webp"},{name:"Доктор",icon:"pic/Allweeklybosses/Doktor.webp"},{name:"Владыка истлевшего первобытного пламени",icon:"pic/Allweeklybosses/Lord-of-Eroded-Primal-Fire.webp"},{name:"Слуга (Арлекино)",icon:"pic/Allweeklybosses/Nomer-chetyre-iz-Predvestnikov-Fatui_-Arlekino.webp"},{name:"Всепожирающий нарвал",icon:"pic/Allweeklybosses/Vsepozhirayushchiy-narval.webp"},{name:"Страж оазиса Апепа",icon:"pic/Allweeklybosses/Strazh-oazisa-Apepa.webp"},{name:"Сёки но Ками",icon:"pic/Allweeklybosses/Syeki-no-Kami.webp"},{name:"Магацу митакэ Наруками",icon:"pic/Allweeklybosses/m_29060201.webp"},{name:"Синьора",icon:"pic/Allweeklybosses/Sinora.png"},{name:"Аждаха",icon:"pic/Allweeklybosses/Azhdaha.png"},{name:"Чайльд",icon:"pic/Allweeklybosses/Childe.png"},{name:"Лупус Бореалис",icon:"pic/Allweeklybosses/UI_MonsterIcon_LupiBoreas.png"},{name:"Ужас бури (Двалин)",icon:"pic/Allweeklybosses/Stormterror.png"}];
const LOCAL_LEGENDS=[
{name:"Волшебные рыцари-близнецы",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-284766-1-800x476.jpg",guideUrl:"https://wotpack.ru/volshebnye-rycari-bliznecy-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Окружной судья океана",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-284964-4.jpg",guideUrl:"https://wotpack.ru/okruzhnoj-sudja-okeana-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Дева озера Вивианна",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-283768-1-800x425.jpg",guideUrl:"https://wotpack.ru/deva-ozera-vivianna-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Дева озера Нинианна",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-283708-1-800x423.jpg",guideUrl:"https://wotpack.ru/deva-ozera-ninianna-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Угасающий старый солдат",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-283590-1-800x450.jpeg",guideUrl:"https://wotpack.ru/ugasajushhij-staryj-soldat-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Владыка отшельников Доварху",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-283520-1-800x450.jpeg",guideUrl:"https://wotpack.ru/vladyka-otshelnikov-dovarhu-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Меч ущелья",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-283554-1-800x450.jpeg",guideUrl:"https://wotpack.ru/mech-ushhelja-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Железный виконт",icon:"https://wotpack.ru/wp-content/uploads/2023/08/word-image-284964-10.jpg",guideUrl:"https://wotpack.ru/zheleznyj-vikont-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Генератор сверхвычислений",icon:"https://wotpack.ru/wp-content/uploads/2023/09/word-image-301036-4.jpeg",guideUrl:"https://wotpack.ru/avtomaticheskij-generator-polej-sverhvychislenij-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Лиахра Блистательная",icon:"https://wotpack.ru/wp-content/uploads/2023/09/word-image-301327-4.jpeg",guideUrl:"https://wotpack.ru/liahra-blistatelnaja-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Изольт",icon:"https://wotpack.ru/wp-content/uploads/2023/09/word-image-301389-1-1-800x450.jpeg",guideUrl:"https://wotpack.ru/izolt-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Шассанион",icon:"https://wotpack.ru/wp-content/uploads/2023/11/word-image-321383-7-800x450.jpeg",guideUrl:"https://wotpack.ru/shassanion-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Деянейра Снежневна",icon:"https://wotpack.ru/wp-content/uploads/2023/11/1-10-800x450.jpg",guideUrl:"https://wotpack.ru/dejanejra-snezhnevna-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Роки Авилдсен",icon:"https://wotpack.ru/wp-content/uploads/2023/11/word-image-321618-1-800x450.jpeg",guideUrl:"https://wotpack.ru/roki-avildsen-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Магический меч Круж",icon:"https://wotpack.ru/wp-content/uploads/2023/11/word-image-322447-1-800x450.jpeg",guideUrl:"https://wotpack.ru/magicheskij-mech-kruzh-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Лиям",icon:"https://wotpack.ru/wp-content/uploads/2023/11/word-image-321469-1-800x450.jpeg",guideUrl:"https://wotpack.ru/lijam-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Киней",icon:"https://wotpack.ru/wp-content/uploads/2024/04/Kinej-v-Genshin-Impact-800x450.jpg",guideUrl:"https://wotpack.ru/kinej-v-genshin-impact-kak-najti-i-pobedit/"},{name:"Три полихромные звезды",icon:"https://wotpack.ru/wp-content/uploads/2024/08/mestnaya-legenda-tri-polihromnye-zvezdy-3-800x449.jpg",guideUrl:"https://wotpack.ru/tri-polihromnye-zvezdy-v-genshin-impact-kak-nayti-i-pobedit-vasiliya-sidorenko-i-nomonkonova/"},{name:"Косихо",icon:"https://wotpack.ru/wp-content/uploads/2024/08/kosiho-v-genshin-impact-kak-nayti-i-pobedit-800x450.jpg",guideUrl:"https://wotpack.ru/kosiho-v-genshin-impact-kak-nayti-i-pobedit-cherepahu/"},{name:"Сапфо среди волн",icon:"https://wotpack.ru/wp-content/uploads/2024/08/sapfo-sredi-voln-v-genshin-impact-kak-nayti-i-pobedit-800x450.jpg",guideUrl:"https://wotpack.ru/sapfo-sredi-voln-v-genshin-impact-kak-nayti-i-pobedit/"},{name:"Балачко",icon:"https://wotpack.ru/wp-content/uploads/2024/08/balachko-v-genshin-impact-kak-nayti-i-pobedit-397x206.jpg",guideUrl:"https://wotpack.ru/balachko-v-genshin-impact-kak-nayti-i-pobedit/"},{name:"Рилай",icon:"https://wotpack.ru/wp-content/uploads/2024/11/rilay-v-genshin-impact-800x450.jpg",guideUrl:"https://wotpack.ru/rilay-v-genshin-impact-kak-nayti-i-pobedit/"},{name:"Король снежных кабанов",icon:"https://wotpack.ru/wp-content/uploads/2021/11/%D0%BA%D0%BE%D1%80%D0%BE%D0%BB%D1%8C-%D1%81%D0%BD%D0%B5%D0%B6%D0%BD%D1%8B%D1%85-%D0%BA%D0%B0%D0%B1%D0%B0%D0%BD%D0%BE%D0%B2-348x220.jpg",guideUrl:"https://wotpack.ru/genshin-impact-ah-svezhee-mjaso-prohozhdenie-kvesta-gajd/"},{name:"Бронзовый замок",icon:"https://wotpack.ru/wp-content/uploads/2024/11/bronzovyy-2.jpg",guideUrl:"https://wotpack.ru/bronzovyy-zamok-v-genshin-impact-kak-nayti-i-pobedit/"},{name:"Ничтожный",icon:"https://wotpack.ru/wp-content/uploads/2025/03/nichtozhnyy-v-mire-vid.jpg",guideUrl:"https://wotpack.ru/nichtozhnyy-v-genshin-impact-kak-nayti-i-pobedit/"},{name:"Пик",icon:"https://wotpack.ru/wp-content/uploads/2025/03/pik-v-genshin-impact-kak-pobedit-mutanta-730x411.jpg",guideUrl:"https://wotpack.ru/pik-v-genshin-impact-kak-nayti-i-pobedit-mutanta/"},{name:"Боевой козел и Железный коготь",icon:"https://wotpack.ru/wp-content/uploads/2025/03/boevoy-kozyol-i-zheleznyy-kogot-v-genshin-impact_-kak-nayti-i-pobedit-730x411.jpg",guideUrl:"https://wotpack.ru/boevoy-kozyol-i-zheleznyy-kogot-v-genshin-impact-kak-nayti-i-pobedit/"},{name:"Теночцитока",icon:"https://wotpack.ru/wp-content/uploads/2025/07/posledniy-vyzhivshiy-iz-tenochtsitoka-v-genshin-impact-730x455.jpg",guideUrl:"https://wotpack.ru/posledniy-vyzhivshiy-iz-tenochtsitoka-v-genshin-impact-kak-nayti-i-pobedit/"},{name:"Царь-краб, хозяин дворца",icon:"https://wotpack.ru/wp-content/uploads/2025/09/word-image-546429-2.jpeg",guideUrl:"https://wotpack.ru/tsarskiy-krab-v-genshin-impact-kak-pobedit-i-proyti-ispytanie/"},{name:"Сигурд",icon:"https://wotpack.ru/wp-content/uploads/2025/09/sigurd-v-genshin-impact-730x411.jpg",guideUrl:"https://wotpack.ru/sigurd-v-genshin-impact-kak-pobedit-i-proyti-ispytanie/"},{name:"Раскольников",icon:"https://wotpack.ru/wp-content/uploads/2025/09/raskolnikov-v-genshin-impact-730x411.jpg",guideUrl:"https://wotpack.ru/raskolnikov-v-genshin-impact-kak-pobedit-i-proyti-ispytanie/"},{name:"Ицзи и Тяньюнь",icon:"https://wotpack.ru/wp-content/uploads/2024/01/20240131070630.jpg",guideUrl:"https://wotpack.ru/vladyki-gor-chichzhan-v-genshin-impact-kak-najti-i-pobedit-iczi-i-tjanjun/"},{name:"Шестнадцатикратная мандрагора",icon:"pic/LocalLegends/placeholder.webp",guideUrl:"https://wotpack.ru/shestnadtsatikratnaya-mandragora-v-genshin-impact-kak-pobedit-i-proyti-ispytanie/"},{name:"Старая ведьма Хильетта",icon:"https://wotpack.ru/wp-content/uploads/2026/01/hiletta-v-genshin-impact-730x390.jpg",guideUrl:"https://wotpack.ru/hiletta-v-genshin-impact-kak-pobedit-babushku-i-proyti-ispytanie/"},{name:"Тоскующий волк-одиночка",icon:"https://wotpack.ru/wp-content/uploads/2026/01/kartochka-toskuyuschego-po-rodine-volka-odinochki-u-kateriny-730x411.jpg",guideUrl:"https://wotpack.ru/toskuyuschiy-po-rodine-volk-odinochka-v-genshin-impact-kak-pobedit-klyk-pustoshey/"},{name:"Автоматон Муштешир",icon:"https://wotpack.ru/wp-content/uploads/2026/07/mushteshir-v-genshin-impact-kak-pobedit-i-unichtozhit-chetyre-mehanizma-800x450.jpg",guideUrl:"https://wotpack.ru/mushteshir-v-genshin-impact-kak-pobedit-i-unichtozhit-chetyre-mehanizma/"},{name:"Чурльдрик",icon:"https://wotpack.ru/wp-content/uploads/2026/04/churldrik.-kartochka-v-hronikah-doblesti-800x450.jpg",guideUrl:"https://wotpack.ru/churldrik-v-genshin-impact-kak-pobedit-i-unichtozhit-vkusnyy-kotelok/"},{name:"Маха Васудеваяпутра",icon:"https://wotpack.ru/wp-content/uploads/2026/04/maha-vasudevayaputra-v-genshin-impact-kak-pobedit-do-fazy-obozhzheniya-800x445.jpg",guideUrl:"https://wotpack.ru/maha-vasudevayaputra-v-genshin-impact-kak-pobedit-do-fazy-obozhzheniya/"},{name:"Фуриоса",icon:"https://wotpack.ru/wp-content/uploads/2026/08/furiosa-v-menyu-kateriny-nagrady-800x450.jpg",guideUrl:"https://wotpack.ru/furiosa-v-genshin-impact-kak-pobedit-i-unichtozhit-korni-pregrady/"},{name:"Чурин",icon:"https://wotpack.ru/wp-content/uploads/2026/08/churin-v-genshin-impact-800x450.jpg",guideUrl:"https://wotpack.ru/churin-v-genshin-impact-gde-nayti-i-kak-pobedit-uchenika-vayatelya/"},{name:"Брандашмыг",icon:"https://wotpack.ru/wp-content/uploads/2026/08/himera-razboynik-v-genshin-impact-800x443.jpg",guideUrl:"https://wotpack.ru/himera-razboynik-v-genshin-impact-kak-pobedit-v-gigantskoy-forme-i-umenshennom-sostoyanii/"}];
const TRIALS=[
{level:1,points:1,name:"Око за Око",text:"Персонаж, активировавший Элементальный Взрыв, обязан оставаться на поле до завершения действия ульты. Переключаться на других героев в этот момент запрещено."},
{level:1,points:1,name:"Поцелуй Снежной",text:"Запрещено использовать любую еду, зелья или карманные баффы перед началом боя. Только базовая сила отряда."},
{level:1,points:1,name:"Слепая Вера",text:"Отключите мини-карту во время прохождения. Навигация к цели — только по памяти."},
{level:1,points:1,name:"Запретный Плод",text:"Запрещено подбирать элементальные частицы, созданные персонажами противоположной стихии."},
{level:2,points:3,name:"Право на Ошибку",text:"Если погибает хотя бы один персонаж — немедленно перезапустите бой. Ронова требует идеала: отряд выживает целиком или погибает полностью."},
{level:2,points:3,name:"Голод Бездны",text:"Полная изоляция от родных стихий региона: запрещено использовать персонажей региона, в котором вы находитесь."},
{level:2,points:3,name:"Печать Молчания",text:"Стихийные навыки и ульты разрешены только одному «жрецу» отряда. Остальные сражаются строго обычными и заряженными атаками."},
{level:2,points:3,name:"Эхо Прошлого",text:"Запрещено использовать персонажей, вышедших в последнем крупном патче. Допускаются только «старые» герои."},
{level:3,points:5,name:"Очи Роновы",text:"Каждые 45 секунд боя меняйте активного персонажа по строгому кругу: 1 → 2 → 3 → 4. Любое нарушение ротации — провал контракта."},
{level:3,points:5,name:"Час Искупления",text:"Сражение на 1–2 уровнях Мира выше текущего. Если уровень максимален — весь отряд экипирован артефактами не выше 4★."},
{level:3,points:5,name:"Взгляд Смерти",text:"Если HP главного ДД опускается ниже 30% — запрещено лечить его или накладывать щит. Он добивает босса на грани гибели или падает."},
{level:3,points:5,name:"Петля Времени",text:"Босс должен быть уничтожен строго за 120 секунд. Время вышло — контракт аннулируется."}];
const SYSTEM_HANDICAPS=[
"Ограничить FPS до 30 и выкрутить рендеринг на максимум","Не использовать кнопку спринта ни разу за весь бой","Прыгать каждые 5 секунд — без исключений","Минимальное разрешение экрана + максимальная графика","Полностью отключить музыку и звуковые эффекты","Не использовать карту и мини-карту","Поворачивать камеру минимум каждые 10 секунд","Переключать персонажей только клавишами 1–4, без мыши","После каждого полученного удара — три прыжка подряд","Комментировать вслух каждое своё действие","Запрет на еду и зелья во время боя","Играть в оконном режиме на половину экрана"];
const COOP_TASKS={
2:[["Игрок 1: только Пиро/Электро персонажи","Игрок 2: только Гидро/Крио/Анемо персонажи"],["Игрок 1: саппорт и хил — без права наносить урон","Игрок 2: единственный источник урона"],["Игрок 1: только 4★ персонажи","Игрок 2: только 5★ персонажи"],["Игрок 1: персонажи Мондштадта и Ли Юэ","Игрок 2: персонажи Инадзумы, Сумеру и дальше"]],
3:[["Хостер: 2 персонажа — основной урон","Игрок 2: саппорт и хил","Игрок 3: контроль и стихийные реакции"],["Хостер: только 5★ персонажи","Игрок 2: только 4★ персонажи","Игрок 3: только стартовые герои и Путешественник"],["Хостер: Пиро-отряд","Игрок 2: Электро-отряд","Игрок 3: Гидро/Крио-отряд"]],
4:[["Игрок 1: главный ДД","Игрок 2: хил и саппорт","Игрок 3: щиты и контроль","Игрок 4: суб-ДД и реакции"],["Игрок 1: Пиро","Игрок 2: Электро","Игрок 3: Гидро или Крио","Игрок 4: Анемо, Гео или Дендро"],["Игроки 1–2: только 4★ персонажи","Игроки 3–4: только 5★ персонажи","Стихии в отряде не должны повторяться"]]};
const LEVEL_ROMAN={1:"I",2:"II",3:"III"};
const LEVEL_NAMES={1:"Прикосновение Тени",2:"Тлеющий Контракт",3:"Лик Роновы"};
const MODE_NAMES={1:"Соло",2:"Дуо",3:"Трио",4:"Фулкооп"};
/* ==================== ТРИКВЕТР ==================== */
const TQ=`<svg viewBox="0 0 100 100" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round">
<circle cx="50" cy="50" r="45" stroke-opacity=".35" stroke-width="1.4"/>
<path d="M50 50 C30 36 30 14 50 6 C70 14 70 36 50 50 Z"/>
<g transform="rotate(120 50 50)"><path d="M50 50 C30 36 30 14 50 6 C70 14 70 36 50 50 Z"/></g>
<g transform="rotate(240 50 50)"><path d="M50 50 C30 36 30 14 50 6 C70 14 70 36 50 50 Z"/></g>
<circle cx="50" cy="50" r="4" fill="currentColor" stroke="none"/></svg>`;
/* ==================== БОЛЬШОЙ ЖИВОЙ СИГИЛ ==================== */
const SIGIL=`<svg viewBox="0 0 120 120" fill="none" stroke="currentColor">
<g class="sg-ringA"><circle cx="60" cy="60" r="56" stroke-width="1" stroke-dasharray="3 8"/><path d="M60 4 l2 5 -2 5 -2 -5z" fill="currentColor" stroke="none"/><path d="M116 60 l-5 2 -5 -2 5 -2z" fill="currentColor" stroke="none"/><path d="M60 116 l-2 -5 2 -5 2 5z" fill="currentColor" stroke="none"/><path d="M4 60 l5 -2 5 2 -5 2z" fill="currentColor" stroke="none"/></g>
<g class="sg-ringB"><circle cx="60" cy="60" r="47" stroke-width=".7" stroke-dasharray="14 10" stroke-opacity=".55"/></g>
<g class="sg-tq" stroke-width="2.2">
<path d="M60 60 C44 48 44 28 60 20 C76 28 76 48 60 60Z"/>
<path d="M60 60 C44 48 44 28 60 20 C76 28 76 48 60 60Z" transform="rotate(120 60 60)"/>
<path d="M60 60 C44 48 44 28 60 20 C76 28 76 48 60 60Z" transform="rotate(240 60 60)"/></g>
<g class="sg-eye">
<path d="M42 60 Q60 48 78 60 Q60 72 42 60Z" stroke-width="1.6" fill="rgba(0,0,0,.55)"/>
<circle class="sg-iris" cx="60" cy="60" r="4.5" fill="currentColor" stroke="none"/></g></svg>`;
document.getElementById('brand-sigil').innerHTML=SIGIL;
document.getElementById('prompt-sigil').innerHTML=SIGIL;
document.getElementById('about-sigil').innerHTML=SIGIL;
document.querySelectorAll('.tq-sep').forEach(s=>{s.classList.add('tq');s.innerHTML=TQ;});
/* ==================== КОНФИГ / СОСТОЯНИЕ ==================== */
function getOrCreateUID(){let u=localStorage.getItem('genshinRouletteUID');if(!u){u=Math.random().toString(36).slice(2,15)+Math.random().toString(36).slice(2,15);localStorage.setItem('genshinRouletteUID',u);}return u;}
const UID=getOrCreateUID();
const K=n=>`${UID}_${n}`;
const config={animationSpeed:localStorage.getItem(K('animSpeed'))||'medium',
excludedBosses:JSON.parse(localStorage.getItem(K('excludedBosses')))||{'world-bosses':[],'weekly-bosses':[],'local-legends':[]}};
let allCharacters=[...LOCAL_CHARACTERS];
let historyTeams=JSON.parse(localStorage.getItem(K('teamsHistory')))||[];
let historyBosses=JSON.parse(localStorage.getItem(K('bossesHistory')))||[];
let playerCharacters=JSON.parse(localStorage.getItem(K('playerCharacters')))||[];
let session=JSON.parse(localStorage.getItem(K('session')))||{tab:'team',bossType:'world',team:null,boss:null,challenge:null};
let playerCount=session.pc||1;
let currentCategory=session.tab||'team';
let currentBossType=session.bossType||'world';
let isSpinning=false;
const $=id=>document.getElementById(id);
const spinBtn=$('spin-btn'),warnMsg=$('warn-msg');
const bgMusic=$('bg-music'),boomSound=$('boom-sound');
const sidebar=$('sidebar');
let isMusicPlaying=false;
function saveSession(){session.pc=playerCount;localStorage.setItem(K('session'),JSON.stringify(session));}
function getDistribution(p){return p===1?[4]:p===2?[2,2]:p===3?[2,1,1]:[1,1,1,1];}
function getPlayerLabel(i,p){return p===3&&i===0?'Хостер':'Игрок '+(i+1);}
function warn(t){warnMsg.textContent=t;clearTimeout(warn._t);warn._t=setTimeout(()=>warnMsg.textContent='',3500);}
/* ==================== МУЗЫКА ==================== */
function updateMusicIcon(){musicIconOn.style.display=isMusicPlaying?'block':'none';musicIconOff.style.display=isMusicPlaying?'none':'block';}
const audioPrompt=$('audio-prompt'),musicIconOn=$('music-icon-on'),musicIconOff=$('music-icon-off'),volumeSlider=$('volume-slider');
function initMusic(){
bgMusic.volume=.5;volumeSlider.value=50;
const p=bgMusic.play();
if(p!==undefined){p.then(()=>{isMusicPlaying=true;updateMusicIcon();audioPrompt.style.opacity='0';setTimeout(()=>audioPrompt.classList.add('hidden'),500);})
.catch(()=>{isMusicPlaying=false;updateMusicIcon();audioPrompt.classList.remove('hidden');});}
}
audioPrompt.addEventListener('click',()=>{bgMusic.play().then(()=>{isMusicPlaying=true;updateMusicIcon();}).catch(()=>{});audioPrompt.style.opacity='0';setTimeout(()=>audioPrompt.classList.add('hidden'),500);});
$('music-toggle').addEventListener('click',()=>{if(isMusicPlaying){bgMusic.pause();isMusicPlaying=false;}else{bgMusic.play().catch(()=>{});isMusicPlaying=true;}updateMusicIcon();});
volumeSlider.addEventListener('input',e=>bgMusic.volume=e.target.value/100);
/* ==================== УГЛИ И ПЕПЕЛ ==================== */
function initEmbers(){
const canvas=$('ember-canvas'),ctx=canvas.getContext('2d');let parts=[];
const resize=()=>{canvas.width=innerWidth;canvas.height=innerHeight;};resize();addEventListener('resize',resize);
class P{constructor(t){this.t=t;this.reset(true);}
reset(init){this.x=Math.random()*canvas.width;this.y=init?Math.random()*canvas.height:canvas.height+8;
if(this.t==='ash'){this.s=Math.random()*1.6+.5;this.v=Math.random()*.35+.1;this.o=Math.random()*.22+.05;this.drift=(Math.random()-.5)*.25;}
else{this.s=Math.random()*1.7+.6;this.v=Math.random()*.7+.35;this.o=Math.random()*.5+.25;this.drift=(Math.random()-.5)*.45;this.fl=Math.random()*Math.PI*2;}}
step(){this.y-=this.v;this.x+=this.drift+Math.sin(this.y*.01+this.fl)*.15;
if(this.y<-10||this.x<-10||this.x>canvas.width+10)this.reset(false);
const a=this.t==='ash'?this.o:this.o*(0.65+0.35*Math.sin(Date.now()*.006+this.fl));
ctx.beginPath();ctx.arc(this.x,this.y,this.s,0,6.283);
ctx.fillStyle=this.t==='ash'?`rgba(120,120,128,${a})`:`rgba(255,${48+Math.floor(60*Math.random())},40,${a})`;
if(this.t==='ember'){ctx.shadowColor='rgba(255,48,64,.8)';ctx.shadowBlur=6;}else ctx.shadowBlur=0;
ctx.fill();}}
for(let i=0;i<46;i++)parts.push(new P('ash'));
for(let i=0;i<24;i++)parts.push(new P('ember'));
(function loop(){ctx.clearRect(0,0,canvas.width,canvas.height);parts.forEach(p=>p.step());requestAnimationFrame(loop);})();
}
/* ==================== ОЧИ БЕЗДНЫ: 7 ГЛАЗ, РАНДОМ, ≥10 СМ ==================== */
const EYE_SVG=(cid)=>`<svg viewBox="0 0 120 60" style="overflow:visible;">
<defs><clipPath id="${cid}"><path d="M8 30 Q60 4 112 30 Q60 56 8 30Z"/></clipPath></defs>
<path d="M8 30 Q60 4 112 30 Q60 56 8 30Z" fill="rgba(5,2,3,.55)" stroke="rgba(196,30,47,.85)" stroke-width="1.5"/>
<g clip-path="url(#${cid})">
<g class="iris-g">
<circle cx="60" cy="30" r="13" fill="#2a0508" stroke="rgba(255,48,64,.9)" stroke-width="1.2"/>
<ellipse cx="60" cy="30" rx="3" ry="9" fill="#000" stroke="rgba(255,48,64,.5)" stroke-width=".6"/>
<circle cx="55" cy="25" r="1.8" fill="rgba(255,220,220,.5)"/>
</g>
<rect class="lid lid-t" x="0" y="0" width="120" height="30" fill="#020203"/>
<rect class="lid lid-b" x="0" y="30" width="120" height="30" fill="#020203"/>
</g>
<path d="M8 30 Q60 4 112 30 Q60 56 8 30Z" fill="none" stroke="rgba(255,48,64,.3)" stroke-width=".6"/></svg>`;
const mouse={x:innerWidth/2,y:innerHeight/2,idle:0};
let eyes=[];
const EYE_MIN_DIST=378; // ~10 см при 96dpi
function placeEyes(){
const layer=$('eyes-layer');layer.innerHTML='';eyes=[];
const W=innerWidth,H=innerHeight;
// Запретные зоны: сайдбар и центральная панель (чтобы глаза НЕ перекрывали контент)
const forbid=[];
if(innerWidth>=1024){const sb=$('sidebar');if(sb){const r=sb.getBoundingClientRect();if(r.width>0)forbid.push({x:r.left,y:r.top,w:r.width,h:r.height});}}
const panel=document.querySelector('.panel');
if(panel){const r=panel.getBoundingClientRect();forbid.push({x:r.left,y:r.top,w:r.width,h:r.height});}
const pts=[];let attempts=0;
while(pts.length<7&&attempts<600){
attempts++;
const x=50+Math.random()*(W-100);
const y=60+Math.random()*(H-180);
let ok=true;
for(const p of pts){if(Math.hypot(p.x-x,p.y-y)<EYE_MIN_DIST){ok=false;break;}}
if(!ok)continue;
for(const f of forbid){
if(x>f.x-40&&x<f.x+f.w+40&&y>f.y-40&&y<f.y+f.h+40){ok=false;break;}
}
if(!ok)continue;
pts.push({x,y});
}
// Если мало места — раскладываем по краям
let fb=0;
while(pts.length<7){
const edge=fb%4;fb++;
let x,y;
if(edge===0){x=80+Math.random()*(W-160);y=70;}
else if(edge===1){x=80+Math.random()*(W-160);y=H-130;}
else if(edge===2){x=innerWidth>=1024?320:60;y=100+Math.random()*(H-260);}
else{x=W-90;y=120+Math.random()*(H-300);}
let ok=true;
for(const p of pts){if(Math.hypot(p.x-x,p.y-y)<EYE_MIN_DIST*.6){ok=false;break;}}
if(ok)pts.push({x,y});
if(fb>40)break;
}
pts.forEach((p,i)=>createEye(layer,p.x,p.y,i));
}
function createEye(layer,x,y,i){
const scale=0.75+Math.random()*0.55;
const rot=(Math.random()*16-8).toFixed(1);
const el=document.createElement('div');
el.className='abyss-eye';
el.style.left=(x-60*scale)+'px';
el.style.top=(y-30*scale)+'px';
el.style.width=(120*scale)+'px';
el.style.height=(60*scale)+'px';
el.style.transform=`rotate(${rot}deg)`;
el.innerHTML=EYE_SVG('ec'+i);
layer.appendChild(el);
eyes.push({el,x,y,iris:el.querySelector('.iris-g'),lt:el.querySelector('.lid-t'),lb:el.querySelector('.lid-b'),open:0,px:0,py:0,auto:0,seed:i*1.7});
}
function initEyes(){
placeEyes();
let rT;addEventListener('resize',()=>{clearTimeout(rT);rT=setTimeout(placeEyes,300);});
addEventListener('mousemove',e=>{mouse.x=e.clientX;mouse.y=e.clientY;mouse.idle=Date.now();});
// Иногда глаза открываются сами, когда курсор замер
setInterval(()=>{if(Date.now()-mouse.idle>3500&&eyes.length){const e=eyes[Math.floor(Math.random()*eyes.length)];e.auto=Date.now()+2200;}},6000);
(function loop(){
const now=Date.now();
eyes.forEach(e=>{
const d=Math.hypot(mouse.x-e.x,mouse.y-e.y);
let target=Math.max(0,1-d/320);
target=Math.pow(target,1.15);
if(e.auto>now)target=Math.max(target,.85);
target=Math.min(1,target+0.04*Math.sin(now*0.0012+e.seed));
e.open+=(target-e.open)*0.08;
const h=30*(1-e.open);
e.lt.setAttribute('height',Math.max(0,h).toFixed(2));
e.lb.setAttribute('y',(30+30*e.open).toFixed(2));
e.lb.setAttribute('height',Math.max(0,h).toFixed(2));
let tx=0,ty=0;
if(d<400&&d>1){tx=(mouse.x-e.x)/d*6;ty=(mouse.y-e.y)/d*3.5;}
e.px+=(tx-e.px)*.12;e.py+=(ty-e.py)*.12;
e.iris.setAttribute('transform',`translate(${e.px.toFixed(2)} ${e.py.toFixed(2)})`);
e.el.style.opacity=(0.22+e.open*0.75).toFixed(2);
e.el.style.filter=`drop-shadow(0 0 ${(2+e.open*9).toFixed(1)}px rgba(163,0,0,${(0.15+e.open*0.55).toFixed(2)}))`;
});
requestAnimationFrame(loop);
})();
}
/* --- Плавный параллакс колец --- */
function initParallax(){
const rings=$('abyss-rings');let mx=0,my=0,tx=0,ty=0;
addEventListener('mousemove',e=>{tx=e.clientX/innerWidth-.5;ty=e.clientY/innerHeight-.5;});
(function loop(){mx+=(tx-mx)*.03;my+=(ty-my)*.03;
rings.style.transform=`translate(${(mx*-22).toFixed(1)}px,${(my*-15).toFixed(1)}px)`;requestAnimationFrame(loop);})();
}
/* ==================== КАРТОЧКИ ==================== */
function buildCard(frontBuilder,wide=false){
const wrap=document.createElement('div');
wrap.className='gcard-wrap'+(wide?' wide':'');
wrap.innerHTML=`<div class="gcard"><div class="gface gface-rune"><span class="tq">${TQ}</span><span class="rune-x">✕ ✕ ✕</span></div><div class="gface gface-content"></div></div>`;
frontBuilder(wrap.querySelector('.gface-content'));
return wrap;
}
function attachTilt(wrap){
const card=wrap.querySelector('.gcard');
wrap.addEventListener('mousemove',e=>{
if(!card.classList.contains('flipped'))return;
const r=wrap.getBoundingClientRect();
const rx=((e.clientY-r.top)/r.height-.5)*-8,ry=((e.clientX-r.left)/r.width-.5)*10;
card.style.transform=`rotateY(${180+ry}deg) rotateX(${rx}deg)`;
});
wrap.addEventListener('mouseleave',()=>{card.style.transform='';});
}
function emptyState(){return `<div class="pane-empty"><span class="tq">${TQ}</span><p>Алтарь пуст. Нажмите «Призвать», и тьма ответит.</p></div>`;}
/* ==================== РИТУАЛ ОТРЯДА ==================== */
function charFrontHTML(c){
return `<img class="char-face-img" src="${c.icon}" alt="${c.name}" onerror="this.onerror=null;this.src='https://placehold.co/96x96/0d0d0f/C41E2F?text=N/A'">
<div class="char-face-name" title="${c.name}">${c.name}</div>
<div class="char-face-el"><img src="pic/Elements/Element_${c.element}.webp" onerror="this.style.display='none'" alt="">${c.element}</div>`;
}
async function spinTeam(){
if(isSpinning)return;
const pool=playerCharacters.length>0?playerCharacters:allCharacters;
const dist=getDistribution(playerCount),need=dist.reduce((a,b)=>a+b,0);
if(pool.length<need){warn(`Недостаточно душ для ритуала: нужно ${need}, доступно ${pool.length}.`);return;}
isSpinning=true;spinBtn.disabled=true;document.body.classList.add('dimmed');
$('actions-team').classList.add('hidden');
await veil();
document.body.classList.remove('dimmed');
const charsPool=[...pool],result=[];
const area=$('team-area');area.innerHTML='';
const allWraps=[];
for(let p=0;p<playerCount;p++){
const grp=document.createElement('div');grp.className='player-group';
const isHost=playerCount===3&&p===0;
grp.innerHTML=`<div class="player-group-title ${isHost?'host':''}">${getPlayerLabel(p,playerCount)} · ${dist[p]} перс.</div><div class="cards-row"></div>`;
area.appendChild(grp);
const row=grp.querySelector('.cards-row');
const pChars=[];
for(let c=0;c<dist[p];c++){
const picked=charsPool.splice(Math.floor(Math.random()*charsPool.length),1)[0];
pChars.push(picked);
const wrap=buildCard(el=>el.innerHTML=charFrontHTML(picked));
wrap.classList.add('pop-in');wrap.style.animationDelay=(allWraps.length*70)+'ms';
attachTilt(wrap);row.appendChild(wrap);allWraps.push(wrap);
}
result.push({label:getPlayerLabel(p,playerCount),host:isHost,chars:pChars});
}
session.team={count:playerCount,groups:result};saveSession();
const speed=config.animationSpeed;
const baseDelay=speed==='fast'?220:speed==='slow'?560:380;
setTimeout(()=>{
allWraps.forEach((w,i)=>setTimeout(()=>{
w.querySelector('.gcard').classList.add('flipped');
boomSound.currentTime=0;boomSound.play().catch(()=>{});
},i*baseDelay));
setTimeout(()=>{isSpinning=false;spinBtn.disabled=false;$('actions-team').classList.remove('hidden');},allWraps.length*baseDelay+600);
},allWraps.length*70+420);
}
function renderTeamInstant(){
if(!session.team)return;
playerCount=session.team.count;
const area=$('team-area');area.innerHTML='';
session.team.groups.forEach(g=>{
const grp=document.createElement('div');grp.className='player-group';
grp.innerHTML=`<div class="player-group-title ${g.host?'host':''}">${g.label} · ${g.chars.length} перс.</div><div class="cards-row"></div>`;
const row=grp.querySelector('.cards-row');
g.chars.forEach(c=>{
const wrap=buildCard(el=>el.innerHTML=charFrontHTML(c));
attachTilt(wrap);row.appendChild(wrap);
const card=wrap.querySelector('.gcard');card.classList.add('instant','flipped');
});
area.appendChild(grp);
});
$('actions-team').classList.remove('hidden');
}
/* ==================== РИТУАЛ БОССА ==================== */
async function spinBoss(){
if(isSpinning)return;
isSpinning=true;spinBtn.disabled=true;document.body.classList.add('dimmed');
$('actions-boss').classList.add('hidden');
await veil();document.body.classList.remove('dimmed');
const data=currentBossType==='world'?{list:WORLD_BOSSES,key:'world-bosses'}:currentBossType==='weekly'?{list:WEEKLY_BOSSES,key:'weekly-bosses'}:{list:LOCAL_LEGENDS,key:'local-legends'};
const avail=data.list.filter(b=>!config.excludedBosses[data.key].includes(b.name));
const area=$('boss-area');area.innerHTML='';
if(!avail.length){area.innerHTML='<div class="pane-empty"><p style="color:var(--flame)">Все жертвы отвергнуты. Проверьте настройки боссов.</p></div>';isSpinning=false;spinBtn.disabled=false;return;}
const pick=avail[Math.floor(Math.random()*avail.length)];
session.boss={type:currentBossType,name:pick.name,icon:pick.icon,guideUrl:pick.guideUrl||null};saveSession();
renderBossCard(pick,currentBossType,true);
}
function renderBossCard(pick,type,animate){
const area=$('boss-area');area.innerHTML='';
const isLegend=type==='legend';
const wrap=buildCard(el=>{
el.innerHTML=`<img class="boss-face-img" src="${pick.icon}" alt="${pick.name}" onerror="this.onerror=null;this.src='https://placehold.co/112x112/0d0d0f/C41E2F?text=N/A'">
<div class="boss-face-name">${pick.name}</div>
<div class="boss-face-hint">${isLegend?(pick.guideUrl?'нажмите — гайд по легенде':'местная легенда'):(type==='world'?'мировой босс':'еженедельный босс')}</div>`;
if(isLegend&&pick.guideUrl){el.style.cursor='pointer';el.addEventListener('click',()=>window.open(pick.guideUrl,'_blank'));}
});
if(animate){wrap.classList.add('pop-in');attachTilt(wrap);area.appendChild(wrap);
setTimeout(()=>{wrap.querySelector('.gcard').classList.add('flipped');boomSound.currentTime=0;boomSound.play().catch(()=>{});
setTimeout(()=>{isSpinning=false;spinBtn.disabled=false;$('actions-boss').classList.remove('hidden');},750);},480);
}else{attachTilt(wrap);area.appendChild(wrap);const c=wrap.querySelector('.gcard');c.classList.add('instant','flipped');$('actions-boss').classList.remove('hidden');}
}
function renderBossInstant(){
if(!session.boss)return;
renderBossCard({name:session.boss.name,icon:session.boss.icon,guideUrl:session.boss.guideUrl},session.boss.type,false);
}
/* ==================== КОНТРАКТ РОНОВЫ ==================== */
function pickTrial(){const r=Math.random();const lv=r<.45?1:r<.8?2:3;const pool=TRIALS.filter(t=>t.level===lv);return pool[Math.floor(Math.random()*pool.length)];}
function challengeFrontHTML(ch){
let html=`<div class="contract">
<div class="contract-level"><span class="lvl">Уровень ${LEVEL_ROMAN[ch.trial.level]}</span> ${LEVEL_NAMES[ch.trial.level]}</div>
<h3 class="contract-name">«${ch.trial.name}»</h3>
<p class="contract-text">${ch.trial.text}</p>`;
if(ch.tasks&&ch.tasks.length){
html+=`<div class="contract-block"><div class="contract-block-title">Распределение ролей</div>`;
ch.tasks.forEach(t=>html+=`<div class="task-row ${t.host?'host':''}"><b>${t.player}</b><span>${t.text}</span></div>`);
html+=`</div>`;
}
if(ch.handicaps.length){
html+=`<div class="contract-block"><div class="contract-block-title">Печати Системы</div>`;
ch.handicaps.forEach(h=>html+=`<div class="handicap-row"><span class="tq">${TQ}</span><span>${h}</span></div>`);
html+=`</div>`;
}
html+=`<div class="curse-pts pts-${ch.trial.points}">☩ ${ch.trial.points} ${ch.trial.points===1?'очко':(ch.trial.points<5?'очка':'очков')} проклятия</div></div>`;
return html;
}
async function spinChallenge(){
if(isSpinning)return;
isSpinning=true;spinBtn.disabled=true;document.body.classList.add('dimmed');
$('actions-challenge').classList.add('hidden');
await veil();document.body.classList.remove('dimmed');
const trial=pickTrial();
const shuffled=[...SYSTEM_HANDICAPS].sort(()=>Math.random()-.5);
const handicaps=shuffled.slice(0,Math.random()<.25?2:1);
let tasks=[];
if(playerCount>1&&COOP_TASKS[playerCount]){
const set=COOP_TASKS[playerCount][Math.floor(Math.random()*COOP_TASKS[playerCount].length)];
tasks=set.map((t,i)=>({player:getPlayerLabel(i,playerCount),text:t.replace(/^(Хостер|Игрок \d+):\s*/,''),host:playerCount===3&&i===0}));
}
const ch={trial:{name:trial.name,text:trial.text,level:trial.level,points:trial.points},handicaps,tasks};
session.challenge=ch;saveSession();
const area=$('challenge-area');area.innerHTML='';
const wrap=buildCard(el=>el.innerHTML=challengeFrontHTML(ch),true);
if(trial.points>=5)wrap.classList.add('smoke-wrap');
const rune=wrap.querySelector('.gface-rune');
wrap.classList.add('pop-in');attachTilt(wrap);area.appendChild(wrap);
const contentH=wrap.querySelector('.gface-content').scrollHeight;
rune.style.minHeight=Math.max(320,contentH)+'px';
setTimeout(()=>{wrap.querySelector('.gcard').classList.add('flipped');boomSound.currentTime=0;boomSound.play().catch(()=>{});
setTimeout(()=>{isSpinning=false;spinBtn.disabled=false;$('actions-challenge').classList.remove('hidden');},900);},500);
}
function renderChallengeInstant(){
if(!session.challenge)return;
const area=$('challenge-area');area.innerHTML='';
const wrap=buildCard(el=>el.innerHTML=challengeFrontHTML(session.challenge),true);
if(session.challenge.trial.points>=5)wrap.classList.add('smoke-wrap');
attachTilt(wrap);area.appendChild(wrap);
const rune=wrap.querySelector('.gface-rune');
rune.style.minHeight=Math.max(320,wrap.querySelector('.gface-content').scrollHeight)+'px';
const c=wrap.querySelector('.gcard');c.classList.add('instant','flipped');
$('actions-challenge').classList.remove('hidden');
}
/* ==================== ВУАЛЬ ==================== */
function veil(){return new Promise(res=>{const v=$('summon-veil');v.classList.add('active');setTimeout(()=>{v.classList.remove('active');setTimeout(res,180);},640);});}
/* ==================== ЛЕТОПИСЬ ==================== */
function saveTeamToHistory(){
if(!session.team)return;
const chars=session.team.groups.flatMap(g=>g.chars);
historyTeams.unshift({date:new Date().toISOString(),characters:chars,name:`Отряд · ${MODE_NAMES[playerCount]}`,type:'team'});
localStorage.setItem(K('teamsHistory'),JSON.stringify(historyTeams));renderHistory();
}
function saveBossToHistory(){
if(!session.boss)return;
const t=session.boss.type==='legend'?'legend':session.boss.type==='world'?'world-boss':'weekly-boss';
historyBosses.unshift({date:new Date().toISOString(),name:session.boss.name,icon:session.boss.icon,guideUrl:session.boss.guideUrl,type:t});
localStorage.setItem(K('bossesHistory'),JSON.stringify(historyBosses));renderHistory();
}
function saveChallengeToHistory(){
if(!session.challenge)return;
const ch=session.challenge;
historyBosses.unshift({date:new Date().toISOString(),type:'challenge',cid:Date.now()+''+Math.floor(Math.random()*999),
name:ch.trial.name,text:ch.trial.text,level:ch.trial.level,points:ch.trial.points,handicaps:ch.handicaps,tasks:ch.tasks,status:'active'});
localStorage.setItem(K('bossesHistory'),JSON.stringify(historyBosses));renderHistory();
}
function setChallengeStatus(cid,st){
const e=historyBosses.find(x=>x.cid===cid);
if(e){e.status=e.status===st?'active':st;localStorage.setItem(K('bossesHistory'),JSON.stringify(historyBosses));renderHistory();}
}
function renderHistory(){
const box=$('history-content');box.innerHTML='';
const all=[...historyTeams,...historyBosses].sort((a,b)=>{
if(a.type==='challenge'&&b.type==='challenge')return (b.points-a.points)||(new Date(b.date)-new Date(a.date));
if(a.type==='challenge')return -1;if(b.type==='challenge')return 1;
return new Date(b.date)-new Date(a.date);});
if(!all.length){box.innerHTML='<p class="text-center rv-sub" style="font-style:italic;">Летопись пуста... заключите свой первый контракт.</p>';$('clear-history-button').classList.add('hidden');return;}
$('clear-history-button').classList.remove('hidden');
all.forEach(item=>{
const d=new Date(item.date).toLocaleString('ru-RU');
const el=document.createElement('div');
if(item.type==='challenge'){
el.className=`chron-item st-${item.status}${item.points>=5?' flame-high':''}`;
el.innerHTML=`<div class="chron-head"><div class="ch-status"><span class="tq">${TQ}</span></div>
<div class="chron-title">Контракт «${item.name}» · Ур. ${LEVEL_ROMAN[item.level]} · <span class="pts-${item.points}" style="padding:1px 8px;">${item.points} ☩</span></div>
<div class="chron-date">${d}</div></div>
<p class="rv-sub" style="font-size:.82rem;line-height:1.6;margin:0 0 10px;">${item.text}</p>
${(item.tasks&&item.tasks.length)?`<div style="margin-bottom:8px;">${item.tasks.map(t=>`<div class="task-row ${t.host?'host':''}"><b>${t.player}</b><span>${t.text}</span></div>`).join('')}</div>`:''}
${(item.handicaps&&item.handicaps.length)?item.handicaps.map(h=>`<div class="handicap-row"><span class="tq">${TQ}</span><span>${h}</span></div>`).join(''):''}
<div class="status-btns" style="margin-top:10px;">
<button data-st="success" class="${item.status==='success'?'sel-ok':''}">✓ Выполнено</button>
<button data-st="fail" class="${item.status==='fail'?'sel-fail':''}">✗ Провалено</button>
</div>`;
el.querySelectorAll('.status-btns button').forEach(b=>b.addEventListener('click',()=>setChallengeStatus(item.cid,b.dataset.st)));
}else if(item.type==='team'){
el.className='chron-item';
el.innerHTML=`<div class="chron-head"><div class="chron-title">${item.name}</div><div class="chron-date">${d}</div></div><div class="chron-cards"></div>`;
const cc=el.querySelector('.chron-cards');
item.characters.forEach(c=>{
const m=document.createElement('div');m.className='mini-char';
m.innerHTML=`<img src="${c.icon}" onerror="this.onerror=null;this.src='https://placehold.co/56x56/0d0d0f/C41E2F?text=N/A'"><p>${c.name}</p>`;
cc.appendChild(m);});
}else{
el.className='chron-item';
const tl=item.type==='legend'?'Местная легенда':item.type==='world-boss'?'Мировой босс':'Еженедельный босс';
el.innerHTML=`<div class="chron-head"><div class="chron-title">${tl} · ${item.name}</div><div class="chron-date">${d}</div></div>
<div class="chron-cards"><div class="mini-char"><img src="${item.icon}" onerror="this.onerror=null;this.src='https://placehold.co/56x56/0d0d0f/C41E2F?text=N/A'"><p>${item.name}</p></div></div>`;
}
box.appendChild(el);
});
}
function clearHistory(){
historyTeams=[];historyBosses=[];
localStorage.removeItem(K('teamsHistory'));localStorage.removeItem(K('bossesHistory'));
renderHistory();
}
/* ==================== НАСТРОЙКИ ==================== */
function renderBossSettings(){
const cat=$('boss-category-select').value;
const bosses=cat==='world-bosses'?WORLD_BOSSES:cat==='weekly-bosses'?WEEKLY_BOSSES:LOCAL_LEGENDS;
const box=$('bosses-settings-container');box.innerHTML='';
bosses.forEach(boss=>{
const ex=config.excludedBosses[cat].includes(boss.name);
const row=document.createElement('div');row.className='boss-toggle';
const id=`bs-${cat}-${boss.name.replace(/[^\wа-яё-]/gi,'')}`;
row.innerHTML=`<input type="checkbox" id="${id}" ${ex?'':'checked'}><label for="${id}">${boss.name}</label>`;
box.appendChild(row);
row.querySelector('input').addEventListener('change',e=>{
const list=config.excludedBosses[cat];
if(e.target.checked){const i=list.indexOf(boss.name);if(i>-1)list.splice(i,1);}
else if(!list.includes(boss.name))list.push(boss.name);
localStorage.setItem(K('excludedBosses'),JSON.stringify(config.excludedBosses));
});
});
}
function renderCharSelection(filter=''){
const box=$('player-characters-selection');box.innerHTML='';
allCharacters.filter(c=>c.name.toLowerCase().includes(filter.toLowerCase())).forEach(c=>{
const sel=playerCharacters.some(x=>x.name===c.name);
const card=document.createElement('div');
card.className='player-char-card'+(sel?' selected':'');
card.innerHTML=`<img class="avatar" src="${c.icon}" style="border-color:${sel?'var(--flame)':'#2c2c31'}" onerror="this.onerror=null;this.src='https://placehold.co/44x44/0d0d0f/C41E2F?text=N/A'">
<p>${c.name}</p>${sel?'<button class="remove-btn">×</button>':''}`;
card.addEventListener('click',e=>{
if(e.target.classList.contains('remove-btn')){playerCharacters=playerCharacters.filter(x=>x.name!==c.name);}
else{const i=playerCharacters.findIndex(x=>x.name===c.name);if(i>-1)playerCharacters.splice(i,1);else playerCharacters.push(c);}
localStorage.setItem(K('playerCharacters'),JSON.stringify(playerCharacters));
renderCharSelection($('character-search').value);
});
box.appendChild(card);
});
$('clear-player-characters').classList.toggle('hidden',playerCharacters.length===0);
}
/* ==================== МОДАЛКИ ==================== */
function openModal(m,c){m.classList.remove('hidden');setTimeout(()=>{c.classList.remove('scale-95','opacity-0');c.classList.add('scale-100','opacity-100');},10);}
function closeModal(m,c){c.classList.add('scale-95','opacity-0');c.classList.remove('scale-100','opacity-100');setTimeout(()=>m.classList.add('hidden'),300);}
function confirmModal(msg,cb){
const m=document.createElement('div');
m.className='fixed inset-0 z-[200] flex justify-center items-center p-4';
m.style.cssText='background:rgba(0,0,0,.6);backdrop-filter:blur(6px);';
m.innerHTML=`<div class="modal-panel w-full max-w-sm relative text-center p-8">
<h3 class="f-display" style="font-size:1.1rem;font-weight:700;margin:0 0 16px;">Подтверждение</h3>
<p class="rv-sub" style="font-size:.88rem;line-height:1.6;margin-bottom:24px;">${msg}</p>
<div class="flex justify-center gap-3"><button class="rv-btn c-no">Отмена</button><button class="rv-btn rv-btn-danger c-yes">Да, сжечь</button></div></div>`;
document.body.appendChild(m);
m.querySelector('.c-no').addEventListener('click',()=>m.remove());
m.querySelector('.c-yes').addEventListener('click',()=>{cb();m.remove();});
m.addEventListener('click',e=>{if(e.target===m)m.remove();});
}
/* ==================== НАВИГАЦИЯ ==================== */
function updateStage(){
const titles={team:'Призыв Отряда',boss:'Призыв Босса',challenge:'Контракт Роновы'};
const descs={
team:`Режим: ${MODE_NAMES[playerCount]} · ${getDistribution(playerCount).map((d,i)=>`${getPlayerLabel(i,playerCount)} = ${d}`).join(' · ')}`,
boss:`Лик жертвы: ${currentBossType==='world'?'Мировые боссы':currentBossType==='weekly'?'Еженедельные боссы':'Местные легенды'}`,
challenge:`Проклятие будет выбрано по режиму: ${MODE_NAMES[playerCount]}`};
$('stage-title').textContent=titles[currentCategory];
$('topbar-title').textContent=titles[currentCategory];
$('stage-desc').textContent=descs[currentCategory];
['team','boss','challenge'].forEach(t=>$('pane-'+t).classList.toggle('hidden',t!==currentCategory));
$('boss-sub-settings').classList.toggle('hidden',currentCategory!=='boss');
}
function totalCharsUpdate(){$('total-chars').textContent=getDistribution(playerCount).reduce((a,b)=>a+b,0);}
document.querySelectorAll('#player-count-selector .btn-metal').forEach(b=>{
b.addEventListener('click',()=>{
document.querySelectorAll('#player-count-selector .btn-metal').forEach(x=>x.classList.remove('active'));
b.classList.add('active');b.classList.add('flash');setTimeout(()=>b.classList.remove('flash'),450);
playerCount=parseInt(b.dataset.val);totalCharsUpdate();updateStage();saveSession();
});
});
document.querySelectorAll('#category-selector .btn-metal').forEach(b=>{
b.addEventListener('click',()=>{
document.querySelectorAll('#category-selector .btn-metal').forEach(x=>x.classList.remove('active'));
b.classList.add('active');b.classList.add('flash');setTimeout(()=>b.classList.remove('flash'),450);
currentCategory=b.dataset.cat;updateStage();saveSession();
if(innerWidth<1024)sidebar.classList.remove('open');
});
});
document.querySelectorAll('#boss-type-selector .btn-metal').forEach(b=>{
b.addEventListener('click',()=>{
document.querySelectorAll('#boss-type-selector .btn-metal').forEach(x=>x.classList.remove('active'));
b.classList.add('active');b.classList.add('flash');setTimeout(()=>b.classList.remove('flash'),450);
currentBossType=b.dataset.type;updateStage();saveSession();
if(session.boss&&session.boss.type!==currentBossType){$('boss-area').innerHTML=emptyState();$('actions-boss').classList.add('hidden');session.boss=null;saveSession();}
});
});
spinBtn.addEventListener('click',()=>{
if(currentCategory==='team')spinTeam();
else if(currentCategory==='boss')spinBoss();
else spinChallenge();
});
$('reroll-team-btn').addEventListener('click',spinTeam);
$('reroll-boss-btn').addEventListener('click',spinBoss);
$('reroll-challenge-btn').addEventListener('click',spinChallenge);
$('save-team-btn').addEventListener('click',()=>{saveTeamToHistory();warn('Отряд вписан в Летопись.');});
$('save-boss-btn').addEventListener('click',()=>{saveBossToHistory();warn('Жертва вписана в Летопись.');});
$('save-challenge-btn').addEventListener('click',()=>{saveChallengeToHistory();warn('Контракт скреплён печатью в Летописи.');});
$('settings-toggle').addEventListener('click',()=>{if(innerWidth<1024)sidebar.classList.remove('open');openModal($('settings-modal'),$('settings-modal-content'));});
$('settings-close').addEventListener('click',()=>closeModal($('settings-modal'),$('settings-modal-content')));
$('settings-modal').addEventListener('click',e=>{if(e.target===$('settings-modal'))closeModal($('settings-modal'),$('settings-modal-content'));});
$('history-toggle').addEventListener('click',()=>{if(innerWidth<1024)sidebar.classList.remove('open');openModal($('history-modal'),$('history-modal-content'));});
$('history-close').addEventListener('click',()=>closeModal($('history-modal'),$('history-modal-content')));
$('history-modal').addEventListener('click',e=>{if(e.target===$('history-modal'))closeModal($('history-modal'),$('history-modal-content'));});
$('about-toggle').addEventListener('click',()=>{if(innerWidth<1024)sidebar.classList.remove('open');openModal($('about-modal'),$('about-modal-content'));});
$('about-close').addEventListener('click',()=>closeModal($('about-modal'),$('about-modal-content')));
$('about-modal').addEventListener('click',e=>{if(e.target===$('about-modal'))closeModal($('about-modal'),$('about-modal-content'));});
$('author-link').addEventListener('click',()=>openModal($('about-modal'),$('about-modal-content')));
$('clear-history-button').addEventListener('click',()=>confirmModal('Сжечь всю Летопись Контрактов? Пепел не вернуть.',clearHistory));
$('clear-player-characters').addEventListener('click',()=>confirmModal('Снять все отметки с персонажей?',()=>{playerCharacters=[];localStorage.removeItem(K('playerCharacters'));renderCharSelection('');}));
$('character-search').addEventListener('input',e=>renderCharSelection(e.target.value));
$('boss-category-select').addEventListener('change',renderBossSettings);
$('animation-speed').addEventListener('change',e=>{config.animationSpeed=e.target.value;localStorage.setItem(K('animSpeed'),config.animationSpeed);});
document.querySelectorAll('.settings-tab').forEach(t=>{
t.addEventListener('click',()=>{
document.querySelectorAll('.settings-tab').forEach(x=>x.classList.remove('active'));
document.querySelectorAll('.settings-tab-result').forEach(x=>x.classList.add('hidden'));
t.classList.add('active');$('tab-'+t.dataset.tab).classList.remove('hidden');
});
});
$('mobile-menu-btn').addEventListener('click',()=>sidebar.classList.toggle('open'));
document.addEventListener('click',e=>{
if(innerWidth<1024&&sidebar.classList.contains('open')&&!sidebar.contains(e.target)&&!$('mobile-menu-btn').contains(e.target))sidebar.classList.remove('open');
});
/* ==================== ИНИЦИАЛИЗАЦИЯ ==================== */
document.querySelectorAll('#player-count-selector .btn-metal').forEach(b=>b.classList.toggle('active',parseInt(b.dataset.val)===playerCount));
document.querySelectorAll('#category-selector .btn-metal').forEach(b=>b.classList.toggle('active',b.dataset.cat===currentCategory));
document.querySelectorAll('#boss-type-selector .btn-metal').forEach(b=>b.classList.toggle('active',b.dataset.type===currentBossType));
$('animation-speed').value=config.animationSpeed;
$('boss-category-select').value='world-bosses';
$('team-area').innerHTML=emptyState();
$('boss-area').innerHTML=emptyState();
$('challenge-area').innerHTML=emptyState();
initMusic();initEmbers();initEyes();initParallax();
renderCharSelection();renderHistory();renderBossSettings();
totalCharsUpdate();updateStage();saveSession();
renderTeamInstant();renderBossInstant();renderChallengeInstant();
});
</script>
</body>
</html>