Files
shooting-event/live Score.html
2026-03-31 12:49:43 +04:00

1012 lines
66 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>بطولة دويتوايلر للرماية - Tracker</title>
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Cairo:wght@400;600;700;800&family=DM+Mono:wght@400;500;600;800&display=swap" rel="stylesheet">
<style>
:root {
--navy: #1B1F40;
--red: #EC2F23;
--teal: #008CA8;
--white: #FFFFFF;
--bg:#F5F6FA;--surface:#FFFFFF;--card:#FFFFFF;--border:#D8DCE8;
--accent:var(--red);--gold:#D4920A;--silver:#6B7A99;--bronze:#CD7F32;
--green:#00956A;
--text:var(--navy);--muted:#6B7A99;
--ga:var(--navy);--ga-l:rgba(27,31,64,.08);
--gb:var(--teal);--gb-l:rgba(0,140,168,.08);
--gc:var(--red);--gc-l:rgba(236,47,35,.07);
--gd:#D4920A;--gd-l:rgba(212,146,10,.08);
}
*{box-sizing:border-box;margin:0;padding:0;}
body{background:#F0F2F8;color:var(--text);font-family:'Cairo', sans-serif;font-size:16px;min-height:100vh;}
.masthead{background:#FFFFFF;border-bottom:none;padding:0;position:relative;overflow:hidden;box-shadow:0 2px 20px rgba(13,27,46,.08);}
.masthead::before{content:"";position:absolute;bottom:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--navy) 0%,var(--navy) 33%,var(--teal) 33%,var(--teal) 66%,var(--red) 66%,var(--red) 100%);}
@keyframes pulseDot{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.4)}}
@keyframes fadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.masthead-title{font-family:'Cairo',sans-serif;font-size:46px;letter-spacing:1px;color:var(--navy);line-height:1; font-weight: 800;}
.masthead-sub{color:#5A6280;font-size:16px;letter-spacing:1px;text-transform:uppercase;margin-top:8px;font-weight:700;}
.tab-bar{display:flex;background:var(--navy);border-bottom:none;padding:0;overflow-x:auto;position:sticky;top:0;z-index:100;box-shadow:0 4px 16px rgba(27,31,64,.25);}
.tab{flex:1;padding:18px 14px;cursor:pointer;font-size:14px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:rgba(255,255,255,.5);border-bottom:3px solid transparent;border-right:1px solid rgba(255,255,255,.08);white-space:nowrap;transition:all .2s;background:none;border-top:none;border-left:none;text-align:center;font-family:'Cairo',sans-serif;}
.tab:hover{color:#ffffff;background:rgba(255,255,255,.08);}
.tab.active{color:#ffffff;border-bottom:3px solid var(--red);font-weight:700;background:rgba(236,47,35,.15);}
.panel{display:none;padding:32px 32px 64px;animation:fadeIn .25s ease;background:#F0F2F8;}
.panel.active{display:block;}
.sec-title{font-family:'Cairo',sans-serif;font-size:32px;font-weight:800;color:var(--navy);margin-bottom:6px;padding-bottom:10px;border-bottom:3px solid var(--navy);display:inline-block;}
.sec-sub{color:#6B7A99;font-size:15px;margin-bottom:20px;font-family:'Cairo',sans-serif; font-weight:600;}
.tbl-wrap{overflow-x:auto;border-radius:12px;border:2px solid #C8CCD8;margin-bottom:28px;box-shadow:0 4px 16px rgba(27,31,64,.10);background:#FFFFFF;}
table{width:100%;border-collapse:collapse;}
thead tr{background:var(--navy);}
thead th{padding:14px 16px;font-size:12px;text-transform:uppercase;letter-spacing:1px;color:#7AAAD8;font-weight:700;text-align:center;border-left:1px solid rgba(255,255,255,.12);white-space:nowrap;font-family:'Cairo',sans-serif;}
thead th:last-child{border-left:none;}
tbody tr{border-bottom:1px solid #D8DCE8;transition:background .15s;}
tbody tr:last-child{border-bottom:none;}
tbody tr:hover{background:#F5F7FF;}
tbody td{padding:13px 16px;text-align:center;border-left:1px solid #D8DCE8;vertical-align:middle;white-space:nowrap;color:var(--text);}
tbody td:last-child{border-left:none;}
.competitor-cell { display:flex; align-items:center; gap:20px; justify-content:flex-start; }
.competitor-img { width: 84px; height: 84px; border-radius: 50%; object-fit: cover; border: 3px solid #E2E6EF; background: #F0F2F8; flex-shrink: 0; transition: transform 0.2s; box-shadow: 0 4px 12px rgba(0,0,0,0.08);}
.clickable-img { cursor: pointer; border-color: var(--teal); }
.clickable-img:hover { transform: scale(1.05); box-shadow: 0 6px 16px rgba(0,140,168,.3); }
.editable-name { border: 1px dashed transparent; padding: 4px 8px; border-radius: 6px; transition: all 0.2s; outline: none; display: inline-block; min-width: 60px;}
.editable-name:hover { border-color: #B8C8E8; background: #F8FAFC; cursor: text; }
.editable-name:focus { border-color: var(--teal); background: #FFF; box-shadow: 0 0 0 3px rgba(0,140,168,.1); }
.td-name{text-align:right;font-weight:800;font-size:20px;white-space:nowrap;font-family:'Cairo',sans-serif;}
.td-en{text-align:left;color:var(--text);font-family:'DM Mono',monospace;font-size:15px;font-weight:600;white-space:nowrap; direction:ltr; display:inline-block;}
.td-num{font-family:'DM Mono',monospace;font-weight:600;font-size:15px;color:#6B7A99;}
.td-total{font-weight:800;font-size:18px;color:var(--text);font-family:'DM Mono',monospace;}
.td-rank{font-family:'Bebas Neue',monospace;font-size:24px;color:#D4920A;}
.grp-hdr td{font-family:'Cairo',sans-serif;font-size:18px;font-weight:800;letter-spacing:1px;padding:12px 18px;text-align:right!important;color:#fff!important;}
.grp-sep td{padding:6px;background:#F0F2F8!important;border:none!important;}
.grp-a td{background:var(--navy);border-left-color:rgba(255,255,255,.15)!important;}
.grp-b td{background:var(--teal);border-left-color:rgba(255,255,255,.15)!important;}
.grp-c td{background:var(--red);border-left-color:rgba(255,255,255,.15)!important;}
.grp-d td{background:#D4920A;border-left-color:rgba(255,255,255,.15)!important;}
.ga-row{background:rgba(27,31,64,.04);}
.gb-row{background:rgba(0,140,168,.04);}
.gc-row{background:rgba(236,47,35,.03);}
.gd-row{background:rgba(212,146,10,.04);}
.medal-qualify{background:linear-gradient(-90deg,rgba(0,149,106,.08),transparent);}
.medal-icon{font-size:22px;text-align:center;}
.q-badge{display:inline-block;background:rgba(0,140,168,.1);border:1.5px solid var(--teal);color:var(--teal);border-radius:20px;padding:3px 12px;font-size:12px;font-weight:700;letter-spacing:.5px;}
.no-q{color:#A0AABC;font-size:14px;}
.grp-pill{display:inline-block;font-family:'Bebas Neue',sans-serif;font-size:20px;letter-spacing:1px;padding:3px 16px;border-radius:20px;}
.pill-a{background:var(--navy);color:#fff;}.pill-b{background:var(--teal);color:#fff;}.pill-c{background:var(--red);color:#fff;}.pill-d{background:#D4920A;color:#fff;}
.summary-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:16px;margin-bottom:32px;}
.sum-card{background:#FFFFFF;border:2px solid #D8DCE8;border-radius:16px;padding:24px 16px 20px;text-align:center;box-shadow:0 4px 16px rgba(27,31,64,.10);transition:all .2s;}.sum-card:hover{transform:translateY(-4px);box-shadow:0 10px 32px rgba(27,31,64,.16);}
.sum-card .big{font-family:'Bebas Neue',sans-serif;font-size:56px;line-height:1;}
.sum-card .lbl{font-size:12px;color:#6B7A99;text-transform:uppercase;letter-spacing:1px;margin-top:8px;font-family:'Cairo',sans-serif;font-weight:700;}
.sum-card .st{font-size:14px;margin-top:8px;font-weight:700;}
.sum-card.ca{background:rgba(27,31,64,.04);border-top:5px solid var(--navy);}.sum-card.ca .big{color:var(--navy);}.sum-card.cb{background:rgba(0,140,168,.04);border-top:5px solid var(--teal);}.sum-card.cb .big{color:var(--teal);}.sum-card.cc{background:rgba(236,47,35,.04);border-top:5px solid var(--red);}.sum-card.cc .big{color:var(--red);}.sum-card.cd{background:rgba(212,146,10,.04);border-top:5px solid #D4920A;}.sum-card.cd .big{color:#D4920A;}.sum-card.cu{background:rgba(27,31,64,.04);border-top:5px solid #B0B8CC;}.sum-card.cu .big{color:#8896B0;}
.st-ok{color:#007A60;font-weight:700;font-size:14px;}.st-warn{color:var(--red);font-weight:700;font-size:14px;}
.tie-info{background:#FFF5F6;border:1px solid rgba(236,47,35,.2);border-radius:10px;padding:16px 22px;margin-bottom:24px;font-size:15px;color:var(--red);line-height:1.8;}
.info-note{background:#F0FBFD;border-right:5px solid var(--teal);padding:14px 18px;border-radius:10px 0 0 10px;font-size:15px;color:var(--navy);margin-bottom:22px;font-weight:600;}
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:24px;}
@media(max-width:700px){.two-col{grid-template-columns:1fr;}}
.sub-hdr{font-family:'Cairo',sans-serif;font-weight:800;letter-spacing:1px;font-size:20px;margin-bottom:12px;}
.grp-select{background:#FFFFFF;color:var(--text);border:1.5px solid #C8D8F0;border-radius:7px;padding:6px 10px;font-family:'Cairo',sans-serif;font-size:14px;font-weight:700;cursor:pointer;outline:none;transition:border-color .2s;}
.grp-select:focus{border-color:var(--teal);}
.grp-select.sel-a{background:var(--navy);color:#fff;border-color:var(--navy);}
.grp-select.sel-b{background:var(--teal);color:#fff;border-color:var(--teal);}
.grp-select.sel-c{background:var(--red);color:#fff;border-color:var(--red);}
.grp-select.sel-d{background:#D4920A;color:#fff;border-color:#D4920A;}
.btn-reset{background:#FFF8F8;border:2px solid var(--red);color:var(--red);border-radius:8px;padding:9px 22px;font-size:14px;font-weight:700;cursor:pointer;letter-spacing:0.5px;transition:all .2s;font-family:'Cairo',sans-serif;}
.btn-reset:hover{background:#FFE8EB;}
.btn-row{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:16px;align-items:center;}
.btn-set{background:#F0FBFD;border:2px solid var(--teal);color:var(--teal);border-radius:8px;padding:9px 22px;font-size:14px;font-weight:700;cursor:pointer;letter-spacing:0.5px;transition:all .2s;font-family:'Cairo',sans-serif;}
.btn-set:hover{background:#E0F5EE;border-color:#00956A; color:#00956A;}
.btn-save{background:var(--teal);color:#fff;border:2px solid var(--teal);border-radius:8px;padding:9px 22px;font-size:14px;font-weight:700;cursor:pointer;letter-spacing:0.5px;transition:all .2s;font-family:'Cairo',sans-serif; box-shadow: 0 4px 10px rgba(0,140,168,0.2);}
.btn-save:hover{background:#007A94;border-color:#007A94; transform: translateY(-2px); box-shadow: 0 6px 14px rgba(0,140,168,0.3);}
.btn-lock { background: var(--navy); color: #fff; border: 2px solid var(--navy); border-radius: 8px; padding: 9px 22px; font-size: 14px; font-weight: 700; cursor: pointer; transition: all .2s; font-family: 'Cairo', sans-serif;}
.btn-lock:hover { background: #0E132B; border-color: #0E132B; }
.btn-unlock { background: #FFFDF5; border: 2px solid #D4920A; color: #D4920A; border-radius: 8px; padding: 9px 22px; font-size: 14px; font-weight: 700; cursor: pointer; transition: all .2s; font-family: 'Cairo', sans-serif; }
.btn-unlock:hover { background: #FFF8E6; }
.score-input{width:62px;background:#F0FBFD;color:#007A94;font-family:'DM Mono',monospace;font-weight:700;font-size:16px;border:1.5px solid var(--teal);border-radius:6px;padding:5px 8px;text-align:center;outline:none;transition:all .2s;}
.score-input:focus{border-color:var(--teal);background:rgba(0,140,168,.15);box-shadow:0 0 0 3px rgba(0,140,168,.15);}
.score-input.invalid{border-color:var(--red);background:rgba(236,47,35,.12);color:var(--red);}
.score-input:disabled { background: #E2E6EF; color: #6B7A99; border-color: #C8CCD8; cursor: not-allowed; box-shadow: none; }
.tb-none{background:#F0FBF7;border:1.5px solid #00956A;border-radius:10px;padding:18px 24px;color:#00956A;font-size:16px;font-weight:700;margin-bottom:20px;}
.tb-group-title{font-family:'Cairo',sans-serif;font-weight:800;font-size:20px;margin:22px 0 12px;color:var(--navy);}
.tb-tied-score{background:#FFF0F2;border:1px solid rgba(236,47,35,.3);border-radius:6px;padding:4px 12px;font-family:'DM Mono',monospace;font-size:14px;color:var(--red);margin-right:10px;}
/* --- PROFESSIONAL PODIUM CSS --- */
.podium-wrapper { display: flex; justify-content: center; align-items: flex-end; height: 380px; margin-top: 100px; gap: 15px; padding: 0 20px; direction: ltr;}
.podium-col { flex: 1; max-width: 280px; display: flex; flex-direction: column; align-items: center; position: relative; background: #fff; border-radius: 16px 16px 0 0; box-shadow: 0 10px 40px rgba(13,27,46,0.1); transition: transform 0.3s ease; }
.podium-col:hover { transform: translateY(-5px); }
.podium-col.pos-1 { height: 320px; border-top: 8px solid #D4AF37; background: linear-gradient(180deg, #FFFAF0 0%, #FFFFFF 100%); z-index: 3; box-shadow: 0 15px 50px rgba(212, 175, 55, 0.2); }
.podium-col.pos-2 { height: 240px; border-top: 8px solid #C0C0C0; background: linear-gradient(180deg, #F8F9FA 0%, #FFFFFF 100%); z-index: 2; }
.podium-col.pos-3 { height: 180px; border-top: 8px solid #CD7F32; background: linear-gradient(180deg, #FFF5E6 0%, #FFFFFF 100%); z-index: 1; }
.podium-avatar-wrap { position: absolute; top: -65px; left: 50%; transform: translateX(-50%); }
.podium-col.pos-1 .podium-avatar-wrap { top: -85px; }
.podium-img { width: 120px; height: 120px; border-radius: 50%; object-fit: cover; border: 5px solid #fff; box-shadow: 0 8px 24px rgba(0,0,0,0.12); background: #F0F2F8; }
.podium-col.pos-1 .podium-img { width: 160px; height: 160px; border: 6px solid #D4AF37; box-shadow: 0 12px 30px rgba(212, 175, 55, 0.3);}
.podium-col.pos-2 .podium-img { border-color: #C0C0C0; }
.podium-col.pos-3 .podium-img { border-color: #CD7F32; }
.podium-medal-icon { font-size: 46px; margin-top: 65px; line-height: 1; }
.podium-col.pos-1 .podium-medal-icon { font-size: 64px; margin-top: 85px; }
.podium-name { font-family: 'Cairo', sans-serif; font-size: 24px; font-weight: 800; color: var(--navy); margin-top: 10px; text-align: center; line-height: 1.2; padding: 0 10px;}
.podium-col.pos-1 .podium-name { font-size: 28px; }
.podium-name.empty { color: #8896B0; font-weight: 600; font-size: 20px; }
.podium-score { margin-top: auto; margin-bottom: 25px; background: rgba(0,0,0,0.04); padding: 8px 20px; border-radius: 20px; font-family: 'DM Mono', monospace; font-size: 20px; font-weight: 700; color: var(--red); border: 1px solid rgba(0,0,0,0.05); }
/* --- AUTH MODAL CSS --- */
.auth-overlay { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(13,27,46,0.6); display:none; align-items:center; justify-content:center; z-index:999; backdrop-filter:blur(4px); }
.auth-box { background:#fff; padding:32px; border-radius:16px; width:340px; box-shadow:0 10px 40px rgba(0,0,0,0.2); text-align:center; animation:fadeIn 0.2s ease; border-top: 6px solid var(--red); }
.auth-input { width:100%; background:#F0F2F8; border:2px solid #D8DCE8; border-radius:8px; padding:10px 14px; font-family:'Cairo', sans-serif; font-size:16px; font-weight:600; margin-bottom:12px; outline:none; transition: border-color 0.2s; }
.auth-input:focus { border-color: var(--teal); background: #fff; }
/* --- TOAST NOTIFICATION CSS --- */
.toast-notification {
visibility: hidden;
min-width: 250px;
background-color: var(--green);
color: white;
text-align: center;
border-radius: 8px;
padding: 16px 24px;
position: fixed;
z-index: 1000;
left: 50%;
bottom: 30px;
transform: translateX(-50%);
font-family: 'Cairo', sans-serif;
font-weight: 700;
font-size: 16px;
box-shadow: 0 8px 24px rgba(0,149,106,0.3);
opacity: 0;
transition: opacity 0.3s, bottom 0.3s, visibility 0.3s;
}
.toast-notification.show {
visibility: visible;
opacity: 1;
bottom: 50px;
}
/* --- AIRPORT SCREEN (LIVE GROUPS) CSS --- */
#live-groups.panel {
padding: 0;
background: #0d1226;
min-height: 80vh;
display: none;
flex-direction: column;
position: relative;
}
#live-groups.panel.active {
display: flex;
}
.lg-container {
flex: 1;
display: flex;
flex-direction: column;
padding: 3vh 3vw;
box-sizing: border-box;
justify-content: center;
}
.lg-header {
text-align: center;
font-size: 36px;
font-family: 'Cairo', sans-serif;
font-weight: 800;
letter-spacing: 1px;
margin-bottom: 30px;
color: #D4AF37;
text-shadow: 0 2px 10px rgba(0,0,0,0.6);
}
.lg-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
align-content: center;
}
.lg-card {
background: rgba(255,255,255,0.08);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 12px;
display: flex;
align-items: center;
padding: 15px;
gap: 20px;
}
.lg-card img {
width: 90px;
height: 90px;
border-radius: 50%;
border: 3px solid var(--teal);
object-fit: cover;
flex-shrink: 0;
}
.lg-info { display: flex; flex-direction: column; justify-content: center;}
.lg-num { font-family: 'DM Mono', monospace; font-size: 16px; color: var(--teal); font-weight: 700; margin-bottom: 4px; line-height: 1; }
.lg-name { font-family: 'Cairo', sans-serif; font-size: 24px; font-weight: 800; color: white; line-height: 1.2; margin-bottom: 4px;}
.lg-name-en { font-family: 'DM Mono', monospace; font-size: 14px; color: #8896B0; text-transform: uppercase; letter-spacing: 1px; line-height: 1;}
.lg-empty { grid-column: 1 / -1; text-align: center; color: #8896B0; font-size: 28px; margin-top: 10vh; font-family: 'Cairo', sans-serif; }
.lg-progress-bar {
position: absolute;
bottom: 0;
left: 0;
height: 6px;
background: var(--red);
width: 0%;
box-shadow: 0 0 10px var(--red);
}
@keyframes cardIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.run-progress {
animation: loadProgress 5s linear infinite;
}
@keyframes loadProgress {
0% { width: 0%; }
100% { width: 100%; }
}
</style>
</head>
<body>
<input type="file" id="image-uploader" accept="image/*" style="display:none;">
<div id="toast" class="toast-notification">✓ تم حفظ بنجاح!</div>
<div id="auth-modal" class="auth-overlay">
<div class="auth-box">
<h3 style="color:var(--navy); margin-bottom:6px; font-family:'Cairo',sans-serif; font-size:24px; font-weight:800;">صلاحية الإدارة</h3>
<p style="color:var(--muted); font-size:14px; margin-bottom:20px; font-weight:600;">يرجى إدخال بيانات الدخول للتأكيد</p>
<input type="text" id="auth-user" placeholder="اسم المستخدم (admin)" class="auth-input">
<input type="password" id="auth-pass" placeholder="كلمة المرور (12345)" class="auth-input" style="margin-bottom:16px;">
<div style="color:var(--red); font-size:14px; font-weight:700; margin-bottom:16px; display:none;" id="auth-error">بيانات الدخول غير صحيحة!</div>
<div style="display:flex; gap:12px;">
<button class="btn-set" onclick="confirmAuth()" style="flex:1; padding:10px; font-size:16px;">تأكيد</button>
<button class="btn-reset" onclick="closeAuth()" style="flex:1; padding:10px; font-size:16px; color:#6B7A99; border-color:#C8CCD8;">إلغاء</button>
</div>
</div>
</div>
<div class="masthead">
<div style="display:flex;align-items:flex-start;justify-content:space-between;padding:20px 40px 22px;position:relative;">
<div style="display:flex;flex-direction:column;gap:4px;margin-top:10px; align-items: flex-start;">
<div class="masthead-title">بطولة دويتوايلر للرماية</div>
<div class="masthead-sub" style="font-size:16px;">فئة المسدس · مسافات: 15م ← 20م ← 25م</div>
<div style="margin-top:14px;width:140px;">
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 455.88 86.28"><defs><style>.dtw-1 { fill: #eb3229; }.dtw-2 { fill: #448293; }</style></defs><g id="Layer_1-2" data-name="Layer 1"><polygon class="dtw-2" points="45.08 0 45.2 0 76.12 31.62 73.31 34.51 42.3 2.88 45.08 0"/><path class="dtw-1" d="M311.21,64.43v-15.95s-15.29-25.65-15.29-25.65l-13.64,41.91-10.09.02-3.61-10.5-4.22-12.31-.07-.19-.43-1.27c.02-.17-.05-.27-.15-.06l-8.29,24.34h-10.1s-13.96-42.89-13.96-42.89l12.23-.04,7.29,24.6,8-24.55c.05-.17.19-.15.33-.16h9.7s7.91,24.34,7.91,24.34c.03.28.1.42.23.11l7.18-24.33,24.29-.02,8.6,15.5,8.52-15.26c.07-.19.18-.23.37-.24h12.27c.14,0,.28-.02.36.06.05.06-.03.16-.11.3l-15.73,26.24c.08.14.06.22.06.32v10.59s0,.25,0,.25v4.41s0,.24,0,.24c0,.06,0,.2-.11.2h-11.54Z"/><path class="dtw-1" d="M445.95,49.59l9.93,14.82-13.35.03-8.42-12.9h-5.06s-.03,12.89-.03,12.89h-11.58s0-42.61,0-42.61h20.3c2.31,0,4.44.31,6.63.89,4.82,1.36,8.67,4.81,9.74,9.8,1.17,5.44.01,11.32-4.53,14.89-1.09.88-2.21,1.52-3.63,2.18ZM442.9,36.99c-.05-1.99-1.04-3.63-2.86-4.33-.97-.43-2.01-.55-3.1-.6h-7.89s0,10.21,0,10.21h7.77c3.27,0,6.17-1.56,6.08-5.27Z"/><path class="dtw-1" d="M150.4,48.9c-1.95,7.71-7.93,12.8-15.45,14.66-2.28.53-4.48.86-6.86.87h-16.67s0-42.59,0-42.59h16.55c2.51,0,4.84.3,7.24.87,7.37,1.78,13.23,6.7,15.16,14.18,1.01,3.93,1.05,8.01.03,12.02ZM138.82,39.71c-.74-2.87-2.69-5.1-5.38-6.3-1.66-.72-3.38-1.1-5.22-1.1h-5.2s0,21.63,0,21.63h5.32c1.79,0,3.47-.39,5.09-1.09,5.21-2.23,6.7-8.08,5.38-13.15Z"/><path class="dtw-1" d="M409.65,47.64h-20.06s0,6.75,0,6.75h22.44s0,10.05,0,10.05h-33.91s0-42.6,0-42.6h33.59s.01,10.04.01,10.04h-22.15s0,6.24,0,6.24c0,.15.1.21.26.2h19.8s0,9.32,0,9.32Z"/><polygon class="dtw-1" points="197.02 64.4 184.63 64.45 181.58 56.84 165.46 56.83 162.46 64.45 150.3 64.41 161.97 36.24 173.28 36.25 168.88 47.63 178.21 47.63 173.86 36.25 185.36 36.24 197.02 64.4"/><polygon class="dtw-1" points="217.03 64.41 205.44 64.45 205.44 32.19 192.9 32.18 192.91 21.82 229.56 21.82 229.56 32.18 217.02 32.19 217.03 64.41"/><polygon class="dtw-1" points="373.64 54.08 373.66 64.43 341.84 64.42 341.83 21.83 353.42 21.84 353.41 54.07 373.64 54.08"/><polygon class="dtw-2" points="42.27 83.36 39.48 86.28 0 46.02 2.82 43.13 42.27 83.36"/><polygon class="dtw-2" points="90.24 46.01 59.24 77.63 56.39 74.77 87.4 43.14 90.24 46.01"/><polygon class="dtw-1" points="183.64 32.17 163.66 32.19 168.07 21.52 179.26 21.52 183.64 32.17"/><polygon class="dtw-1" points="76.12 48.88 47.94 20.14 50.75 17.25 78.95 45.99 76.12 48.88"/><polygon class="dtw-1" points="62.04 46.01 42.31 25.91 45.12 23.01 64.85 43.12 62.04 46.01"/><polygon class="dtw-1" points="45.13 80.5 42.29 77.64 62.03 57.51 64.85 60.4 45.13 80.5"/><polygon class="dtw-2" points="22.58 40.24 19.73 37.39 39.47 17.26 42.29 20.14 22.58 40.24"/><polygon class="dtw-2" points="28.21 23 25.37 20.12 39.47 5.75 42.3 8.62 28.21 23"/><polygon class="dtw-2" points="14.09 48.89 5.63 40.27 8.46 37.38 16.91 46 14.09 48.89"/></g></svg>
</div>
</div>
<div style="position:absolute;top:25px;left:40px;display:flex;gap:8px;align-items:center; direction: ltr;">
<div style="width:12px;height:12px;border-radius:50%;background:var(--navy);animation:pulseDot 2s ease-in-out infinite;"></div>
<div style="width:12px;height:12px;border-radius:50%;background:var(--red);animation:pulseDot 2s ease-in-out infinite .5s;"></div>
<div style="width:12px;height:12px;border-radius:50%;background:var(--teal);animation:pulseDot 2s ease-in-out infinite 1s;"></div>
<span style="font-family:'DM Mono',monospace;font-size:16px;font-weight:800;letter-spacing:2px;color:var(--navy);text-transform:uppercase;margin-left:8px;">● LIVE TRACKER</span>
</div>
</div>
</div>
<div class="tab-bar">
<button class="tab active" onclick="show('ga',this)">توزيع المجموعات</button>
<button class="tab" onclick="show('live-groups',this)">📺 عرض المجموعات</button>
<button class="tab" onclick="show('ps',this)">المرحلة التمهيدية</button>
<button class="tab" onclick="show('or',this)">الترتيب العام</button>
<button class="tab" onclick="show('fs',this)">المرحلة النهائية</button>
<button class="tab" onclick="show('tb',this)">كسر التعادل</button>
<button class="tab" onclick="show('podium',this)">🏆 تتويج الأبطال</button>
</div>
<div id="ga" class="panel active">
<div class="sec-title">توزيع المجموعات والتحكم</div>
<div class="sec-sub">توزيع 24 متسابق على 4 مجموعات (A, B, C, D) - 6 لاعبين لكل مجموعة</div>
<div class="info-note">
<strong>إدارة المتسابقين:</strong> انقر على أي اسم لتعديله مباشرة. انقر على صورة المتسابق لرفع صورة جديدة. <strong>يتم الحفظ تلقائياً!</strong>
</div>
<div class="btn-row">
<button class="btn-save" onclick="saveGroupAssignments()">💾 حفظ التوزيع</button>
<button class="btn-reset" onclick="requireAuth(function(){ resetAllGroups(); })">✕ إفراغ المجموعات</button>
<button class="btn-set" onclick="restoreDefaults()">↺ استعادة التوزيع الأصلي</button>
<div style="margin-right:auto; display:flex; gap:12px; flex-wrap:wrap;">
<button class="btn-reset" onclick="requireAuth(function(){ clearSavedNames(); })" style="border-color:#6B7A99; color:#6B7A99; background:#F5F6FA;">🗑️ مسح الأسماء المحفوظة</button>
<button class="btn-reset" onclick="requireAuth(function(){ clearSavedImages(); })" style="border-color:#6B7A99; color:#6B7A99; background:#F5F6FA;">🗑️ مسح الصور المحفوظة</button>
</div>
</div>
<div class="summary-grid">
<div class="sum-card ca"><div class="big" id="cnt-a">0</div><div class="lbl">المجموعة A</div><div class="st" id="st-a"></div></div>
<div class="sum-card cb"><div class="big" id="cnt-b">0</div><div class="lbl">المجموعة B</div><div class="st" id="st-b"></div></div>
<div class="sum-card cc"><div class="big" id="cnt-c">0</div><div class="lbl">المجموعة C</div><div class="st" id="st-c"></div></div>
<div class="sum-card cd"><div class="big" id="cnt-d">0</div><div class="lbl">المجموعة D</div><div class="st" id="st-d"></div></div>
<div class="sum-card cu"><div class="big" id="cnt-u">0</div><div class="lbl">غير معين</div><div class="st" id="st-u"></div></div>
</div>
<div class="tbl-wrap"><table>
<thead><tr><th>الرقم</th><th>صورة واسم المتسابق (انقر للتعديل)</th><th style="text-align:left">الاسم بالإنجليزي (انقر للتعديل)</th><th>المجموعة ▾</th><th>الترتيب بالمجموعة</th></tr></thead>
<tbody id="ga-body"></tbody>
</table></div>
</div>
<div id="live-groups" class="panel">
<div id="lg-container" class="lg-container"></div>
<div id="lg-progress" class="lg-progress-bar"></div>
</div>
<div id="ps" class="panel">
<div class="sec-title">المرحلة التمهيدية</div>
<div class="sec-sub">المسافة: 15 متر · 3 جولات × 10 طلقات · الحد الأقصى 100/جولة · المجموع: 300</div>
<div class="btn-row">
<button class="btn-lock" id="btn-lock-ps" onclick="lockStage('ps')">🔒 حفظ وإقفال النتائج</button>
<button class="btn-unlock" id="btn-unlock-ps" onclick="requireAuth(function(){ unlockStage('ps'); })" style="display:none;">🔓 تعديل النتائج</button>
<button class="btn-reset" onclick="requireAuth(function(){ clearAllScores('ps'); })">✕ مسح جميع النتائج (تصفير)</button>
<button class="btn-set" onclick="undoScores('ps')" id="undo-ps" disabled style="opacity:.4">↩ تراجع</button>
</div>
<div class="tbl-wrap"><table>
<thead><tr><th>الرقم</th><th>اسم المتسابق</th><th style="text-align:left">الاسم بالإنجليزي</th><th>جولة 1</th><th>جولة 2</th><th>جولة 3</th><th>المجموع /300</th><th>ترتيب المجموعة</th></tr></thead>
<tbody id="ps-body"></tbody>
</table></div>
</div>
<div id="or" class="panel">
<div class="sec-title">الترتيب العام</div>
<div class="sec-sub">حساب تلقائي من المرحلة التمهيدية · أفضل 12 يتأهلون للنهائي</div>
<div class="two-col">
<div>
<div class="sub-hdr" style="color:var(--muted)">جميع المتسابقين (24)</div>
<div class="tbl-wrap"><table>
<thead><tr><th>الرقم</th><th>اسم المتسابق</th><th>مجموعة</th><th>النتيجة /300</th><th>الترتيب</th><th>الحالة</th></tr></thead>
<tbody id="or-body"></tbody>
</table></div>
</div>
<div>
<div class="sub-hdr" style="color:var(--teal)">أفضل 12 متأهل للنهائيات</div>
<div class="tbl-wrap"><table>
<thead><tr><th>المركز</th><th>اسم المتسابق</th><th>مجموعة</th><th>النتيجة</th></tr></thead>
<tbody id="top12-body"></tbody>
</table></div>
</div>
</div>
</div>
<div id="fs" class="panel">
<div class="sec-title">المرحلة النهائية</div>
<div class="sec-sub">المسافة: 20 متر · جولتان × 10 طلقات · الحد الأقصى 100/جولة · المجموع: 200</div>
<div class="btn-row">
<button class="btn-lock" id="btn-lock-fs" onclick="lockStage('fs')">🔒 حفظ وإقفال النتائج</button>
<button class="btn-unlock" id="btn-unlock-fs" onclick="requireAuth(function(){ unlockStage('fs'); })" style="display:none;">🔓 تعديل النتائج</button>
<button class="btn-reset" onclick="requireAuth(function(){ clearAllScores('fs'); })">✕ مسح جميع النتائج (تصفير)</button>
<button class="btn-set" onclick="undoScores('fs')" id="undo-fs" disabled style="opacity:.4">↩ تراجع</button>
</div>
<div class="two-col">
<div>
<div class="sub-hdr" style="color:var(--navy)">المجموعة النهائية 1 — تصنيف 1-6</div>
<div class="tbl-wrap"><table>
<thead><tr><th>التصنيف</th><th>اسم المتسابق</th><th>جولة 1</th><th>جولة 2</th><th>المجموع /200</th><th>الترتيب</th></tr></thead>
<tbody id="fg1-body"></tbody>
</table></div>
</div>
<div>
<div class="sub-hdr" style="color:var(--teal)">المجموعة النهائية 2 — تصنيف 7-12</div>
<div class="tbl-wrap"><table>
<thead><tr><th>التصنيف</th><th>اسم المتسابق</th><th>جولة 1</th><th>جولة 2</th><th>المجموع /200</th><th>الترتيب</th></tr></thead>
<tbody id="fg2-body"></tbody>
</table></div>
</div>
</div>
</div>
<div id="tb" class="panel">
<div class="sec-title">مرحلة كسر التعادل</div>
<div class="sec-sub">المسافة: 25 متر · جولة واحدة × 3 طلقات · الحد الأقصى 10/طلقة · المجموع: 30</div>
<div class="tie-info">
<strong>قواعد كسر التعادل:</strong><br>
1. تُطبق فقط عند تعادل لاعبين أو أكثر في المجموع النهائي للبطولة.<br>
2. يقوم المتعادلون برماية <strong>جولة من 3 طلقات</strong> على مسافة <strong>25 متراً</strong>. الفائز هو صاحب المجموع الأعلى (من 30).<br>
3. في حال استمرار التعادل، يتم اللجوء إلى طلقة واحدة (الموت المفاجئ) حتى الحسم.
</div>
<div class="tb-layout">
<div style="position:relative;min-height:200px;">
<div class="btn-row">
<button class="btn-lock" id="btn-lock-tb" onclick="lockStage('tb')">🔒 حفظ وإقفال النتائج</button>
<button class="btn-unlock" id="btn-unlock-tb" onclick="requireAuth(function(){ unlockStage('tb'); })" style="display:none;">🔓 تعديل النتائج</button>
<button class="btn-reset" onclick="requireAuth(function(){ clearAllScores('tb'); })">✕ مسح نتائج التعادل (تصفير)</button>
<button class="btn-set" onclick="undoScores('tb')" id="undo-tb" disabled style="opacity:.4">↩ تراجع</button>
</div>
<div id="tb-status"></div>
<div id="tb-groups"></div>
</div>
</div>
<div style="font-family:'Cairo',sans-serif;font-weight:800;letter-spacing:1px;font-size:22px;color:var(--navy);margin:40px 0 12px;">الترتيب الشامل للنهائيات</div>
<div class="tbl-wrap"><table>
<thead><tr><th>المركز</th><th>اسم المتسابق</th><th>النتيجة النهائية /200</th><th>نتيجة التعادل /30</th><th>الميدالية</th></tr></thead>
<tbody id="tb-ranking-body"></tbody>
</table></div>
</div>
<div id="podium" class="panel">
<div class="sec-title" style="color: var(--gold); border-bottom-color: var(--gold);">تتويج الأبطال</div>
<div class="sec-sub">النتائج النهائية لأصحاب المراكز الثلاثة الأولى في بطولة دويتوايلر للرماية</div>
<div class="podium-wrapper">
<div class="podium-col pos-2">
<div class="podium-avatar-wrap"><img src="" id="pod-img-2" class="podium-img" alt=""></div>
<div class="podium-medal-icon" id="pod-medal-2">🥈</div>
<div class="podium-name empty" id="pod-name-2">— بانتظار النتيجة —</div>
<div class="podium-score" id="pod-score-2">-</div>
</div>
<div class="podium-col pos-1">
<div class="podium-avatar-wrap"><img src="" id="pod-img-1" class="podium-img" alt=""></div>
<div class="podium-medal-icon" id="pod-medal-1">🥇</div>
<div class="podium-name empty" id="pod-name-1">— بانتظار النتيجة —</div>
<div class="podium-score" id="pod-score-1">-</div>
</div>
<div class="podium-col pos-3">
<div class="podium-avatar-wrap"><img src="" id="pod-img-3" class="podium-img" alt=""></div>
<div class="podium-medal-icon" id="pod-medal-3">🥉</div>
<div class="podium-name empty" id="pod-name-3">— بانتظار النتيجة —</div>
<div class="podium-score" id="pod-score-3">-</div>
</div>
</div>
</div>
<script>
const COMPETITORS_BASE=[
[1,"علي العمري","A. AL-OMARI","A"],[2,"عامر المحادين","A. MAHADIN","A"],[3,"علي خليل","A. KHALIL","A"],
[4,"شادي العشي","S. AL-ASHI","A"],[5,"طارق الدويكات","T. AL-DWEIKAT","A"],[6,"حازم العطيات","H. ALATIYYAT","A"],
[7,"علي ابو غزالة","A. ABU GHAZALEH","B"],[8,"فادي الساحوري","F. ALSAHOURI","B"],[9,"احمد ابو صالح","A. ABU SALEH","B"],
[10,"راندي عوده","R. ODEH","B"],[11,"علي الخصاونة","A. KHASAWNEH","B"],[12,"ماهر جالدالله","M. JADALLAH","B"],
[13,"عبدالله الحنيطي","A. HUNEITI","C"],[14,"ايهم الحواتمة","A. HAWATMEH","C"],[15,"معتز الوريكات","M. AL-WREIKAT","C"],
[16,"زيد الجمل","Z. AL-JAMAL","C"],[17,"نسيب وهبه","N. WEHBEH","C"],[18,"محسن العبدلي","M. AL-ABDALI","C"],
[19,"مالك ابو سنينة","M. ABU SNEINEH","D"],[20,"عمر الكيلاني","O. KILANI","D"],[21,"سعادة المراشدة","S. AL-MARASHDEH","D"],
[22,"مطلق الطيب","M. AL-TAYYEB","D"],[23,"محمد الحنيطي","M. HUNEITI","D"],[24,"ابراهيم الشوابكة","I. AL-SHAWABKEH","D"],
];
function showToast(message) {
const toast = document.getElementById("toast");
toast.textContent = message;
toast.className = "toast-notification show";
setTimeout(function() { toast.className = toast.className.replace("show", ""); }, 3000);
}
const ADMIN_USER = "admin";
const ADMIN_PASS = "12345";
let pendingAuthCallback = null;
function requireAuth(callback) {
pendingAuthCallback = callback;
document.getElementById('auth-user').value = "";
document.getElementById('auth-pass').value = "";
document.getElementById('auth-error').style.display = "none";
document.getElementById('auth-modal').style.display = "flex";
document.getElementById('auth-user').focus();
}
function closeAuth() {
document.getElementById('auth-modal').style.display = "none";
pendingAuthCallback = null;
}
function confirmAuth() {
const u = document.getElementById('auth-user').value.trim().toLowerCase();
const p = document.getElementById('auth-pass').value.trim();
if(u === ADMIN_USER.toLowerCase() && p === ADMIN_PASS) {
const callbackToRun = pendingAuthCallback;
closeAuth();
if(callbackToRun) callbackToRun();
} else {
document.getElementById('auth-error').style.display = "block";
}
}
document.getElementById('auth-pass').addEventListener('keypress', function (e) {
if (e.key === 'Enter') confirmAuth();
});
let competitorImages = JSON.parse(localStorage.getItem('dtw_images')) || {};
let customNames = JSON.parse(localStorage.getItem('dtw_names')) || {};
let groupAssign = JSON.parse(localStorage.getItem('dtw_groups'));
if (!groupAssign) { groupAssign = {}; COMPETITORS_BASE.forEach(c => { groupAssign[c[0]] = c[3]; }); }
let scores = JSON.parse(localStorage.getItem('dtw_scores_ps')) || {};
COMPETITORS_BASE.forEach(c => { if(!scores[c[0]]) scores[c[0]] = [0,0,0]; });
let finalScores = JSON.parse(localStorage.getItem('dtw_scores_fs')) || {};
let tbScores = JSON.parse(localStorage.getItem('dtw_scores_tb')) || {};
function saveScoresLocal() {
localStorage.setItem('dtw_scores_ps', JSON.stringify(scores));
localStorage.setItem('dtw_scores_fs', JSON.stringify(finalScores));
localStorage.setItem('dtw_scores_tb', JSON.stringify(tbScores));
}
function lockStage(stage) {
localStorage.setItem('dtw_locked_'+stage, 'true');
showToast("🔒 تم حفظ وإقفال النتائج بنجاح!");
if(stage === 'ps') renderPS();
if(stage === 'fs') renderFS();
if(stage === 'tb') renderFinalMedals();
}
function unlockStage(stage) {
localStorage.setItem('dtw_locked_'+stage, 'false');
showToast("🔓 تم فتح تعديل النتائج!");
if(stage === 'ps') renderPS();
if(stage === 'fs') renderFS();
if(stage === 'tb') renderFinalMedals();
}
function clearSavedImages() {
localStorage.removeItem('dtw_images');
competitorImages = {};
renderAllViews();
showToast("🗑️ تم مسح الصور بنجاح");
}
function clearSavedNames() {
localStorage.removeItem('dtw_names');
customNames = {};
renderAllViews();
showToast("🗑️ تم مسح الأسماء بنجاح");
}
const PILL={A:'<span class="grp-pill pill-a">A</span>',B:'<span class="grp-pill pill-b">B</span>',C:'<span class="grp-pill pill-c">C</span>',D:'<span class="grp-pill pill-d">D</span>','':'<span style="color:var(--muted);font-size:11px;">—</span>'};
const GC={A:"ga-row",B:"gb-row",C:"gc-row",D:"gd-row","":""};
let currentUploadingCompetitorId = null;
const uploader = document.getElementById('image-uploader');
function triggerImageUpload(num) { currentUploadingCompetitorId = num; uploader.click(); }
uploader.addEventListener('change', function(e) {
const file = e.target.files[0];
if (file && currentUploadingCompetitorId) {
const reader = new FileReader();
reader.onload = function(event) {
const img = new Image();
img.onload = function() {
const canvas = document.createElement('canvas');
let width = img.width, height = img.height; const MAX_SIZE = 200;
if (width > height) { if (width > MAX_SIZE) { height *= MAX_SIZE / width; width = MAX_SIZE; } } else { if (height > MAX_SIZE) { width *= MAX_SIZE / height; height = MAX_SIZE; } }
canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, width, height);
competitorImages[currentUploadingCompetitorId] = canvas.toDataURL('image/jpeg', 0.85);
try { localStorage.setItem('dtw_images', JSON.stringify(competitorImages)); } catch(e) { alert("مساحة المتصفح ممتلئة!"); }
renderAllViews();
}; img.src = event.target.result;
}; reader.readAsDataURL(file);
} e.target.value = '';
});
function getCompetitorData(num) {
const comp = COMPETITORS_BASE.find(c => c[0] === num);
let ar = comp ? comp[1] : "بدون اسم", en = comp ? comp[2] : "No Name";
if (customNames[num]) { if (customNames[num].ar) ar = customNames[num].ar; if (customNames[num].en) en = customNames[num].en; }
return { ar, en, imgSrc: competitorImages[num] || `https://ui-avatars.com/api/?name=${encodeURIComponent(ar)}&background=F0F2F8&color=1B1F40&bold=true&rounded=true&size=128` };
}
function updateName(num, lang, newText) {
if (!customNames[num]) customNames[num] = {ar: null, en: null};
customNames[num][lang] = newText.trim();
localStorage.setItem('dtw_names', JSON.stringify(customNames));
renderAllViews();
}
function renderAllViews() { renderGA(); renderPS(); renderOR(); renderFS(); updateTbPodium(); }
function saveGroupAssignments() { localStorage.setItem('dtw_groups', JSON.stringify(groupAssign)); renderAllViews(); showToast("✓ تم حفظ توزيع المجموعات بنجاح!"); }
function resetAllGroups(){ COMPETITORS_BASE.forEach(c => { groupAssign[c[0]] = ""; }); localStorage.setItem('dtw_groups', JSON.stringify(groupAssign)); renderGA(); showToast("✓ تم إفراغ المجموعات"); }
function restoreDefaults(){
if(confirm("هل أنت متأكد من استعادة التوزيع الأصلي للمجموعات؟")){
localStorage.removeItem('dtw_groups'); groupAssign = {}; COMPETITORS_BASE.forEach(c => { groupAssign[c[0]] = c[3]; });
renderAllViews(); showToast("✓ تم استعادة التوزيع الأصلي");
}
}
function onGroupChange(num, val){
if(val){
const currentCount = COMPETITORS_BASE.filter(c => groupAssign[c[0]] === val).length;
if(currentCount >= 6){
document.getElementById("ga-row-"+num).querySelector(".grp-select").value = groupAssign[num] || "";
alert(`عذراً، المجموعة ${val} ممتلئة (الحد الأقصى 6 لاعبين).`);
return;
}
}
groupAssign[num] = val;
updateSummaryCards();
const row = document.getElementById("ga-row-"+num);
if(row){
row.className = val ? GC[val] : "";
row.querySelector(".grp-select").className = "grp-select " + (val ? "sel-"+val.toLowerCase() : "sel-none");
}
localStorage.setItem('dtw_groups', JSON.stringify(groupAssign));
renderPS();
renderOR();
showToast("✓ تم حفظ تعديل المجموعة بنجاح!");
}
function updateSummaryCards(){
const cnt={A:0,B:0,C:0,D:0,u:0}; COMPETITORS_BASE.forEach(c=>{ const g = groupAssign[c[0]]; if(g && cnt[g]!==undefined) cnt[g]++; else cnt.u++; });
["A","B","C","D"].forEach(g=>{ document.getElementById("cnt-"+g.toLowerCase()).textContent=cnt[g]; const st=document.getElementById("st-"+g.toLowerCase()); if(cnt[g]===6){st.className="st st-ok";st.textContent="✓ مكتمل";} else if(cnt[g]<6){st.className="st st-warn";st.textContent=`⚠ بحاجة لـ ${6-cnt[g]}`;} });
document.getElementById("cnt-u").textContent=cnt.u; const stU=document.getElementById("st-u"); if(cnt.u===0){stU.className="st st-ok";stU.textContent="✓ تم التوزيع";} else{stU.className="st st-warn";stU.textContent=`${cnt.u} بلا مجموعة`;}
}
function renderGA(){
const gaBody=document.getElementById("ga-body"); gaBody.innerHTML="";
const groups=["A","B","C","D",""];
groups.forEach((g,gi)=>{
const members=g ? COMPETITORS_BASE.filter(c=>groupAssign[c[0]]===g) : COMPETITORS_BASE.filter(c=>!groupAssign[c[0]]);
if(members.length===0) return;
if(gi>0 && gaBody.children.length>0){ const sep=document.createElement("tr"); sep.className="grp-sep"; sep.innerHTML=`<td colspan="5"></td>`; gaBody.appendChild(sep); }
const hdr=document.createElement("tr"); hdr.className=(g?({A:"grp-a",B:"grp-b",C:"grp-c",D:"grp-d"})[g]:"")+" grp-hdr"; hdr.innerHTML=`<td colspan="5">${g?"المجموعة "+g:"⚠ غير معين"}</td>`; gaBody.appendChild(hdr);
members.forEach(m=>{
const num = m[0];
const {ar, en, imgSrc} = getCompetitorData(num); const grp=groupAssign[num]||""; const tr=document.createElement("tr"); tr.id="ga-row-"+num; tr.className=grp?GC[grp]:"";
const assigned=COMPETITORS_BASE.filter(c=>groupAssign[c[0]]===grp&&grp!=="").map(c=>c[0]); const pos=grp?assigned.indexOf(num)+1:"—";
tr.innerHTML=`<td class="td-num">${num}</td>
<td><div class="competitor-cell"><img src="${imgSrc}" class="competitor-img clickable-img" onclick="triggerImageUpload(${num})"> <span class="td-name editable-name" contenteditable="true" spellcheck="false" onblur="updateName(${num}, 'ar', this.innerText)">${ar}</span></div></td>
<td style="text-align:left;"><span class="td-en editable-name" contenteditable="true" spellcheck="false" onblur="updateName(${num}, 'en', this.innerText)">${en}</span></td>
<td><select class="grp-select ${grp?"sel-"+grp.toLowerCase():"sel-none"}" onchange="onGroupChange(${num},this.value)">
<option value="" ${grp===""?"selected":""}>— غير معين</option><option value="A" ${grp==="A"?"selected":""}>مجموعة A</option><option value="B" ${grp==="B"?"selected":""}>مجموعة B</option><option value="C" ${grp==="C"?"selected":""}>مجموعة C</option><option value="D" ${grp==="D"?"selected":""}>مجموعة D</option>
</select></td><td class="td-num" style="color:var(--muted)">${pos}</td>`; gaBody.appendChild(tr);
});
});
updateSummaryCards();
}
renderGA();
function onScoreChange(num, rdIdx, inputEl){
let raw = parseInt(inputEl.value);
if(isNaN(raw)) raw = 0;
if(raw < 0 || raw > 100){ inputEl.classList.add("invalid"); return; }
inputEl.classList.remove("invalid"); scores[num][rdIdx] = raw; saveScoresLocal();
const tot = scores[num].reduce((a,b)=>a+b,0); document.getElementById("ps-tot-"+num).textContent = tot;
const grp = groupAssign[num]; if(!grp) return;
const groupMembers = COMPETITORS_BASE.filter(c=>groupAssign[c[0]]===grp).map(c=>c[0]);
const groupTotals = groupMembers.map(n => scores[n].reduce((a,b)=>a+b,0));
groupMembers.forEach((n, i) => { const myTot = groupTotals[i]; const rk = groupTotals.filter(t => t > myTot).length + 1; const el = document.getElementById("ps-rk-"+n); if(el) el.textContent = rk; });
renderOR();
}
const undoHistory = { ps: null, fs: null, tb: null };
function setUndoBtn(stage, enabled){ const btn = document.getElementById("undo-"+stage); if(btn){ btn.disabled = !enabled; btn.style.opacity = enabled ? "1" : ".4"; } }
function clearAllScores(stage) {
if(stage === 'ps') {
undoHistory.ps = JSON.parse(JSON.stringify(scores));
for (let num in scores) { scores[num] = [0,0,0]; }
saveScoresLocal();
renderPS();
renderOR();
} else if(stage === 'fs') {
undoHistory.fs = JSON.parse(JSON.stringify(finalScores));
for (let num in finalScores) { finalScores[num] = [0,0]; }
saveScoresLocal();
renderFS();
} else if(stage === 'tb') {
undoHistory.tb = JSON.parse(JSON.stringify(tbScores));
for (let k in tbScores) { tbScores[k] = [0,0,0]; }
saveScoresLocal();
renderFinalMedals();
}
setUndoBtn(stage, true);
showToast("🗑️ تم تصفير جميع النتائج بنجاح!");
}
function undoScores(stage){
if(stage === 'ps' && undoHistory.ps){ Object.keys(undoHistory.ps).forEach(num => { scores[num] = [...undoHistory.ps[num]]; }); undoHistory.ps = null; saveScoresLocal(); renderPS(); renderOR(); }
else if(stage === 'fs' && undoHistory.fs){ Object.keys(undoHistory.fs).forEach(num => { finalScores[num] = [...undoHistory.fs[num]]; }); undoHistory.fs = null; saveScoresLocal(); renderFS(); }
else if(stage === 'tb' && undoHistory.tb){ Object.keys(undoHistory.tb).forEach(k => { tbScores[k] = [...undoHistory.tb[k]]; }); undoHistory.tb = null; saveScoresLocal(); renderFinalMedals(); }
setUndoBtn(stage, false);
}
function renderPS(){
const isLocked = localStorage.getItem('dtw_locked_ps') === 'true';
const btnLock = document.getElementById('btn-lock-ps'); const btnUnlock = document.getElementById('btn-unlock-ps');
if(btnLock) btnLock.style.display = isLocked ? 'none' : 'inline-block';
if(btnUnlock) btnUnlock.style.display = isLocked ? 'inline-block' : 'none';
const dis = isLocked ? 'disabled' : '';
const psBody=document.getElementById("ps-body"); psBody.innerHTML="";
const byGrp={A:[],B:[],C:[],D:[]}; COMPETITORS_BASE.forEach(c=>{ const g = groupAssign[c[0]]; if(g) byGrp[g].push(c[0]); });
[{g:"A",cls:"grp-a"},{g:"B",cls:"grp-b"},{g:"C",cls:"grp-c"},{g:"D",cls:"grp-d"}].forEach(({g,cls})=>{
const hdr=document.createElement("tr"); hdr.className=cls+" grp-hdr"; hdr.innerHTML=`<td colspan="8">المجموعة ${g}</td>`; psBody.appendChild(hdr);
const members=byGrp[g]; const totals=members.map(n=>scores[n].reduce((a,b)=>a+b,0));
members.forEach((num)=>{
const {ar, en, imgSrc} = getCompetitorData(num);
const s=scores[num]; const tot=s.reduce((a,b)=>a+b,0); const rk=totals.filter(t=>t>tot).length+1;
const tr=document.createElement("tr"); tr.className=GC[g];
tr.innerHTML=`<td class="td-num">${num}</td>
<td><div class="competitor-cell"><img src="${imgSrc}" class="competitor-img" alt="${ar}"> <span class="td-name">${ar}</span></div></td>
<td class="td-en">${en}</td>
<td><input class="score-input" type="number" min="0" max="100" value="${s[0]}" oninput="onScoreChange(${num},0,this)" ${dis}></td>
<td><input class="score-input" type="number" min="0" max="100" value="${s[1]}" oninput="onScoreChange(${num},1,this)" ${dis}></td>
<td><input class="score-input" type="number" min="0" max="100" value="${s[2]}" oninput="onScoreChange(${num},2,this)" ${dis}></td>
<td class="td-total" id="ps-tot-${num}">${tot}</td>
<td class="td-rank" id="ps-rk-${num}">${rk}</td>`;
psBody.appendChild(tr);
});
});
}
renderPS();
let top12 = [];
function renderOR(){
const all = COMPETITORS_BASE.map(c => ({ num: c[0], grp: groupAssign[c[0]]||"", total: scores[c[0]].reduce((a,b)=>a+b,0) })).filter(p => p.grp !== "");
const sorted = [...all].sort((a,b) => b.total - a.total);
const rankMap = {}; sorted.forEach((p,i) => rankMap[p.num] = i+1);
const orBody = document.getElementById("or-body"); orBody.innerHTML = "";
all.forEach(p => {
const {ar, en, imgSrc} = getCompetitorData(p.num);
const rk = rankMap[p.num]; const tr = document.createElement("tr"); tr.className = rk<=12 ? "medal-qualify" : "";
tr.innerHTML = `<td class="td-num">${p.num}</td><td><div class="competitor-cell"><img src="${imgSrc}" class="competitor-img" alt="${ar}"> <span class="td-name">${ar}</span></div></td><td>${PILL[p.grp]}</td><td class="td-total">${p.total}</td><td class="td-rank">${rk}</td><td>${rk<=12?'<span class="q-badge">✓ متأهل</span>':'<span class="no-q">—</span>'}</td>`;
orBody.appendChild(tr);
});
top12 = sorted.slice(0,12).map((p,i) => ({...p, seed:i+1}));
// التعديل: إزالة عمود الميدالية وتوحيد تنسيق المتأهلين
const top12Body = document.getElementById("top12-body"); top12Body.innerHTML = "";
top12.forEach((p,i) => {
const {ar, en, imgSrc} = getCompetitorData(p.num);
const tr = document.createElement("tr"); tr.className = "medal-qualify"; // توحيد اللون بدون ذهبي/فضي/برونزي
tr.innerHTML = `<td class="td-rank">${i+1}</td><td><div class="competitor-cell"><img src="${imgSrc}" class="competitor-img" alt="${ar}"> <span class="td-name">${ar}</span></div></td><td>${PILL[p.grp]}</td><td class="td-total">${p.total}</td>`;
top12Body.appendChild(tr);
});
if(top12.length > 0) renderFS();
}
renderOR();
function renderFS(){
const isLocked = localStorage.getItem('dtw_locked_fs') === 'true';
const btnLock = document.getElementById('btn-lock-fs');
const btnUnlock = document.getElementById('btn-unlock-fs');
if(btnLock) btnLock.style.display = isLocked ? 'none' : 'inline-block';
if(btnUnlock) btnUnlock.style.display = isLocked ? 'inline-block' : 'none';
const dis = isLocked ? 'disabled' : '';
const fg1Body = document.getElementById("fg1-body");
const fg2Body = document.getElementById("fg2-body");
if(fg1Body) fg1Body.innerHTML = "";
if(fg2Body) fg2Body.innerHTML = "";
if(typeof top12 === 'undefined' || top12.length === 0) return;
// تقسيم أفضل 12 لاعب إلى مجموعتين
const g1 = top12.slice(0, 6);
const g2 = top12.slice(6, 12);
const renderGroup = (group, tbody) => {
if(!tbody) return;
const totals = group.map(p => {
if (!finalScores[p.num]) finalScores[p.num] = [0, 0];
return finalScores[p.num].reduce((a, b) => a + b, 0);
});
group.forEach((p) => {
const num = p.num;
const {ar, imgSrc} = getCompetitorData(num);
const s = finalScores[num];
const tot = s.reduce((a,b)=>a+b,0);
const rk = totals.filter(t => t > tot).length + 1;
const tr = document.createElement("tr");
tr.innerHTML = `
<td class="td-num">${p.seed}</td>
<td><div class="competitor-cell"><img src="${imgSrc}" class="competitor-img" alt="${ar}"> <span class="td-name">${ar}</span></div></td>
<td><input class="score-input" type="number" min="0" max="100" value="${s[0]}" oninput="onFinalScoreChange(${num},0,this)" ${dis}></td>
<td><input class="score-input" type="number" min="0" max="100" value="${s[1]}" oninput="onFinalScoreChange(${num},1,this)" ${dis}></td>
<td class="td-total" id="fs-tot-${num}">${tot}</td>
<td class="td-rank" id="fs-grk-${num}">${rk}</td>
`;
tbody.appendChild(tr);
});
};
renderGroup(g1, fg1Body);
renderGroup(g2, fg2Body);
}
function onFinalScoreChange(num, rdIdx, inputEl){
let raw = parseInt(inputEl.value);
if(isNaN(raw)) raw = 0;
if(raw < 0 || raw > 100){ inputEl.classList.add("invalid"); return; }
inputEl.classList.remove("invalid"); finalScores[num][rdIdx] = raw; saveScoresLocal();
const tot = finalScores[num].reduce((a,b)=>a+b,0); document.getElementById("fs-tot-"+num).textContent = tot;
const seedIdx = top12.findIndex(p=>p.num===num); const fgGroup = seedIdx < 6 ? top12.slice(0,6) : top12.slice(6,12);
fgGroup.forEach(p => { const t = finalScores[p.num].reduce((a,b)=>a+b,0); const rk = fgGroup.filter(x => finalScores[x.num].reduce((a,b)=>a+b,0) > t).length + 1; const el = document.getElementById("fs-grk-"+p.num); if(el) el.textContent = rk; });
renderFinalMedals();
}
function getTbTotal(grpLabel, num){ const key = grpLabel+"-"+num; return tbScores[key] ? tbScores[key].reduce((a,b)=>a+b,0) : 0; }
let currentTiedPlayers = [];
const MEDAL_SVG = { 1: `🥇`, 2: `🥈`, 3: `🥉`, };
const CLOCK_SVG = { 1: `<span style="opacity:.3;filter:grayscale(1);">⏳</span>`, 2: `<span style="opacity:.3;filter:grayscale(1);">⏳</span>`, 3: `<span style="opacity:.3;filter:grayscale(1);">⏳</span>`, };
function updateTbPodium(){
const standings = [...top12].map(p => { const ft = finalScores[p.num]?finalScores[p.num].reduce((a,b)=>a+b,0):0; const grpLabel = playerTbGroup[p.num]; const tbTot = grpLabel ? getTbTotal(grpLabel, p.num) : 0; return { ...p, ft, tbTot }; });
standings.sort((a,b) => b.ft - a.ft || b.tbTot - a.tbTot);
[1,2,3].forEach(pos => {
const nameEl = document.getElementById("pod-name-"+pos); const scoreEl = document.getElementById("pod-score-"+pos); const medalEl = document.getElementById("pod-medal-"+pos); const imgEl = document.getElementById("pod-img-"+pos);
const p = standings[pos-1];
if(!p || p.ft === 0){
nameEl.textContent="— بانتظار النتيجة —"; nameEl.classList.add("empty"); scoreEl.textContent="-"; imgEl.src = `https://ui-avatars.com/api/?name=?&background=F0F2F8&color=1B1F40&size=150`; if(medalEl) medalEl.innerHTML=CLOCK_SVG[pos]; return;
}
const {ar, imgSrc} = getCompetitorData(p.num);
const isTied = standings.some((x, xi) => { if(x.num === p.num) return false; const xPos = standings.filter(y => y.ft > x.ft || (y.ft===x.ft && y.tbTot > x.tbTot)).length + 1; return xPos <= 3 && x.ft === p.ft && x.tbTot === p.tbTot; });
nameEl.textContent = ar; nameEl.classList.remove("empty"); imgEl.src = imgSrc;
if(isTied){
if(medalEl) medalEl.innerHTML = CLOCK_SVG[pos]; scoreEl.textContent = p.tbTot > 0 ? "تعادل: " + p.tbTot : "النهائي: " + p.ft; scoreEl.style.color = "var(--muted)";
} else {
if(medalEl) medalEl.innerHTML = MEDAL_SVG[pos]; scoreEl.textContent = "النتيجة: " + p.ft + (p.tbTot > 0 ? ` (كسر: +${p.tbTot})` : ""); scoreEl.style.color = pos===1?"#D4AF37":pos===2?"#9DA3AE":"#CD7F32";
}
});
renderTbRankingTable();
}
function onTbScoreChange(key, shotIdx, inputEl){
let raw = parseInt(inputEl.value); if(isNaN(raw)) raw = 0;
if(raw < 0 || raw > 10){ inputEl.classList.add("invalid"); return; }
inputEl.classList.remove("invalid"); tbScores[key][shotIdx] = raw; saveScoresLocal();
const tot = tbScores[key].reduce((a,b)=>a+b,0); const totEl = document.getElementById("tb-tot-"+key); if(totEl) totEl.textContent = tot;
const grpLabel = key.split("-")[0]; const grpKeys = Object.keys(tbScores).filter(k=>k.startsWith(grpLabel+"-"));
grpKeys.forEach(k => { const t = tbScores[k].reduce((a,b)=>a+b,0); const rk = grpKeys.filter(ok => tbScores[ok].reduce((a,b)=>a+b,0) > t).length + 1; const el = document.getElementById("tb-rk-"+k); if(el) el.textContent = t===0 ? "—" : rk; });
updateTbPodium(); updateFinalMedalWithTB();
}
const playerTbGroup = {};
function renderTbRankingTable(){
const body = document.getElementById("tb-ranking-body"); if(!body) return; body.innerHTML = "";
const standings = [...top12].map(p => { const ft = finalScores[p.num]?finalScores[p.num].reduce((a,b)=>a+b,0):0; const grpLabel = playerTbGroup[p.num]; const tbTot = grpLabel ? getTbTotal(grpLabel, p.num) : 0; return { ...p, ft, tbTot }; });
standings.sort((a,b) => b.ft - a.ft || b.tbTot - a.tbTot);
standings.forEach((p, i) => {
const {ar, imgSrc} = getCompetitorData(p.num);
const trueRank = standings.filter(x => x.ft > p.ft || (x.ft===p.ft && x.tbTot > p.tbTot)).length + 1;
const isTied = standings.some(x => { if(x.num === p.num) return false; const xRank = standings.filter(y => y.ft > x.ft || (y.ft===x.ft && y.tbTot > x.tbTot)).length + 1; return xRank <= 3 && x.ft === p.ft && x.tbTot === p.tbTot; });
const tr = document.createElement("tr"); const medalLabels = {1:"🥇",2:"🥈",3:"🥉"}; const medalColors = {1:"#E8784A",2:"#9DA3AE",3:"#CD7F32"};
let rankCell, medalCell, rowClass = "";
if(p.ft === 0) { rankCell = `<td class="td-rank" style="color:var(--muted)">—</td>`; medalCell = `<td class="medal-icon" style="color:var(--muted);font-size:13px">—</td>`; }
else if(isTied){ rankCell = `<td class="td-rank" style="color:var(--muted)">${trueRank}</td>`; medalCell = `<td><span style="background:rgba(236,47,35,.15);border:1px solid rgba(236,47,35,.4);color:var(--red);border-radius:8px;padding:2px 10px;font-size:12px;font-weight:700;">تعادل</span></td>`; }
else { rowClass = trueRank===1?"medal-gold":trueRank===2?"medal-silver":trueRank===3?"medal-bronze":""; rankCell = `<td class="td-rank">${trueRank}</td>`; const medal = medalLabels[trueRank]; medalCell = medal ? `<td class="medal-icon" style="color:${medalColors[trueRank]}">${medal}</td>` : `<td class="medal-icon" style="color:var(--muted);font-size:13px">#${trueRank}</td>`; }
const tbCell = p.tbTot > 0 ? `<td class="td-total" style="color:#ffffff">${p.tbTot}</td>` : `<td style="color:var(--muted);font-size:13px">—</td>`;
const tieBadge = (isTied && p.ft > 0) ? ` <span style="background:rgba(236,47,35,.15);border:1px solid rgba(236,47,35,.4);color:var(--red);border-radius:8px;padding:1px 8px;font-size:11px;font-weight:700;margin-right:6px;">تعادل</span>` : "";
tr.className = rowClass; tr.innerHTML = `${rankCell}<td><div class="competitor-cell"><img src="${imgSrc}" class="competitor-img" alt="${ar}"> <span class="td-name">${ar}${tieBadge}</span></div></td><td class="td-total">${p.ft}</td>${tbCell}${medalCell}`; body.appendChild(tr);
});
}
function updateFinalMedalWithTB(){ renderTbRankingTable(); }
function renderFinalMedals(){ updateFinalMedalWithTB(); const fSortedLive = [...top12].sort((a,b)=>{ const ta=finalScores[a.num]?finalScores[a.num].reduce((x,y)=>x+y,0):0; const tb=finalScores[b.num]?finalScores[b.num].reduce((x,y)=>x+y,0):0; return tb-ta; }); renderTiebreaker(fSortedLive); }
function renderTiebreaker(fSortedLive){
const isLocked = localStorage.getItem('dtw_locked_tb') === 'true';
const btnLock = document.getElementById('btn-lock-tb'); const btnUnlock = document.getElementById('btn-unlock-tb');
if(btnLock) btnLock.style.display = isLocked ? 'none' : 'inline-block';
if(btnUnlock) btnUnlock.style.display = isLocked ? 'inline-block' : 'none';
const dis = isLocked ? 'disabled' : '';
const statusEl = document.getElementById("tb-status"); const groupsEl = document.getElementById("tb-groups");
statusEl.innerHTML = ""; groupsEl.innerHTML = ""; currentTiedPlayers = [];
const scored = fSortedLive.map(p => ({ ...p, ft: finalScores[p.num]?finalScores[p.num].reduce((a,b)=>a+b,0):0 }));
const tieGroups = []; let i = 0;
while(i < Math.min(scored.length, 12)){
const sameScore = scored.filter(p => p.ft === scored[i].ft); const positions = sameScore.map(p => scored.indexOf(p) + 1); const inTop3 = positions.some(pos => pos <= 3);
if(sameScore.length > 1 && inTop3 && scored[i].ft > 0){ if(!tieGroups.find(g => g.score === scored[i].ft)){ tieGroups.push({ score: scored[i].ft, players: sameScore, positions }); } }
i += sameScore.length;
}
if(tieGroups.length === 0){ statusEl.innerHTML = `<div class="tb-none">✓ لا يوجد تعادل في المراكز الثلاثة الأولى.</div>`; updateTbPodium(); return; }
tieGroups.forEach((grp, gi) => {
const grpLabel = "g"+gi; grp.players.forEach(p => { playerTbGroup[p.num] = grpLabel; if(!currentTiedPlayers.find(x => x.num === p.num)) currentTiedPlayers.push(p); });
const medalPos = grp.positions.filter(p=>p<=3); const posStr = medalPos.map(p => p===1?"الأول":p===2?"الثاني":"الثالث").join(" و ");
const title = document.createElement("div"); title.className = "tb-group-title"; title.innerHTML = `تعادل — المركز ${posStr} <span class="tb-tied-score">النتيجة النهائية: ${grp.score}</span>`; groupsEl.appendChild(title);
const wrap = document.createElement("div"); wrap.className = "tbl-wrap"; const table = document.createElement("table");
table.innerHTML = `<thead><tr><th>#</th><th>صورة واسم المتسابق</th><th>طلقة 1 /10</th><th>طلقة 2 /10</th><th>طلقة 3 /10</th><th>المجموع /30</th><th>الترتيب</th></tr></thead>`;
const tbody = document.createElement("tbody");
grp.players.forEach((p, pi) => {
const {ar, imgSrc} = getCompetitorData(p.num);
const key = grpLabel+"-"+p.num; if(!tbScores[key]) tbScores[key] = [0,0,0]; const s = tbScores[key]; const tot = s.reduce((a,b)=>a+b,0);
const rk = grp.players.filter(op => (tbScores[grpLabel+"-"+op.num]||[0,0,0]).reduce((a,b)=>a+b,0) > tot).length + 1;
const tr = document.createElement("tr");
tr.innerHTML = `<td class="td-num">${pi+1}</td><td><div class="competitor-cell"><img src="${imgSrc}" class="competitor-img" alt="${ar}"> <span class="td-name">${ar}</span></div></td><td><input class="score-input" type="number" min="0" max="10" value="${s[0]}" oninput="onTbScoreChange('${key}',0,this)" ${dis}></td><td><input class="score-input" type="number" min="0" max="10" value="${s[1]}" oninput="onTbScoreChange('${key}',1,this)" ${dis}></td><td><input class="score-input" type="number" min="0" max="10" value="${s[2]}" oninput="onTbScoreChange('${key}',2,this)" ${dis}></td><td class="td-total" id="tb-tot-${key}">${tot}</td><td class="td-rank" id="tb-rk-${key}">${tot===0?"—":rk}</td>`;
tbody.appendChild(tr);
});
table.appendChild(tbody); wrap.appendChild(table); groupsEl.appendChild(wrap);
});
updateTbPodium();
}
// === برمجة الشاشة المباشرة (النسخة الجديدة والمستقرة) ===
let liveGroupTimer = null;
let liveGroupIdx = 0;
const LIVE_GROUPS = ["A", "B", "C", "D"];
function renderLiveGroup() {
const container = document.getElementById("lg-container");
if (!container) return;
const g = LIVE_GROUPS[liveGroupIdx];
const members = COMPETITORS_BASE.filter(c => groupAssign[c[0]] === g);
let html = `<div class="lg-header">المجموعة ${g} - GROUP ${g}</div><div class="lg-grid">`;
if(members.length === 0) {
html += `<div class="lg-empty">لا يوجد متسابقين في هذه المجموعة</div>`;
} else {
members.forEach((m, i) => {
const d = getCompetitorData(m[0]);
html += `
<div class="lg-card" style="animation: cardIn 0.5s ease forwards; animation-delay: ${i*0.1}s; opacity: 0;">
<img src="${d.imgSrc}" alt="${d.ar}">
<div class="lg-info">
<div class="lg-num">#${m[0]}</div>
<div class="lg-name">${d.ar}</div>
<div class="lg-name-en">${d.en}</div>
</div>
</div>`;
});
}
html += `</div>`;
container.innerHTML = html;
// إعادة تشغيل شريط التقدم المرئي
const bar = document.getElementById("lg-progress");
if (bar) {
bar.classList.remove("run-progress");
void bar.offsetWidth; // لتنشيط الأنيميشن مجدداً
bar.classList.add("run-progress");
}
liveGroupIdx = (liveGroupIdx + 1) % LIVE_GROUPS.length;
}
function startLiveGroups() {
stopLiveGroups();
liveGroupIdx = 0;
renderLiveGroup();
liveGroupTimer = setInterval(renderLiveGroup, 5000);
}
function stopLiveGroups() {
if (liveGroupTimer) {
clearInterval(liveGroupTimer);
liveGroupTimer = null;
}
}
function show(id, btn){
document.querySelectorAll('.panel').forEach(p=>p.classList.remove('active'));
document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));
document.getElementById(id).classList.add('active');
btn.classList.add('active');
if(id === 'live-groups') {
startLiveGroups();
} else {
stopLiveGroups();
}
}
// Init
updateTbPodium();
</script>
</body>
</html>