alpha_base_3

This commit is contained in:
Flatlogic Bot 2026-03-04 04:15:53 +00:00
parent 01b9e110c3
commit 81a9931032
3 changed files with 247 additions and 65 deletions

View File

@ -274,10 +274,20 @@ body {
100% { color: inherit; }
}
@keyframes blink-theme {
0% { color: inherit; }
50% { color: var(--accent-color); }
100% { color: inherit; }
}
.timer-alert {
animation: blink-red 0.5s infinite;
}
.timer-finish-theme {
animation: blink-theme 0.5s infinite;
}
/* Settings Switches */
.form-check-input:checked {
background-color: var(--accent-color);
@ -357,4 +367,11 @@ body.dark-mode .text-muted {
/* Saved Timers Hover Effect */
#saved-timers-list .card-precise:hover {
border-color: var(--success-color);
}
/* Color input styling */
.participant-color-input {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
cursor: pointer;
}

View File

@ -26,6 +26,7 @@ const app = {
// Relay State
currentParticipant: 1,
participantNames: [],
// Custom State
customActivities: [
@ -53,7 +54,7 @@ const app = {
'countdown': { title: 'Countdown Timer', allowPause: true, hasLaps: false, forceCountdown: true, canSave: true },
'stopwatch': { title: 'Stopwatch', allowPause: false, hasLaps: false, canToggleCountdown: false, canSave: true },
'lap': { title: 'Lap Timer', allowPause: false, hasLaps: true, canToggleCountdown: false },
'relay': { title: 'Relay Timer', allowPause: true, hasRelay: true, canToggleCountdown: false },
'relay': { title: 'Relay Timer', allowPause: false, hasRelay: true, canToggleCountdown: false },
'custom': { title: 'Custom Timer', allowPause: true, isCustom: true, canToggleCountdown: true, canSave: true }
},
@ -78,6 +79,7 @@ const app = {
btnNext: document.getElementById('btn-next'),
btnSaveMain: document.getElementById('btn-save-main'),
btnSaveBuilder: document.getElementById('btn-save-session-builder'),
btnResetBuilder: document.getElementById('btn-reset-builder'),
formatSelect: document.getElementById('format-select'),
listTitle: document.getElementById('list-title'),
@ -92,7 +94,12 @@ const app = {
inputS: document.getElementById('input-s'),
relayConfig: document.getElementById('relay-config'),
relayParticipantCountBox: document.getElementById('relay-participant-count-box'),
participantCount: document.getElementById('participant-count'),
participantNamesContainer: document.getElementById('participant-names-container'),
relayActiveParticipantContainer: document.getElementById('relay-active-participant-container'),
relayActiveName: document.getElementById('relay-active-name'),
btnRelaySplit: document.getElementById('btn-relay-split'),
customBuilder: document.getElementById('custom-builder'),
activityList: document.getElementById('activity-list'),
@ -102,6 +109,7 @@ const app = {
btnDeleteSaved: document.getElementById('btn-delete-saved'),
// Settings / Options
optionsDropdown: document.getElementById('optionsDropdown'),
optCountdownContainer: document.getElementById('opt-countdown-container'),
customOptions: document.getElementById('custom-options'),
restAlertContainer: document.getElementById('rest-alert-container'),
@ -115,6 +123,8 @@ const app = {
alertPreEndSec: document.getElementById('alert-pre-end-seconds'),
alertCompletion: document.getElementById('alert-completion'),
preFinishSection: document.getElementById('pre-finish-section'),
brandLink: document.getElementById('brand-link'),
darkModeToggle: document.getElementById('dark-mode-toggle')
},
@ -153,9 +163,14 @@ const app = {
this.el.btnReset.addEventListener('click', () => this.resetTimer());
this.el.btnLap.addEventListener('click', () => this.recordLap());
this.el.btnNext.addEventListener('click', () => this.recordRelaySplit());
this.el.btnRelaySplit.addEventListener('click', () => this.recordRelaySplit());
this.el.btnSaveMain.addEventListener('click', () => this.saveCurrentTimer());
this.el.btnSaveBuilder.addEventListener('click', () => this.saveCurrentTimer());
if (this.el.btnResetBuilder) {
this.el.btnResetBuilder.addEventListener('click', () => this.resetCustomBuilder());
}
this.el.brandLink.addEventListener('click', (e) => {
e.preventDefault();
this.switchView('landing');
@ -166,6 +181,8 @@ const app = {
this.el.settingIsCountdown.addEventListener('change', () => this.resetTimer());
this.el.lapSort.addEventListener('change', () => this.renderHistory());
this.el.participantCount.addEventListener('input', () => this.renderParticipantInputs());
this.el.savedTimersDropdown.addEventListener('change', (e) => {
if (e.target.value) {
this.loadTimer(e.target.value);
@ -226,7 +243,7 @@ const app = {
// UI Adjustments
this.el.btnPause.classList.toggle('d-none', !mode.allowPause);
this.el.btnLap.classList.toggle('d-none', !mode.hasLaps);
this.el.btnNext.classList.toggle('d-none', !mode.hasRelay);
this.el.btnNext.classList.add('d-none'); // Removed from timer entirely for all modes
this.el.btnSaveMain.classList.toggle('d-none', !mode.canSave || mode.isCustom);
this.el.timerSideColumn.classList.toggle('d-none', !mode.hasLaps && !mode.hasRelay && !mode.isCustom);
@ -235,17 +252,37 @@ const app = {
this.el.customBuilder.classList.remove('d-none');
this.el.historySection.classList.add('d-none');
this.el.savedTimersContainer.classList.remove('d-none');
this.el.relayConfig.classList.add('d-none');
} else if (mode.hasRelay) {
this.el.customBuilder.classList.add('d-none');
this.el.relayConfig.classList.remove('d-none');
this.el.historySection.classList.remove('d-none');
this.el.savedTimersContainer.classList.add('d-none');
// Move history to main column immediately for Relay (separate from participants)
this.el.lapResultsContainer.classList.remove('d-none');
this.el.lapResultsContainer.appendChild(this.el.historySection);
this.el.lapSort.classList.remove('d-none');
} else {
this.el.customBuilder.classList.add('d-none');
this.el.relayConfig.classList.add('d-none');
this.el.historySection.classList.remove('d-none');
this.el.savedTimersContainer.classList.toggle('d-none', !mode.canSave);
}
this.el.countdownInputs.classList.toggle('d-none', modeKey !== 'countdown');
this.el.relayConfig.classList.toggle('d-none', !mode.hasRelay);
this.el.customOptions.classList.toggle('d-none', !mode.isCustom);
this.el.restAlertContainer.classList.toggle('d-none', !mode.isCustom);
this.el.activeActivityName.classList.add('d-none');
this.el.relayActiveParticipantContainer.classList.add('d-none');
// Options Dropdown visibility logic
this.el.optionsDropdown.classList.toggle('d-none', modeKey === 'time-watch');
// Pre-finish section visibility logic
const noPreFinishModes = ['stopwatch', 'lap', 'relay'];
this.el.preFinishSection.classList.toggle('d-none', noPreFinishModes.includes(modeKey));
this.el.lapSort.classList.add('d-none');
// Options Box adjustments
@ -267,7 +304,8 @@ const app = {
this.el.listHead.innerHTML = '<tr><th style="width: 80px;">Lap</th><th>Split Time</th><th>Delta</th><th class="text-end">Notes</th></tr>';
} else if (mode.hasRelay) {
this.el.listTitle.textContent = 'Relay Splits';
this.el.listHead.innerHTML = '<tr><th style="width: 120px;">Participant</th><th>Total Time</th><th>Split</th><th class="text-end">Status</th></tr>';
this.el.listHead.innerHTML = '<tr><th>Participant</th><th>Start Time</th><th>Split Time</th><th class="text-end">Total Time</th></tr>';
this.renderParticipantInputs();
} else if (mode.isCustom) {
this.el.listTitle.textContent = 'Activities';
this.el.listHead.innerHTML = '<tr><th>Activity</th><th>Duration</th><th class="text-end">Status</th></tr>';
@ -277,6 +315,25 @@ const app = {
this.updateDisplay();
},
renderParticipantInputs() {
const count = Math.min(12, Math.max(1, parseInt(this.el.participantCount.value) || 1));
this.el.participantCount.value = count;
let html = '';
const colors = ['#3b82f6', '#10b981', '#ef4444', '#f59e0b', '#8b5cf6', '#ec4899', '#06b6d4', '#f97316', '#14b8a6', '#6366f1', '#a855f7', '#d946ef'];
for (let i = 1; i <= count; i++) {
const defaultColor = colors[(i - 1) % colors.length];
html += `
<div class="input-group input-group-sm">
<span class="input-group-text fs-tiny">#${i}</span>
<input type="text" class="form-control form-control-precise participant-name-input" data-index="${i}" placeholder="Participant Name">
<input type="color" class="form-control form-control-color form-control-precise p-1 participant-color-input" data-index="${i}" value="${defaultColor}" style="width: 40px; height: 31px;">
</div>
`;
}
this.el.participantNamesContainer.innerHTML = html;
},
handleStartClick() {
if (!this.el.sessionTitle.value.trim()) {
if (this.currentMode === 'custom') {
@ -348,6 +405,7 @@ const app = {
}
this.countdownStartValue = totalMs;
this.elapsedTime = totalMs;
this.el.countdownInputs.classList.add('d-none');
}
if (mode.isCustom && !this.isPaused) {
@ -371,6 +429,14 @@ const app = {
this.updateCurrentActivityStatus('in-progress');
}
if (mode.hasRelay && !this.isPaused) {
this.currentParticipant = 1;
this.history = [];
this.el.relayActiveParticipantContainer.classList.remove('d-none');
this.el.relayParticipantCountBox.classList.add('d-none');
this.updateRelayActiveDisplay();
}
if (this.isPaused) {
const offset = (isCountdownMode) ? (this.countdownStartValue - this.elapsedTime) : this.elapsedTime;
this.startTime = now - offset;
@ -388,6 +454,7 @@ const app = {
this.el.btnReset.disabled = true;
this.el.sessionTitle.disabled = true;
this.el.mainTimer.classList.remove('timer-finish');
this.el.mainTimer.classList.remove('timer-finish-theme');
this.el.mainTimer.classList.remove('timer-alert');
// Lock inputs
@ -395,6 +462,8 @@ const app = {
if (this.el.inputM) this.el.inputM.disabled = true;
if (this.el.inputS) this.el.inputS.disabled = true;
if (this.el.participantCount) this.el.participantCount.disabled = true;
document.querySelectorAll('.participant-name-input').forEach(i => i.disabled = true);
document.querySelectorAll('.participant-color-input').forEach(i => i.disabled = true);
this.tick();
},
@ -428,6 +497,11 @@ const app = {
this.el.btnStop.disabled = true;
this.el.btnReset.disabled = false;
this.el.mainTimer.classList.remove('timer-alert');
this.el.relayActiveParticipantContainer.classList.add('d-none');
if (this.currentMode === 'countdown') {
this.el.countdownInputs.classList.remove('d-none');
}
if (this.currentMode === 'lap') {
this.recordLap();
@ -436,7 +510,10 @@ const app = {
this.el.lapResultsContainer.appendChild(this.el.historySection);
this.el.lapSort.classList.remove('d-none');
} else if (this.currentMode === 'relay') {
this.recordRelaySplit(true);
if (wasRunning) this.recordRelaySplit(true);
// Relay splits panel is already under controls in setMode, just ensure sorting is visible
this.el.lapResultsContainer.classList.remove('d-none');
this.el.lapSort.classList.remove('d-none');
} else if (this.currentMode === 'custom' && wasRunning) {
this.updateCurrentActivityStatus('Canceled');
}
@ -454,39 +531,76 @@ const app = {
this.el.listBody.innerHTML = '';
this.el.mainTimer.classList.remove('timer-finish');
this.el.mainTimer.classList.remove('timer-finish-theme');
this.el.mainTimer.classList.remove('timer-alert');
this.el.btnReset.disabled = true;
this.el.btnStart.disabled = false;
this.el.btnPause.disabled = true;
this.el.btnStop.disabled = true;
this.el.btnNext.disabled = false;
this.el.btnRelaySplit.disabled = false;
this.el.activeActivityName.classList.add('d-none');
this.el.relayActiveParticipantContainer.classList.add('d-none');
this.el.relayParticipantCountBox.classList.remove('d-none');
this.el.sessionTitle.disabled = false;
if (this.el.inputH) this.el.inputH.disabled = false;
if (this.el.inputM) this.el.inputM.disabled = false;
if (this.el.inputS) this.el.inputS.disabled = false;
if (this.el.inputH) {
this.el.inputH.disabled = false;
if (this.currentMode === 'countdown') this.el.inputH.value = '';
}
if (this.el.inputM) {
this.el.inputM.disabled = false;
if (this.currentMode === 'countdown') this.el.inputM.value = '';
}
if (this.el.inputS) {
this.el.inputS.disabled = false;
if (this.currentMode === 'countdown') this.el.inputS.value = '';
}
if (this.currentMode === 'countdown' || this.currentMode === 'stopwatch') {
this.el.savedTimersDropdown.value = '';
this.el.sessionTitle.value = '';
if (this.currentMode) this.sessionTitles[this.currentMode] = '';
}
if (this.el.participantCount) this.el.participantCount.disabled = false;
document.querySelectorAll('.participant-name-input').forEach(i => i.disabled = false);
document.querySelectorAll('.participant-color-input').forEach(i => i.disabled = false);
if (this.currentMode === 'countdown') {
this.el.countdownInputs.classList.remove('d-none');
}
// Move history back to side column default
this.el.timerSideColumn.querySelector('.card-precise').appendChild(this.el.historySection);
this.el.lapResultsContainer.classList.add('d-none');
this.el.lapSort.classList.add('d-none');
// Transition: History -> Builder (if custom)
if (this.currentMode === 'custom') {
this.el.customBuilder.classList.remove('d-none');
this.el.historySection.classList.add('d-none');
this.el.savedTimersContainer.classList.remove('d-none');
// Ensure history section is back in side column if it was moved (though only lap moves it)
this.el.timerSideColumn.querySelector('.card-precise').appendChild(this.el.historySection);
}
if (this.currentMode === 'lap') {
// Move history back to side column
this.el.timerSideColumn.querySelector('.card-precise').appendChild(this.el.historySection);
this.el.lapResultsContainer.classList.add('d-none');
this.el.lapSort.classList.add('d-none');
} else if (this.currentMode === 'relay') {
// Put it back under timer for relay even after reset
this.el.lapResultsContainer.classList.remove('d-none');
this.el.lapResultsContainer.appendChild(this.el.historySection);
this.el.lapSort.classList.remove('d-none');
}
this.updateDisplay();
},
resetCustomBuilder() {
this.customActivities = [{ name: 'Activity 1', duration: 60000, isRest: false }];
this.el.sessionTitle.value = '';
if (this.currentMode) this.sessionTitles[this.currentMode] = '';
this.el.savedTimersDropdown.value = '';
this.renderCustomBuilder();
this.resetTimer();
},
tick() {
if (!this.isRunning || this.isPaused) return;
@ -599,8 +713,13 @@ const app = {
updateDisplay() {
const ms = this.elapsedTime;
const format = this.el.formatSelect.value;
let format = this.el.formatSelect.value;
if (this.currentMode === 'time-watch') {
if (format === 'hh:mm:ss.ms') format = 'hh:mm:ss';
if (format === 'seconds.ms') format = 'seconds';
}
this.el.mainTimer.textContent = this.formatTime(ms, format);
// Only show sub-timer if format is not milliseconds as requested
@ -656,6 +775,24 @@ const app = {
this.renderHistory();
},
updateRelayActiveDisplay() {
const maxParticipants = parseInt(this.el.participantCount.value) || 1;
if (this.currentParticipant > maxParticipants) {
this.el.relayActiveParticipantContainer.classList.add('d-none');
return;
}
const nameInput = document.querySelector(`.participant-name-input[data-index="${this.currentParticipant}"]`);
const name = nameInput ? (nameInput.value.trim() || `P${this.currentParticipant}`) : `P${this.currentParticipant}`;
const colorInput = document.querySelector(`.participant-color-input[data-index="${this.currentParticipant}"]`);
const color = colorInput ? colorInput.value : '#3b82f6';
this.el.relayActiveName.textContent = name;
this.el.relayActiveName.style.color = color;
this.el.btnRelaySplit.disabled = false;
this.el.btnRelaySplit.textContent = 'Split';
},
recordRelaySplit(isFinal = false) {
const now = this.elapsedTime;
const lastTime = this.history.length > 0 ? this.history[this.history.length - 1].time : 0;
@ -664,28 +801,44 @@ const app = {
if (this.currentParticipant > maxParticipants && !isFinal) return;
// Get name and color
const nameInput = document.querySelector(`.participant-name-input[data-index="${this.currentParticipant}"]`);
let name = nameInput ? (nameInput.value.trim() || `P${this.currentParticipant}`) : `P${this.currentParticipant}`;
const colorInput = document.querySelector(`.participant-color-input[data-index="${this.currentParticipant}"]`);
const color = colorInput ? colorInput.value : '#3b82f6';
// If it's the last participant, mark as final but keep their name
if (this.currentParticipant === maxParticipants) {
isFinal = true;
}
this.history.push({
id: `P${this.currentParticipant}`,
id: name,
color: color,
startTime: lastTime,
time: now,
delta: delta,
status: isFinal ? 'DONE' : 'SPLIT'
});
this.el.btnRelaySplit.disabled = true;
if (!isFinal) {
this.currentParticipant++;
if (this.currentParticipant > maxParticipants) {
this.stopTimer();
}
this.updateRelayActiveDisplay();
} else {
this.stopTimer();
this.el.btnRelaySplit.disabled = true;
}
this.renderHistory();
},
renderHistory() {
if (this.currentMode === 'lap') {
let sortedHistory = this.history.slice();
const sortVal = this.el.lapSort.value;
let sortedHistory = this.history.slice();
const sortVal = this.el.lapSort.value;
if (this.currentMode === 'lap' || this.currentMode === 'relay') {
if (sortVal === 'best') {
sortedHistory.sort((a, b) => a.delta - b.delta);
} else if (sortVal === 'worse') {
@ -699,27 +852,27 @@ const app = {
if (h.delta < minDelta) minDelta = h.delta;
});
this.el.listBody.innerHTML = sortedHistory.map(h => `
<tr class="${h.delta === minDelta ? 'table-success' : ''}">
<td class="font-tabular fw-bold">#${h.id}</td>
<td class="font-tabular">${this.formatTime(h.time, 'hh:mm:ss.ms')}</td>
<td class="font-tabular text-muted">+${this.formatTime(h.delta, 'seconds.ms')}</td>
<td class="text-end">
${h.delta === minDelta ? '<span class="badge-best">BEST</span>' : ''}
</td>
</tr>
`).join('');
} else if (this.currentMode === 'relay') {
this.el.listBody.innerHTML = this.history.slice().reverse().map(h => `
<tr>
<td class="fw-bold">${h.id}</td>
<td class="font-tabular">${this.formatTime(h.time, 'hh:mm:ss.ms')}</td>
<td class="font-tabular text-muted">${this.formatTime(h.delta, 'seconds.ms')}</td>
<td class="text-end">
<span class="badge ${h.status === 'DONE' ? 'bg-danger' : 'bg-primary'} font-tabular" style="font-size: 0.6rem;">${h.status}</span>
</td>
</tr>
`).join('');
if (this.currentMode === 'relay') {
this.el.listBody.innerHTML = sortedHistory.map(h => `
<tr>
<td class="font-tabular fw-bold" style="border-left: 4px solid ${h.color}; padding-left: 10px;">${h.id}</td>
<td class="font-tabular">${this.formatTime(h.startTime || 0, 'hh:mm:ss.ms')}</td>
<td class="font-tabular text-primary">${this.formatTime(h.delta, 'hh:mm:ss.ms')}</td>
<td class="text-end font-tabular fw-bold">${this.formatTime(h.time, 'hh:mm:ss.ms')}</td>
</tr>
`).join('');
} else {
this.el.listBody.innerHTML = sortedHistory.map(h => `
<tr class="${h.delta === minDelta && h.delta > 0 ? 'table-success' : ''}">
<td class="font-tabular fw-bold">${h.id}</td>
<td class="font-tabular">${this.formatTime(h.time, 'hh:mm:ss.ms')}</td>
<td class="font-tabular text-muted">+${this.formatTime(h.delta, 'seconds.ms')}</td>
<td class="text-end">
${h.delta === minDelta && h.delta > 0 ? '<span class="badge-best">BEST</span>' : ''}
</td>
</tr>
`).join('');
}
} else if (this.currentMode === 'custom') {
this.el.listBody.innerHTML = this.history.slice().reverse().map(h => {
let badgeClass = 'bg-success';
@ -884,11 +1037,7 @@ const app = {
alert('Session saved successfully!');
if (this.currentMode === 'custom') {
this.customActivities = [{ name: 'Activity 1', duration: 60000, isRest: false }];
this.el.sessionTitle.value = '';
if (this.currentMode) this.sessionTitles[this.currentMode] = '';
this.renderCustomBuilder();
this.resetTimer();
this.resetCustomBuilder();
}
} else {
alert('Error saving session: ' + result.error);
@ -997,7 +1146,11 @@ const app = {
},
playCompletionAlert() {
this.el.mainTimer.classList.add('timer-finish');
this.el.mainTimer.classList.add('timer-finish-theme');
setTimeout(() => {
this.el.mainTimer.classList.remove('timer-finish-theme');
}, 3000);
if (this.el.alertCompletion.checked) {
this.beep(880, 0.5);
setTimeout(() => this.beep(1100, 0.5), 200);

View File

@ -158,7 +158,7 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
<div class="alert-settings-box">
<label class="d-block small text-muted text-uppercase tracking-wider mb-2 border-bottom pb-1">Sound Alerts</label>
<div class="mb-3">
<div id="pre-start-section" class="mb-3">
<div class="form-check form-switch mb-1">
<input class="form-check-input" type="checkbox" id="alert-pre-start">
<label class="form-check-label fw-bold small" for="alert-pre-start">Pre-start</label>
@ -169,7 +169,7 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
</div>
</div>
<div class="mb-3">
<div id="pre-finish-section" class="mb-3">
<div class="form-check form-switch mb-1">
<input class="form-check-input" type="checkbox" id="alert-pre-end" checked>
<label class="form-check-label fw-bold small" for="alert-pre-end">Pre-finish</label>
@ -187,7 +187,7 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
</div>
</div>
<div class="form-check form-switch">
<div id="completion-section" class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="alert-completion" checked>
<label class="form-check-label fw-bold small" for="alert-completion">Completion Sound</label>
</div>
@ -199,7 +199,7 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
<div class="timer-workspace-container">
<!-- Side Column (History / Builder) - LEFT -->
<!-- Side Column (History / Builder / Relay Config) - LEFT -->
<div id="timer-side-column" class="timer-side-column d-none">
<div class="card card-precise p-4 h-100">
@ -238,6 +238,7 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
</div>
<div class="d-flex gap-1">
<button id="btn-save-session-builder" class="btn btn-outline-success btn-sm btn-precise">Save</button>
<button id="btn-reset-builder" class="btn btn-outline-dark btn-sm btn-precise">Reset</button>
</div>
</div>
@ -246,6 +247,18 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
</div>
</div>
<!-- Relay Configuration Section -->
<div id="relay-config" class="d-none text-start">
<h4 class="fs-6 fw-bold text-uppercase tracking-widest mb-3 border-bottom pb-2">Participants</h4>
<div id="relay-participant-count-box" class="mb-3">
<label class="small text-muted mb-1 d-block">Participant Count (Max 12)</label>
<input type="number" id="participant-count" class="form-control form-control-precise" value="4" min="1" max="12" style="width: 80px;">
</div>
<div id="participant-names-container" class="d-flex flex-column gap-2">
<!-- Name inputs injected here -->
</div>
</div>
</div>
</div>
@ -269,6 +282,14 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
</div>
<div id="active-activity-name" class="text-primary d-none text-center mt-2">Activity Name</div>
<!-- Relay Active Participant Container -->
<div id="relay-active-participant-container" class="d-none mt-3 p-3 border rounded bg-light">
<div class="d-flex align-items-center justify-content-center gap-3">
<span id="relay-active-name" class="fw-bold fs-5">Participant Name</span>
<button id="btn-relay-split" class="btn btn-primary btn-sm btn-precise">Split</button>
</div>
</div>
</div>
<div class="timer-display font-tabular mb-2" id="main-timer">00:00:00.000</div>
@ -299,15 +320,6 @@ $projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
<button id="btn-delete-saved" class="btn btn-outline-danger btn-precise">Delete</button>
</div>
</div>
<!-- Mode Specific Inputs (Other) -->
<div class="d-flex justify-content-center flex-wrap gap-3 mb-5 mt-5">
<div id="relay-config" class="d-none text-start">
<label class="small text-muted mb-1 d-block">Participant Count</label>
<input type="number" id="participant-count" class="form-control form-control-precise" value="4" min="1" style="width: 100px;">
</div>
</div>
</div>
</div>