jak volit

This commit is contained in:
2026-09-22 14:43:53 +02:00
commit 083ee569e5

294
jakvolit.php Normal file
View File

@@ -0,0 +1,294 @@
<?php
$maxVotes = 9;
?>
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jak správně volit & Simulátor</title>
<style>
:root {
--primary-teal: #008080;
--primary-dark: #005b5b;
--accent-blue: #006699;
--bg-light: #f4f8f8;
--text-color: #2c3e50;
}
html { scroll-behavior: smooth; scroll-padding-top: 70px; }
body {
background-color: #ffffff; color: var(--text-color);
margin: 0; padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
.navbar {
position: sticky; top: 0; z-index: 1000;
background: linear-gradient(135deg, var(--primary-teal), var(--accent-blue));
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
}
.navbar-container { max-width: 1300px; margin: 0 auto; display: flex; justify-content: center; padding: 0 10px; }
.navbar nav { display: flex; gap: 10px; }
.navbar a {
color: #ffffff; text-decoration: none; padding: 15px 20px;
font-weight: 600; font-size: 15px; transition: background 0.2s; display: block; text-align: center;
}
.navbar a:hover { background-color: rgba(255, 255, 255, 0.15); }
.container { max-width: 1300px; margin: 0 auto; padding: 20px; }
section { padding: 40px 0; border-bottom: 1px solid #e0ecec; }
section:last-of-type { border-bottom: none; }
h2 { text-align: center; color: var(--primary-dark); font-size: 28px; margin-top: 0; margin-bottom: 30px; position: relative; }
h2::after { content: ''; display: block; width: 50px; height: 3px; background: var(--primary-teal); margin: 8px auto 0; border-radius: 2px; }
h3 { color: var(--primary-teal); margin-top: 30px; }
.info-box { background-color: var(--bg-light); padding: 25px; border-radius: 8px; border-left: 5px solid var(--primary-teal); line-height: 1.6; max-width: 1000px; margin: 0 auto; }
/* Pravidla */
.voting-rules { line-height: 1.7; margin-bottom: 30px; font-size: 15px; }
.voting-rules li { margin-bottom: 12px; }
.voting-rules.mistakes li { color: #a72828; }
.voting-rules.mistakes strong { color: #dc3545; }
/* Simulátor a křížky */
.sim-wrap { margin-top: 40px; }
.sim-grid { display: flex; gap: 15px; margin-top: 20px; }
@media (max-width: 768px) { .sim-grid { flex-direction: column; } }
.party-col { flex: 1; border: 1px solid #b8d8d8; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 5px rgba(0,0,0,0.05); }
.party-header { background: var(--bg-light); padding: 15px 12px; font-weight: bold; border-bottom: 3px solid var(--primary-teal); display: flex; align-items: center; gap: 12px; }
.candidate-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-bottom: 1px solid #f0f0f0; font-size: 14px; transition: background 0.3s; }
.big-cross, .small-cross {
appearance: none;
-webkit-appearance: none;
background-color: #fff;
border: 2px solid #b8d8d8;
border-radius: 4px;
cursor: pointer;
transition: border-color 0.2s;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
flex-shrink: 0;
margin: 0;
}
.big-cross { width: 26px; height: 26px; }
.small-cross { width: 20px; height: 20px; }
.big-cross:hover, .small-cross:hover { border-color: var(--primary-teal); }
.big-cross:checked, .small-cross:checked {
border-color: var(--primary-dark);
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%232c3e50" stroke-width="4" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>');
background-size: 80%;
background-position: center;
background-repeat: no-repeat;
}
.candidate-row.gets-vote { background-color: #d4edda; border-left: 4px solid #28a745; }
.candidate-row.wasted-cross:not(.gets-vote) { background-color: #fff3cd; border-left: 4px solid #ffc107; color: #856404; text-decoration: line-through;}
.candidate-row.gets-vote.wasted-cross { background: repeating-linear-gradient(45deg, #d4edda, #d4edda 10px, #e8f5e9 10px, #e8f5e9 20px); border-left: 4px solid #28a745; }
.sim-result { margin-top: 25px; padding: 20px; border-radius: 8px; text-align: center; border: 2px solid #ccc; background: #f9f9f9; }
.sim-result.valid { border-color: #28a745; background: #e8f5e9; }
.sim-result.invalid { border-color: #dc3545; background: #fbeee8; }
.sim-result.neutral { border-color: var(--primary-teal); background: var(--bg-light); }
#sim-status { font-weight: bold; font-size: 22px; margin-bottom: 8px; }
#sim-text { font-size: 15px; line-height: 1.5; }
.legend { display: flex; gap: 15px; margin-top: 15px; font-size: 13px; justify-content: center; flex-wrap: wrap; }
.legend-item { display: flex; align-items: center; gap: 6px; }
.legend-box { width: 16px; height: 16px; border-radius: 3px; }
.lb-green { background: #d4edda; border: 1px solid #28a745; }
.lb-yellow { background: #fff3cd; border: 1px solid #ffc107; }
.lb-striped { background: repeating-linear-gradient(45deg, #d4edda, #d4edda 5px, #e8f5e9 5px, #e8f5e9 10px); border: 1px solid #28a745; }
.cand-details { display: flex; flex-direction: column; cursor: pointer; line-height: 1.3; }
.cand-name { font-weight: 600; font-size: 15px; color: var(--primary-dark); }
.cand-role { font-size: 13px; color: #666; margin-top: 2px; }
.candidate-row label { flex-grow: 1; }
</style>
</head>
<body>
<header class="navbar">
<div class="navbar-container">
<nav>
<a href="jakvolit.php">Jak volit</a>
</nav>
</div>
</header>
<div class="container">
<!-- SEKC 3: JAK VOLIT -->
<section id="jak-volit">
<h2>Jak správně volit?</h2>
<h3>3 možné způsoby, jak vyplnit volební lístek:</h3>
<ul class="voting-rules">
<li><strong>1. Velký kříž jedné straně:</strong> Uděláte jeden velký křížek v rámečku u názvu zvolené strany. Hlas tak dáváte prvním <?php echo $maxVotes; ?> kandidátům této strany (odshora dolů).</li>
<li><strong>2. Křížky jednotlivcům:</strong> Křížkem označíte konkrétní kandidáty napříč všemi stranami. Zaškrtnout můžete maximálně <?php echo $maxVotes; ?> osob.</li>
<li><strong>3. Kombinace (tzv. panašování):</strong> Uděláte velký kříž jedné straně a zároveň malé křížky kandidátům z <em>jiných</em> stran. Nejdříve se započítají hlasy zakřížkovaným jednotlivcům. Zbylé hlasy do počtu <?php echo $maxVotes; ?> pak připadnou kandidátům strany s velkým křížem (opět v pořadí odshora dolů).</li>
</ul>
<h3>Nejčastější omyly, kterým se vyhnout:</h3>
<ul class="voting-rules mistakes">
<li><strong>Více velkých křížů:</strong> Pokud zaškrtnete velkým křížem více než jednu stranu, je celý lístek <strong>neplatný</strong>.</li>
<li><strong>Příliš mnoho malých křížků:</strong> Pokud zakřížkujete více než <?php echo $maxVotes; ?> kandidátů, je lístek <strong>neplatný</strong>.</li>
<li><strong>Zbytečné křížky (Kříž straně + křížky jejím kandidátům):</strong> Pokud dáte velký kříž straně a zároveň uděláte malé křížky u kandidátů <em>této stejné strany</em>, zákon tyto malé křížky zcela ignoruje. Strana zkrátka dostane hlasy postupně od shora, preferovat konkrétního kandidáta ve vlastní zakřížkované straně nelze.</li>
</ul>
<!-- INTERAKTIVNÍ SIMULÁTOR -->
<div class="sim-wrap">
<h2 style="margin-top: 50px;">Simulátor volebního lístku nanečisto</h2>
<div class="info-box">
Do obecního zastupitelstva se volí <strong><?php echo $maxVotes; ?></strong> kandidátů a každý volič má tedy <strong><?php echo $maxVotes; ?></strong> hlasů, které může rozdělit dle následujícího. Pro označení ve volebním lístku použijte křížek.
</div>
<div class="sim-grid">
<div class="party-col">
<div class="party-header">
<input type="checkbox" class="big-cross" data-party="0" id="p0">
<label for="p0">Společně pro Přišimasy</label>
</div>
<div class="candidate-list">
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_1"><label for="c0_1" class="cand-details"><span class="cand-name">1. Ing.arch. Naděžda Čermáková</span><span class="cand-role">podnikatelka, 34 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_2"><label for="c0_2" class="cand-details"><span class="cand-name">2. Jaroslav Havlín</span><span class="cand-role">projektový manažer,technik, 41 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_3"><label for="c0_3" class="cand-details"><span class="cand-name">3. Martin Foltýnek</span><span class="cand-role">podnikatel, 47 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_4"><label for="c0_4" class="cand-details"><span class="cand-name">4. Ondřej Šmejkal</span><span class="cand-role">zámečník,mechanik, 25 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_5"><label for="c0_5" class="cand-details"><span class="cand-name">5. Jan Formánek</span><span class="cand-role">expedient, 41 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_6"><label for="c0_6" class="cand-details"><span class="cand-name">6. Ing. Libor Kusák</span><span class="cand-role">obchodní manažer, 52 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_7"><label for="c0_7" class="cand-details"><span class="cand-name">7. Mgr. Ludmila Klejchová</span><span class="cand-role">učitelka, 46 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_8"><label for="c0_8" class="cand-details"><span class="cand-name">8. Rostislav Chalupský</span><span class="cand-role">IT technik, 34 let</span></label></div>
<div class="candidate-row" data-party="0"><input type="checkbox" class="small-cross" id="c0_9"><label for="c0_9" class="cand-details"><span class="cand-name">9. Tomáš Jelen</span><span class="cand-role">řidič, 53 let</span></label></div>
</div>
</div>
<!-- === DRUHÁ STRANA (Pravý sloupec) === -->
<div class="party-col">
<div class="party-header">
<input type="checkbox" class="big-cross" data-party="1" id="p1">
<label for="p1">Pro obnovu a rozvoj Přišimas</label>
</div>
<div class="candidate-list">
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_1"><label for="c1_1" class="cand-details"><span class="cand-name">1. Bc. Šárka Rumanová</span><span class="cand-role">starostka obce, 52 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_2"><label for="c1_2" class="cand-details"><span class="cand-name">2. Ing. Jiří Procházka</span><span class="cand-role">produktový manažer, 47 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_3"><label for="c1_3" class="cand-details"><span class="cand-name">3. Michal Strnad</span><span class="cand-role">podnikatel,místostarosta obce, 47 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_4"><label for="c1_4" class="cand-details"><span class="cand-name">4. Radek Studničný</span><span class="cand-role">underwriter specialista,místostarosta obce, 49 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_5"><label for="c1_5" class="cand-details"><span class="cand-name">5. PhDr. Václav Červenka</span><span class="cand-role">psycholog, 47 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_6"><label for="c1_6" class="cand-details"><span class="cand-name">6. Stanislava Řádková</span><span class="cand-role">důchodkyně, 67 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_7"><label for="c1_7" class="cand-details"><span class="cand-name">7. Jakub Macháček</span><span class="cand-role">podnikatel, 39 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_8"><label for="c1_8" class="cand-details"><span class="cand-name">8. Libor Syrový</span><span class="cand-role">lakýrník, 47 let</span></label></div>
<div class="candidate-row" data-party="1"><input type="checkbox" class="small-cross" id="c1_9"><label for="c1_9" class="cand-details"><span class="cand-name">9. Roman Frank</span><span class="cand-role">stavební technik, 33 let</span></label></div>
</div>
</div>
</div>
<!-- Výsledkový box simulátoru -->
<div class="sim-result neutral" id="sim-result-box">
<div id="sim-status">Prázdný lístek</div>
<div id="sim-text">Zkuste zaškrtnout stranu nebo kandidáty.</div>
</div>
<!-- Legenda barev -->
<div class="legend">
<div class="legend-item"><div class="legend-box lb-green"></div> Kandidát získá Váš hlas</div>
<div class="legend-item"><div class="legend-box lb-striped"></div> Kandidát získá hlas (díky velkému kříži, váš malý se ignoruje)</div>
<div class="legend-item"><div class="legend-box lb-yellow"></div> Kandidát hlas <strong>nezíská</strong> (zákon zbytečný křížek škrtne)</div>
</div>
</div>
</section>
</div>
<script>
const MAX_VOTES = <?php echo isset($maxVotes) ?$maxVotes : 9; ?>;
function updateSimulator() {
try {
const bigCrosses = document.querySelectorAll('.big-cross:checked');
const smallCrosses = document.querySelectorAll('.small-cross:checked');
const resultBox = document.getElementById('sim-result-box');
const resultStatus = document.getElementById('sim-status');
const resultText = document.getElementById('sim-text');
if (!resultBox || !resultStatus || !resultText) return;
document.querySelectorAll('.candidate-row').forEach(row => {
row.classList.remove('gets-vote', 'wasted-cross');
});
let activeBigCross = bigCrosses.length === 1 ? bigCrosses[0].dataset.party : null;
let crossData = Array.from(smallCrosses).map(cb => {
let row = cb.closest('.candidate-row');
if (!row) return null;
return { party: row.dataset.party, el: row };
}).filter(item => item !== null);
if (bigCrosses.length > 1) {
resultBox.className = 'sim-result invalid';
resultStatus.innerText = 'Neplatný lístek!';
resultText.innerText = 'Zaškrtli jste velký kříž u více než jedné volební strany. Váš hlas zcela propadá.';
} else if (!activeBigCross) {
if (crossData.length > MAX_VOTES) {
resultBox.className = 'sim-result invalid';
resultStatus.innerText = 'Neplatný lístek!';
resultText.innerText = `Zaškrtli jste příliš mnoho kandidátů (${crossData.length} z ${MAX_VOTES}). Hlas propadá.`;
} else {
resultBox.className = 'sim-result ' + (crossData.length > 0 ? 'valid' : 'neutral');
resultStatus.innerText = crossData.length === 0 ? 'Prázdný lístek' : 'Platný lístek';
resultText.innerText = `Rozdělili jste ${crossData.length} z ${MAX_VOTES} hlasů. Zbývá Vám ${MAX_VOTES - crossData.length} nevyužitých.`;
crossData.forEach(c => c.el.classList.add('gets-vote'));
}
} else {
let otherParties = crossData.filter(c => c.party !== activeBigCross);
let sameParty = crossData.filter(c => c.party === activeBigCross);
if (otherParties.length > MAX_VOTES) {
resultBox.className = 'sim-result invalid';
resultStatus.innerText = 'Neplatný lístek!';
resultText.innerText = `Zaškrtli jste příliš mnoho kandidátů u jiných stran (${otherParties.length} z ${MAX_VOTES}).`;
} else {
resultBox.className = 'sim-result valid';
let remaining = MAX_VOTES - otherParties.length;
if (otherParties.length === 0) {
resultStatus.innerText = 'Platný lístek (Velký kříž)';
resultText.innerText = `Všech ${remaining} hlasů připadlo straně s velkým křížem.`;
} else {
resultStatus.innerText = 'Platný lístek (Kombinace)';
resultText.innerText = `Jiné strany dostaly ${otherParties.length} hlasů. Zbylých ${remaining} hlasů si bere strana s velkým křížem.`;
}
otherParties.forEach(c => c.el.classList.add('gets-vote'));
sameParty.forEach(c => c.el.classList.add('wasted-cross'));
let bigPartyRows = document.querySelectorAll(`.candidate-row[data-party="${activeBigCross}"]`);
for (let i = 0; i < remaining; i++) {
if (bigPartyRows[i]) bigPartyRows[i].classList.add('gets-vote');
}
}
}
} catch (err) {
console.error("KRITICKÁ CHYBA SIMULÁTORU:", err);
}
}
document.addEventListener('change', function(e) {
if (e.target && (e.target.classList.contains('big-cross') || e.target.classList.contains('small-cross'))) {
updateSimulator();
}
});
document.addEventListener('DOMContentLoaded', updateSimulator);
</script>
</body>
</html>