<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Speech & Debate Team Hub</title>
    <!-- Tailwind CSS for sleek UI styling -->
    <script src="https://jsdelivr.net"></script>
    <!-- FontAwesome for UI icons -->
    <link rel="stylesheet" href="https://cloudflare.com">
</head>
<body class="bg-slate-900 text-slate-100 min-h-screen font-sans">

    <!-- Top Navigation Bar -->
    <nav class="bg-slate-800 border-b border-slate-700 sticky top-0 z-50 px-6 py-4 flex flex-wrap justify-between items-center shadow-lg">
        <div class="flex items-center space-x-3">
            <i class="fa-solid fa-gavel text-amber-500 text-2xl"></i>
            <span class="text-xl font-bold tracking-wider uppercase text-amber-400">Forensics Hub</span>
        </div>
        <div class="flex space-x-2 mt-2 sm:mt-0">
            <button onclick="switchTab('timer-tab')" class="tab-btn px-4 py-2 rounded-lg bg-amber-500 text-slate-950 font-semibold shadow-md transition">
                <i class="fa-solid fa-stopwatch mr-1"></i> Timers
            </button>
            <button onclick="switchTab('flow-tab')" class="tab-btn px-4 py-2 rounded-lg bg-slate-700 hover:bg-slate-600 font-semibold transition">
                <i class="fa-solid fa-file-lines mr-1"></i> Flow
            </button>
            <button onclick="switchTab('ballot-tab')" class="tab-btn px-4 py-2 rounded-lg bg-slate-700 hover:bg-slate-600 font-semibold transition">
                <i class="fa-solid fa-square-poll-horizontal mr-1"></i> Ballot Calc
            </button>
            <button onclick="switchTab('motion-tab')" class="tab-btn px-4 py-2 rounded-lg bg-slate-700 hover:bg-slate-600 font-semibold transition">
                <i class="fa-solid fa-lightbulb mr-1"></i> Motions
            </button>
        </div>
    </nav>

    <!-- Main Workspace Matrix -->
    <main class="max-w-7xl mx-auto p-4 md:p-8">
        
        <!-- SECTION 1: DEBATE PREP TIMERS -->
        <section id="timer-tab" class="tab-content space-y-6">
            <div class="bg-slate-800 border border-slate-700 rounded-2xl p-6 shadow-xl">
                <h2 class="text-2xl font-bold border-b border-slate-700 pb-3 mb-6 text-amber-400">
                    <i class="fa-solid fa-clock mr-2"></i>Official Format Prep Clocks
                </h2>
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                    <div class="bg-slate-850 p-6 rounded-xl border border-slate-750 text-center space-y-4">
                        <h3 class="text-lg font-semibold tracking-wide text-emerald-400 uppercase">Affirmative Team</h3>
                        <div id="aff-display" class="text-6xl font-mono font-black text-slate-100 py-4 bg-slate-950 rounded-lg border border-slate-800 tracking-widest">08:00</div>
                        <div class="flex justify-center space-x-3">
                            <button onclick="startTimer('aff')" class="px-5 py-2.5 bg-emerald-600 hover:bg-emerald-500 font-bold rounded-lg transition shadow-md"><i class="fa-solid fa-play"></i></button>
                            <button onclick="pauseTimer('aff')" class="px-5 py-2.5 bg-amber-600 hover:bg-amber-500 font-bold rounded-lg transition shadow-md"><i class="fa-solid fa-pause"></i></button>
                            <button onclick="resetTimer('aff')" class="px-5 py-2.5 bg-rose-600 hover:bg-rose-500 font-bold rounded-lg transition shadow-md"><i class="fa-solid fa-rotate-left"></i></button>
                        </div>
                    </div>
                    <div class="bg-slate-850 p-6 rounded-xl border border-slate-750 text-center space-y-4">
                        <h3 class="text-lg font-semibold tracking-wide text-rose-400 uppercase">Negative Team</h3>
                        <div id="neg-display" class="text-6xl font-mono font-black text-slate-100 py-4 bg-slate-950 rounded-lg border border-slate-800 tracking-widest">08:00</div>
                        <div class="flex justify-center space-x-3">
                            <button onclick="startTimer('neg')" class="px-5 py-2.5 bg-emerald-600 hover:bg-emerald-500 font-bold rounded-lg transition shadow-md"><i class="fa-solid fa-play"></i></button>
                            <button onclick="pauseTimer('neg')" class="px-5 py-2.5 bg-amber-600 hover:bg-amber-500 font-bold rounded-lg transition shadow-md"><i class="fa-solid fa-pause"></i></button>
                            <button onclick="resetTimer('neg')" class="px-5 py-2.5 bg-rose-600 hover:bg-rose-500 font-bold rounded-lg transition shadow-md"><i class="fa-solid fa-rotate-left"></i></button>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- SECTION 2: DIGITAL FLOW SHEET -->
        <section id="flow-tab" class="tab-content hidden space-y-6">
            <div class="bg-slate-800 border border-slate-700 rounded-2xl p-6 shadow-xl">
                <div class="flex justify-between items-center border-b border-slate-700 pb-3 mb-6">
                    <h2 class="text-2xl font-bold text-amber-400"><i class="fa-solid fa-table-columns mr-2"></i>Digital Flow Tracking</h2>
                    <button onclick="clearFlow()" class="text-xs bg-rose-950 hover:bg-rose-900 text-rose-300 font-medium px-3 py-1.5 rounded-lg border border-rose-800 transition">Clear Sheet</button>
                </div>
                <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
                    <div class="space-y-4">
                        <label class="block text-sm font-semibold tracking-wider uppercase text-slate-400">Affirmative Arguments</label>
                        <textarea id="flow-aff" oninput="saveFlow()" placeholder="Type Aff case structure here..." class="w-full h-80 bg-slate-950 border border-slate-800 rounded-xl p-4 text-slate-200 focus:outline-none focus:border-amber-500 font-mono text-sm shadow-inner leading-relaxed resize-none"></textarea>
                    </div>
                    <div class="space-y-4">
                        <label class="block text-sm font-semibold tracking-wider uppercase text-slate-400">Negative Arguments</label>
                        <textarea id="flow-neg" oninput="saveFlow()" placeholder="Type Neg responses here..." class="w-full h-80 bg-slate-950 border border-slate-800 rounded-xl p-4 text-slate-200 focus:outline-none focus:border-amber-500 font-mono text-sm shadow-inner leading-relaxed resize-none"></textarea>
                    </div>
                </div>
            </div>
        </section>

        <!-- SECTION 3: BALLOT CALCULATOR -->
        <section id="ballot-tab" class="tab-content hidden space-y-6">
            <div class="grid grid-cols-1 xl:grid-cols-3 gap-6">
                <!-- Ballot Entry Form -->
                <div class="bg-slate-800 border border-slate-700 rounded-2xl p-6 shadow-xl xl:col-span-2 space-y-6">
                    <h2 class="text-2xl font-bold text-amber-400 border-b border-slate-700 pb-3"><i class="fa-solid fa-calculator mr-2"></i>Round Ballot Tabulator</h2>
                    
                    <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                        <!-- Affirmative Team Scores -->
                        <div class="bg-slate-900/50 p-4 rounded-xl border border-emerald-900/50 space-y-4">
                            <h3 class="text-md font-bold text-emerald-400 flex justify-between">
                                <span>AFFIRMATIVE TEAM</span>
                                <span id="aff-total-points" class="font-mono bg-slate-950 px-2 py-0.5 rounded text-sm text-slate-300">Total: 0</span>
                            </h3>
                            <div class="space-y-3">
                                <div>
                                    <label class="block text-xs text-slate-400 mb-1">Speaker 1 Name</label>
                                    <input type="text" id="aff1-name" value="Aff Speaker 1" class="w-full bg-slate-950 border border-slate-800 rounded px-2.5 py-1.5 text-sm">
                                    <div class="grid grid-cols-2 gap-2 mt-1">
                                        <input type="number" id="aff1-spk" oninput="calculateBallot()" value="28.0" step="0.5" min="0" max="30" class="bg-slate-950 border border-slate-850 rounded text-center p-1 text-xs" placeholder="Points">
                                        <select id="aff1-rank" onchange="calculateBallot()" class="bg-slate-950 border border-slate-850 rounded text-center p-1 text-xs text-slate-300">
                                            <option value="1">1st Rank</option><option value="2">2nd Rank</option><option value="3" selected>3rd Rank</option><option value="4">4th Rank</option>
                                        </select>
                                    </div>
                                </div>
                                <div>
                                    <label class="block text-xs text-slate-400 mb-1">Speaker 2 Name</label>
                                    <input type="text" id="aff2-name" value="Aff Speaker 2" class="w-full bg-slate-950 border border-slate-800 rounded px-2.5 py-1.5 text-sm">
                                    <div class="grid grid-cols-2 gap-2 mt-1">
                                        <input type="number" id="aff2-spk" oninput="calculateBallot()" value="29.0" step="0.5" min="0" max="30" class="bg-slate-950 border border-slate-850 rounded text-center p-1 text-xs" placeholder="Points">
                                        <select id="aff2-rank" onchange="calculateBallot()" class="bg-slate-950 border border-slate-850 rounded text-center p-1 text-xs text-slate-300">
1st Rank2nd Rank3rd Rank4th Rank

NEGATIVE TEAM
Total: 0

Speaker 1 Name
1st Rank2nd Rank3rd Rank4th Rank

Speaker 2 Name
1st Rank2nd Rank3rd Rank4th Rank

Round Decision Outcome
Calculating...

Log Round Decision

Ballot Ledger Archive

Log New Motion

Debate Topic / Motion

Format Category
Policy / CX
Lincoln-Douglas
Public Forum
World Schools

Add Motion

Active Brainstorm Board

function switchTab(tabId) {
document.querySelectorAll('.tab-content').forEach(el => el.classList.add('hidden'));
document.getElementById(tabId).classList.remove('hidden');
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('bg-amber-500', 'text-slate-950');
btn.classList.add('bg-slate-700', 'hover:bg-slate-600');
});
const activeBtn = event.currentTarget;
activeBtn.classList.remove('bg-slate-700', 'hover:bg-slate-600');
activeBtn.classList.add('bg-amber-500', 'text-slate-950');
}
// Timer Matrix Control
let timers = {
aff: { time: 480, interval: null, default: 480 },
neg: { time: 480, interval: null, default: 480 }
};
function updateDisplay(side) {
const minutes = Math.floor(timers[side].time / 60).toString().padStart(2, '0');
const seconds = (timers[side].time % 60).toString().padStart(2, '0');
document.getElementById(${side}-display).innerText = ${minutes}:${seconds};
}
function startTimer(side) {
if (timers[side].interval) return;
timers[side].interval = setInterval(() => {
if (timers[side].time > 0) {
timers[side].time--;
updateDisplay(side);
} else {
clearInterval(timers[side].interval);
timers[side].interval = null;
}
}, 1000);
}
function pauseTimer(side) {
clearInterval(timers[side].interval);
timers[side].interval = null;
}
function resetTimer(side) {
pauseTimer(side);
timers[side].time = timers[side].default;
updateDisplay(side);
}
// Flow Management Matrix
function saveFlow() {
localStorage.setItem('flow_aff', document.getElementById('flow-aff').value);
localStorage.setItem('flow_neg', document.getElementById('flow-neg').value);
}
function clearFlow() {
if(confirm('Are you sure you want to clear your current flow sheet?')) {
document.getElementById('flow-aff').value = '';
document.getElementById('flow-neg').value = '';
saveFlow();
}
}
// Ballot Calculation Matrix Engine
let trackingDecisionStr = "";
let historicBallots = JSON.parse(localStorage.getItem('historic_ballots')) || [];
function calculateBallot() {
const aff1Spk = parseFloat(document.getElementById('aff1-spk').value) || 0;
const aff2Spk = parseFloat(document.getElementById('aff2-spk').value) || 0;
const neg1Spk = parseFloat(document.getElementById('neg1-spk').value) || 0;
const neg2Spk = parseFloat(document.getElementById('neg2-spk').value) || 0;
const affTotalPoints = aff1Spk + aff2Spk;
const negTotalPoints = neg1Spk + neg2Spk;
document.getElementById('aff-total-points').innerText = Total: ${affTotalPoints};
document.getElementById('neg-total-points').innerText = Total: ${negTotalPoints};
const aff1Rank = parseInt(document.getElementById('aff1-rank').value);
const aff2Rank = parseInt(document.getElementById('aff2-rank').value);
const neg1Rank = parseInt(document.getElementById('neg1-rank').value);
const neg2Rank = parseInt(document.getElementById('neg2-rank').value);
const affTotalRanks = aff1Rank + aff2Rank;
const negTotalRanks = neg1Rank + neg2Rank;
// Clerical Error Validation
const rankSet = new Set([aff1Rank, aff2Rank, neg1Rank, neg2Rank]);
if (rankSet.size < 4) {
trackingDecisionStr = "⚠️ Error: Ranks must be unique (1-4 without duplicates).";
document.getElementById('ballot-decision').innerHTML = <span class="text-rose-400 font-medium">${trackingDecisionStr}</span>;
return;
}
// Standard debate tiebreaking logic hierarchy: Low Ranks Win -> High Speaker Points Win
if (affTotalRanks < negTotalRanks) {
trackingDecisionStr = Affirmative Wins (Ranks: ${affTotalRanks} vs ${negTotalRanks});
} else if (negTotalRanks < affTotalRanks) {
trackingDecisionStr = Negative Wins (Ranks: ${negTotalRanks} vs ${affTotalRanks});
} else {
if (affTotalPoints > negTotalPoints) {
trackingDecisionStr = Affirmative Wins via Speaker Points Tiebreak (${affTotalPoints} vs ${negTotalPoints});
} else if (negTotalPoints > affTotalPoints) {
trackingDecisionStr = Negative Wins via Speaker Points Tiebreak (${negTotalPoints} vs ${affTotalPoints});
} else {
trackingDecisionStr = "Absolute Dead Tie (Ranks and Points match exactly)";
}
}
document.getElementById('ballot-decision').innerText = trackingDecisionStr;
}
function logBallot() {
if (trackingDecisionStr.startsWith("⚠️")) {
alert("Please correct validation errors before logging the round outcome.");
return;
}
const record = {
id: Date.now(),
timestamp: new Date().toLocaleDateString(),
summary: trackingDecisionStr,
aff: ${document.getElementById('aff1-name').value} & ${document.getElementById('aff2-name').value},
neg: ${document.getElementById('neg1-name').value} & ${document.getElementById('neg2-name').value}
};
historicBallots.unshift(record);
localStorage.setItem('historic_ballots', JSON.stringify(historicBallots));
renderLedger();
}
function deleteBallot(id) {
historicBallots = historicBallots.filter(b => b.id !== id);
localStorage.setItem('historic_ballots', JSON.stringify(historicBallots));
renderLedger();
}
function renderLedger() {
const container = document.getElementById('ballot-ledger');
if (historicBallots.length === 0) {
container.innerHTML = <p class="text-slate-500 text-sm italic">No historic round outcomes tracked yet.</p>;
return;
}
container.innerHTML = historicBallots.map(b => <div class="bg-slate-950 p-3.5 border border-slate-850 rounded-xl relative group shadow-inner"> <button onclick="deleteBallot(${b.id})" class="absolute top-3 right-3 text-slate-600 hover:text-rose-400 transition"><i class="fa-solid fa-trash"></i></button> <div class="text-[10px] font-bold text-slate-500 tracking-wider mb-1">${b.timestamp}</div> <div class="text-xs text-slate-300 font-semibold truncate pr-6">${b.summary}</div> <div class="text-[11px] text-slate-400 mt-1 leading-relaxed"> <span class="text-emerald-500">Aff:</span> ${b.aff} <br> <span class="text-rose-500">Neg:</span> ${b.neg} </div> </div>).join('');
}
// Motion Repository Management
let motions = JSON.parse(localStorage.getItem('team_motions')) || [];
document.getElementById('motion-form').addEventListener('submit', function(e) {
e.preventDefault();
const text = document.getElementById('motion-text').value;
const category = document.getElementById('motion-cat').value;
motions.unshift({ id: Date.now(), text, category });
localStorage.setItem('team_motions', JSON.stringify(motions));
document.getElementById('motion-text').value = '';
renderMotions();
});
function deleteMotion(id) {
motions = motions.filter(m => m.id !== id);
localStorage.setItem('team_motions', JSON.stringify(motions));
renderMotions();
}
function renderMotions() {
const list = document.getElementById('motion-list');
if (motions.length === 0) {
list.innerHTML = <p class="text-slate-500 text-sm italic">No practice motions recorded yet.</p>;
return;
}
list.innerHTML = motions.map(m => <div class="bg-slate-950 border border-slate-850 p-4 rounded-xl flex justify-between items-start space-x-4 shadow-sm"> <div class="space-y-1"> <span class="inline-block text-[10px] uppercase font-bold tracking-wider px-2 py-0.5 rounded bg-slate-800 text-amber-400 border border-slate-700">${m.category}</span> <p class="text-sm font-medium text-slate-200 leading-relaxed">${m.text}</p> </div> <button onclick="deleteMotion(${m.id})" class="text-slate-500 hover:text-rose-400 transition p-1"><i class="fa-solid fa-trash-can text-sm"></i></button> </div>).join('');
}
// Initial Boot Loader Routine
window.onload = function() {
document.getElementById('flow-aff').value = localStorage.getItem('flow_aff') || '';
document.getElementById('flow-neg').value = localStorage.getItem('flow_neg') || '';
renderMotions();
calculateBallot();
renderLedger();
};