BELO Productions
Crew Intake
Crew Details
Enter one row per crew member. Add as many rows as needed, then submit all at once.
Fields marked * are required.
Crew members
0 rows
| Name* | Role* | Company* | Festival/Show* | Dept* | Phone* | Email* | Accred 1* | Accred 2* | Vehicle Pass* | Tee* | Allergies* | Accessibility* | On-site Dates * | Submit |
|---|
← Scroll horizontally to see all columns →
Submitted
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Crew Intake — BELO Productions</title>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #FAFAF8;
--white: #FFFFFF;
--black: #0D0D0D;
--mid: #F2F2EF;
--border: #D8D8D2;
--border-focus: #0D0D0D;
--muted: #888880;
--accent: #0D0D0D;
--error: #CC2200;
--success: #1A6B3C;
--row-hover: #F7F7F4;
--row-alt: #FDFDFB;
--header-bg: #0D0D0D;
--header-fg: #FFFFFF;
--radius: 2px;
--shift-bg: #F0F4FF;
--shift-border: #C8D4F0;
}
html { background: var(--bg); color: var(--black); font-family: 'IBM Plex Sans', sans-serif; font-size: 14px; }
body { min-height: 100vh; }
/* ── HEADER ── */
header {
background: var(--black);
padding: 16px 32px;
display: flex;
align-items: center;
gap: 20px;
position: sticky;
top: 0;
z-index: 100;
border-bottom: 1px solid #222;
}
.header-logo { height: 36px; width: auto; display: block; filter: brightness(0) invert(1); }
.header-divider { width: 1px; height: 28px; background: #333; flex-shrink: 0; }
.header-title { font-family: 'IBM Plex Mono', monospace; font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; color: #999; }
.header-festival { font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: #FFF; letter-spacing: 0.05em; margin-left: auto; display: none; }
/* ── PAGE LAYOUT ── */
.page { max-width: 1400px; margin: 0 auto; padding: 32px 24px 80px; }
.page-header { margin-bottom: 28px; }
.page-title { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; line-height: 1; margin-bottom: 6px; }
.page-sub { font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--muted); letter-spacing: 0.05em; line-height: 1.6; }
.page-sub span { color: var(--error); }
/* ── SECTION ── */
.section { margin-bottom: 32px; }
.section-head {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted);
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
margin-bottom: 0;
display: flex;
align-items: center;
justify-content: space-between;
}
/* ── GRID TABLE ── */
.grid-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
.grid-table thead tr { background: var(--header-bg); }
.grid-table thead th {
padding: 10px 8px;
text-align: left;
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
font-weight: 500;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--header-fg);
white-space: nowrap;
overflow: hidden;
border-right: 1px solid #333;
user-select: none;
}
.grid-table thead th:last-child { border-right: none; width: 36px; }
.grid-table thead th .req { color: #FF6B6B; margin-left: 2px; }
/* Column widths */
.col-name { width: 140px; }
.col-role { width: 130px; }
.col-company { width: 130px; }
.col-show { width: 120px; }
.col-dept { width: 100px; }
.col-phone { width: 120px; }
.col-email { width: 170px; }
.col-accred1 { width: 110px; }
.col-accred2 { width: 110px; }
.col-vehicle { width: 110px; }
.col-tee { width: 70px; }
.col-allergies { width: 140px; }
.col-access { width: 140px; }
.col-del { width: 36px; }
.col-shifts { width: 380px; min-width: 380px; }
.col-submit { width: 70px; min-width: 70px; text-align: center; }
/* Data rows */
.grid-table tbody tr {
border-bottom: 1px solid var(--border);
transition: background 0.1s;
}
.grid-table tbody tr:nth-child(even) { background: var(--row-alt); }
.grid-table tbody tr:hover { background: var(--row-hover); }
.grid-table tbody tr.error-row { background: #FFF5F5 !important; }
.grid-table tbody td {
padding: 3px 4px;
vertical-align: top;
border-right: 1px solid var(--border);
position: relative;
}
.grid-table tbody td:last-child { border-right: none; text-align: center; padding: 4px; }
/* Cell inputs */
.cell-input, .cell-select {
width: 100%;
border: none;
background: transparent;
font-family: 'IBM Plex Sans', sans-serif;
font-size: 12px;
color: var(--black);
padding: 5px 6px;
outline: none;
border-radius: var(--radius);
transition: background 0.1s, box-shadow 0.1s;
-webkit-appearance: none;
appearance: none;
}
.cell-input:focus, .cell-select:focus {
background: #FFFFF0;
box-shadow: inset 0 0 0 1.5px var(--border-focus);
}
.cell-input::placeholder { color: #C8C8C0; font-size: 11px; }
.cell-input.required-empty, .cell-select.required-empty { box-shadow: inset 0 0 0 1.5px var(--error); background: rgb(255, 245, 245); }
.cell-select {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%23888'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 6px center;
padding-right: 20px;
cursor: pointer;
}
.cell-select option { background: white; color: var(--black); }
/* Row number */
.row-num {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
color: var(--muted);
padding: 7px 4px;
text-align: right;
width: 28px;
user-select: none;
border-right: 1px solid var(--border);
background: var(--mid);
vertical-align: middle;
}
/* Delete button */
.del-btn {
background: none;
border: none;
cursor: pointer;
color: #CCC;
font-size: 16px;
line-height: 1;
padding: 4px;
border-radius: 2px;
transition: color 0.1s, background 0.1s;
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
}
.del-btn:hover { color: var(--error); background: #FFF0EE; }
/* Add row bar */
.add-row-bar {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 8px;
border: 1px dashed var(--border);
border-top: none;
background: var(--bg);
}
.add-btn {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
background: none;
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 6px 14px;
cursor: pointer;
color: var(--muted);
transition: all 0.15s;
}
.add-btn:hover { border-color: var(--black); color: var(--black); background: var(--mid); }
.add-btn.primary { background: var(--black); color: white; border-color: var(--black); }
.add-btn.primary:hover { background: #333; }
.row-count { font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--muted); }
/* ── SHIFTS SECTION ── */
.shifts-section { margin-top: 4px; }
.shifts-label {
font-family: 'IBM Plex Mono', monospace;
font-size: 9px;
color: var(--muted);
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 2px 6px;
}
.shift-row-inline {
display: flex;
align-items: center;
gap: 4px;
padding: 3px 0;
flex-wrap: nowrap;
}
.shift-input {
border: 1px solid var(--shift-border);
background: var(--shift-bg);
border-radius: var(--radius);
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
padding: 3px 5px;
outline: none;
color: var(--black);
}
.shift-input:focus { border-color: var(--black); }
.shift-input.date-inp { width: 96px; }
.shift-input.time-inp { width: 46px; }
.shift-sep { font-size: 10px; color: var(--muted); }
.shift-check-wrap { display: flex; align-items: center; gap: 3px; }
.shift-check-wrap input[type="checkbox"] { accent-color: var(--black); width: 12px; height: 12px; }
.shift-check-wrap label { font-size: 10px; color: var(--muted); cursor: pointer; white-space: nowrap; }
.shift-add-btn, .shift-del-btn {
background: none; border: none; cursor: pointer;
font-size: 14px; color: var(--muted); padding: 0 2px;
line-height: 1; border-radius: 2px;
}
.shift-add-btn:hover { color: var(--black); }
.shift-del-btn:hover { color: var(--error); }
/* ── BOTTOM ACTIONS ── */
.bottom-bar {
position: sticky;
bottom: 0;
background: var(--white);
border-top: 2px solid var(--black);
padding: 14px 24px;
display: flex;
align-items: center;
gap: 16px;
margin: 0 -24px;
}
.submit-btn {
background: var(--black);
color: white;
font-family: 'IBM Plex Sans', sans-serif;
font-weight: 600;
font-size: 13px;
padding: 11px 28px;
border: none;
border-radius: var(--radius);
cursor: pointer;
transition: opacity 0.15s;
letter-spacing: 0.01em;
}
.submit-btn:hover { opacity: 0.85; }
.submit-btn:disabled { opacity: 0.4; cursor: default; }
.clear-btn {
background: none;
border: 1px solid var(--border);
color: var(--muted);
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
padding: 11px 18px;
border-radius: var(--radius);
cursor: pointer;
transition: all 0.15s;
}
.clear-btn:hover { border-color: var(--black); color: var(--black); }
.status-msg {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
padding: 8px 14px;
border-radius: var(--radius);
display: none;
}
.status-msg.ok { display: block; background: #EEF7F2; color: var(--success); border: 1px solid #C0E0CE; }
.status-msg.err { display: block; background: #FFF0EE; color: var(--error); border: 1px solid #F0C8C0; }
.status-msg.sending { display: block; background: var(--mid); color: var(--muted); border: 1px solid var(--border); }
/* ── SUCCESS SCREEN ── */
.success-screen {
display: none;
text-align: center;
padding: 80px 40px;
}
.success-screen.show { display: block; }
.success-icon {
width: 56px; height: 56px;
background: var(--black);
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
margin: 0 auto 24px;
}
.success-icon svg { width: 26px; height: 26px; }
.success-screen h2 { font-size: 28px; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 8px; }
.success-screen p { font-family: 'IBM Plex Mono', monospace; font-size: 12px; color: var(--muted); line-height: 1.7; margin-bottom: 24px; }
.success-name-tag {
display: inline-block;
background: var(--mid);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 6px 14px;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
color: var(--black);
margin-bottom: 28px;
}
/* ── OVERLAY ── */
.overlay {
position: fixed; inset: 0;
background: rgba(255,255,255,0.88);
display: none; align-items: center; justify-content: center;
flex-direction: column; gap: 14px; z-index: 200;
}
.overlay.active { display: flex; }
.spinner {
width: 32px; height: 32px;
border: 2px solid var(--border);
border-top-color: var(--black);
border-radius: 50%;
animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.overlay p { font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--muted); letter-spacing: 0.1em; }
/* ── SCROLL HINT ── */
.scroll-hint {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
color: var(--muted);
text-align: right;
padding: 4px 0;
letter-spacing: 0.05em;
}
/* ── TABLE WRAPPER ── */
.table-wrap {
overflow-x: auto;
border: 1px solid var(--border);
border-radius: var(--radius);
}
.table-wrap::-webkit-scrollbar { height: 6px; }
.table-wrap::-webkit-scrollbar-track { background: var(--mid); }
.table-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.submitted-row td { opacity: 0.6; }
.submitted-row { background: #F0FFF4 !important; }
@media (max-width: 768px) {
header { padding: 12px 16px; }
.page { padding: 20px 12px 100px; }
.bottom-bar { padding: 12px 16px; margin: 0 -12px; }
}
</style>
</head>
<body>
<div class="overlay" id="overlay">
<div class="spinner"></div>
<p>Submitting crew details...</p>
</div>
<header>
<img class="header-logo" id="headerLogo" src="data:image/jpeg;base64,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" alt="BELO Productions" style="height:32px;width:auto;display:block;filter:brightness(0) invert(1);">
<div id="headerWordmark" style="display:flex;align-items:center;gap:12px;">
<span style="font-family:'IBM Plex Mono',monospace;font-size:13px;font-weight:600;color:#FFF;letter-spacing:0.05em;">BELO Productions</span>
</div>
<div class="header-divider"></div>
<span class="header-title">Crew Intake</span>
<span class="header-festival" id="headerFestival"></span>
</header>
<div class="page" id="mainPage">
<div class="page-header">
<h1 class="page-title">Crew Details</h1>
<p class="page-sub" id="pageSubtitle">
Enter one row per crew member. Add as many rows as needed, then submit all at once.<br>
Fields marked <span>*</span> are required.
</p>
</div>
<!-- CREW GRID -->
<div class="section">
<div class="section-head">
<span>Crew members</span>
<span class="row-count" id="rowCount">0 rows</span>
</div>
<div class="table-wrap">
<table class="grid-table" id="crewTable">
<thead>
<tr>
<th style="width:28px;background:#111;"></th>
<th class="col-name">Name<span class="req">*</span></th>
<th class="col-role">Role<span class="req">*</span></th>
<th class="col-company">Company<span class="req">*</span></th>
<th class="col-show">Festival/Show<span class="req">*</span></th>
<th class="col-dept">Dept<span class="req">*</span></th>
<th class="col-phone">Phone<span class="req">*</span></th>
<th class="col-email">Email<span class="req">*</span></th>
<th class="col-accred1">Accred 1<span class="req">*</span></th>
<th class="col-accred2">Accred 2<span class="req">*</span></th>
<th class="col-vehicle">Vehicle Pass<span class="req">*</span></th>
<th class="col-tee">Tee<span class="req">*</span></th>
<th class="col-allergies">Allergies<span class="req">*</span></th>
<th class="col-access">Accessibility<span class="req">*</span></th>
<th class="col-shifts">Shifts <span class="req">*</span></th>
<th class="col-submit">Submit</th>
<th class="col-del"></th>
</tr>
</thead>
<tbody id="crewBody"></tbody>
</table>
</div>
<div class="add-row-bar">
<button class="add-btn" onclick="addRow()">+ Add row</button>
<button class="add-btn" onclick="addRows(5)">+ Add 5 rows</button>
<button class="add-btn" onclick="addRows(10)">+ Add 10 rows</button>
<span class="row-count" id="rowCount2"></span>
</div>
<div class="scroll-hint">← Scroll horizontally to see all columns →</div>
</div>
<div class="bottom-bar">
<button class="submit-btn" id="submitBtn" onclick="submitAll()">Submit all unsent rows</button>
<button class="clear-btn" onclick="clearAll()">Clear all</button>
<div class="status-msg" id="statusMsg"></div>
</div>
</div>
<!-- SUCCESS -->
<div class="success-screen" id="successScreen">
<div class="success-icon">
<svg viewBox="0 0 26 26" fill="none">
<path d="M5 13l6 6L21 7" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<h2>Submitted</h2>
<div class="success-name-tag" id="successTag"></div>
<p id="successMsg"></p>
<button class="submit-btn" onclick="addMore()" style="margin:0 auto;">Add more crew</button>
</div>
<script>
// ── CONFIG ── Update these per festival ──
// SETUP:
// 1. Deploy WebApp.gs as a Google Apps Script web app → copy the URL
// 2. In Formspree dashboard → your form → Integrations → Webhook
// → paste the web app URL as the webhook endpoint
// 3. Formspree will forward every submission to the web app automatically
var CONFIG = {
formspreeEndpoint: 'https://formspree.io/f/mykodqwa', // your Formspree form ID
festivalName: 'R&V 2026', // e.g. 'Rhythm & Vines 2026' — must match registry exactly
festivalLogoUrl: '', // optional festival logo URL
};
// Apply branding
(function() {
if (CONFIG.festivalName) {
var hf = document.getElementById('headerFestival');
hf.textContent = CONFIG.festivalName;
hf.style.display = 'block';
document.title = CONFIG.festivalName + ' — Crew Intake';
document.getElementById('pageSubtitle').innerHTML =
'<strong>' + CONFIG.festivalName + '</strong> · ' +
document.getElementById('pageSubtitle').innerHTML;
}
// Logo always shown — embedded directly
document.getElementById('headerLogo').style.display = 'block';
document.getElementById('headerWordmark').style.display = 'none';
})();
// ── OPTIONS ──
var DEPTS = ['PROD','LX','VIDEO','LASERS','SFX','AUDIO','POWER','ART','SITE','STAGE CREW','STAGE MANAGER'];
var ACCREDS = ['','PRODUCTION','AAA','STAFF','ARTIST HOUSE','n/a'];
var VEHICLES = ['','NONE','STAFF','LOADING DOCK','MOVE','PRODUCTION PARK'];
var TEES = ['','XS','S','M','L','XL','2XL','3XL','4XL','5XL'];
var rowCount = 0;
var rows = [];
// ── SAVED VALUES (localStorage) ──
var SAVED_KEYS = ['company','showName','accred1','accred2','vehiclePass'];
function getSaved(key) {
try { return localStorage.getItem('belo_crew_' + key) || ''; } catch(e) { return ''; }
}
function setSaved(key, val) {
try { localStorage.setItem('belo_crew_' + key, val); } catch(e) {}
}
// ── BUILD ROW ──
function addRow(data) {
rowCount++;
var id = 'r' + rowCount;
rows.push(id);
var tbody = document.getElementById('crewBody');
var tr = document.createElement('tr');
tr.id = id;
tr.dataset.rowNum = rowCount;
var company = (data && data.company) || getSaved('company') || '';
var showName = (data && data.showName) || getSaved('showName') || (CONFIG.festivalName || '');
var accred1 = (data && data.accred1) || getSaved('accred1') || 'PRODUCTION';
var accred2 = (data && data.accred2) || getSaved('accred2') || 'n/a';
var vehicle = (data && data.vehicle) || getSaved('vehiclePass') || '';
tr.innerHTML =
'<td class="row-num">' + rowCount + '</td>' +
td('name', inp('name', data&&data.name||'', 'Full name', true)) +
td('role', inp('role', data&&data.role||'', 'Job title', true)) +
td('company', inp('company', company, 'Company', true, true)) +
td('show', inp('show', showName, 'Show name', true, true)) +
td('dept', sel('dept', DEPTS, data&&data.dept||'', true)) +
td('phone', inp('phone', data&&data.phone||'', '021...', true)) +
td('email', inp('email', data&&data.email||'', 'email@...', true)) +
td('accred1', sel('accred1', ACCREDS, accred1, true, true)) +
td('accred2', sel('accred2', ACCREDS, accred2, true, true)) +
td('vehicle', sel('vehicle', VEHICLES, vehicle, true, true)) +
td('tee', sel('tee', TEES, data&&data.tee||'', true)) +
td('allergies', inp('allergies', data&&data.allergies||'', 'None / list', true)) +
td('access', inp('access', data&&data.access||'', 'None / list', true)) +
'<td class="col-shifts" style="padding:6px;vertical-align:top;">' + buildShiftsCell(id) + '</td>' +
'<td class="col-submit" style="vertical-align:top;padding:6px;">' +
'<button class="row-submit-btn" id="sub_' + id + '" onclick="submitRow(\'' + id + '\') " title="Submit this row" ' +
'style="background:#0D0D0D;color:#fff;border:none;border-radius:2px;padding:7px 10px;font-size:10px;font-family:\'IBM Plex Mono\',monospace;letter-spacing:0.05em;cursor:pointer;white-space:nowrap;transition:opacity 0.15s;width:100%;">Submit</button>' +
'</td>' +
'<td class="col-del" style="vertical-align:top;padding:4px;"><button class="del-btn" onclick="delRow(\'' + id + '\') " title="Remove row">×</button></td>';
tbody.appendChild(tr);
updateCount();
attachSaveListeners(tr);
// Auto-add one shift row so it's always visible
addShift(id);
}
function td(cls, content) {
return '<td class="col-' + cls + '">' + content + '</td>';
}
function inp(name, val, placeholder, required, saveable) {
var r = required ? ' data-required="1"' : '';
var s = saveable ? ' data-save="' + name + '"' : '';
return '<input class="cell-input" type="text" name="' + name + '" value="' +
escHtml(val) + '" placeholder="' + placeholder + '"' + r + s + '>';
}
function sel(name, options, selected, required, saveable) {
var r = required ? ' data-required="1"' : '';
var s = saveable ? ' data-save="' + name + '"' : '';
var html = '<select class="cell-select" name="' + name + '"' + r + s + '>';
if (!options[0]) html += '<option value="">—</option>';
options.forEach(function(o) {
if (!o) return;
html += '<option value="' + o + '"' + (o === selected ? ' selected' : '') + '>' + o + '</option>';
});
html += '</select>';
return html;
}
function buildShiftsCell(rowId) {
return '<div class="shifts-section" id="shifts_' + rowId + '" style="width:100%;min-width:0;">' +
'<div class="shifts-list" id="shiftlist_' + rowId + '" style="display:flex;flex-direction:column;gap:4px;"></div>' +
'<button type="button" onclick="addShift(\'' + rowId + '\')" ' +
'style="font-family:\'IBM Plex Mono\',monospace;font-size:9px;color:#888;background:none;' +
'border:1px dashed #ccc;border-radius:2px;padding:3px 8px;cursor:pointer;margin-top:4px;' +
'width:100%;letter-spacing:0.05em;text-transform:uppercase;display:block;">+ add shift</button>' +
'</div>';
}
function addShift(rowId) {
var container = document.getElementById('shiftlist_' + rowId);
var shiftId = rowId + '_s' + Date.now();
var div = document.createElement('div');
div.className = 'shift-row-inline';
div.id = shiftId;
div.style.cssText = 'display:flex;align-items:center;gap:3px;flex-wrap:nowrap;background:#F7F7FF;border-radius:2px;padding:4px 5px;border:1px solid #E0E4F0;';
div.innerHTML =
'<input class="shift-input date-inp" type="date" title="Date" style="width:110px;min-width:110px;">' +
'<input class="shift-input time-inp" type="time" title="Start time" style="width:52px;">' +
'<span style="color:#aaa;font-size:10px;flex-shrink:0;">–</span>' +
'<input class="shift-input time-inp" type="time" title="End time" style="width:52px;">' +
'<label style="display:flex;align-items:center;gap:2px;cursor:pointer;flex-shrink:0;" title="Onsite">' +
'<input type="checkbox" class="s-onsite" style="width:11px;height:11px;"> ' +
'<span style="font-size:10px;color:#555;white-space:nowrap;">Onsite</span>' +
'</label>' +
'<label style="display:flex;align-items:center;gap:2px;cursor:pointer;flex-shrink:0;" title="Travel day">' +
'<input type="checkbox" class="s-travel" style="width:11px;height:11px;"> ' +
'<span style="font-size:10px;color:#555;white-space:nowrap;">Travel day</span>' +
'</label>' +
'<button type="button" onclick="this.parentNode.remove()" title="Remove shift" ' +
'style="background:none;border:none;color:#ccc;cursor:pointer;font-size:13px;padding:0 2px;flex-shrink:0;line-height:1;">×</button>';
container.appendChild(div);
// Mutual exclusion for onsite/travel + disable times
var cbO = div.querySelector('.s-onsite');
var cbT = div.querySelector('.s-travel');
var tS = div.querySelectorAll('.time-inp');
function toggle() {
if (cbO.checked || cbT.checked) {
tS.forEach(function(t){ t.disabled=true; t.value=''; });
if (cbO.checked) cbT.checked = false;
if (cbT.checked) cbO.checked = false;
} else {
tS.forEach(function(t){ t.disabled=false; });
}
}
cbO.addEventListener('change', toggle);
cbT.addEventListener('change', toggle);
}
function attachSaveListeners(tr) {
tr.querySelectorAll('[data-save]').forEach(function(el) {
el.addEventListener('change', function() {
setSaved(el.dataset.save, el.value);
});
});
}
function delRow(id) {
var tr = document.getElementById(id);
if (tr) tr.remove();
rows = rows.filter(function(r){ return r !== id; });
updateCount();
}
function addRows(n) {
for (var i = 0; i < n; i++) addRow();
}
function updateCount() {
var n = document.getElementById('crewBody').querySelectorAll('tr').length;
var txt = n + ' row' + (n !== 1 ? 's' : '');
document.getElementById('rowCount').textContent = txt;
document.getElementById('rowCount2').textContent = txt;
}
function clearAll() {
if (!confirm('Clear all rows?')) return;
document.getElementById('crewBody').innerHTML = '';
rows = []; rowCount = 0;
updateCount();
addRow(); addRow(); addRow();
}
function escHtml(s) {
return String(s||'').replace(/&/g,'&').replace(/"/g,'"').replace(/</g,'<').replace(/>/g,'>');
}
// ── COLLECT ROW DATA ──
function getRowData(tr) {
var d = {};
tr.querySelectorAll('.cell-input, .cell-select').forEach(function(el) {
d[el.name] = el.value.trim();
});
// Shifts
var shifts = [];
tr.querySelectorAll('.shift-row-inline').forEach(function(sr) {
var date = sr.querySelector('.date-inp').value;
var start = sr.querySelector('.time-inp').value;
var endInps = sr.querySelectorAll('.time-inp');
var end = endInps.length > 1 ? endInps[1].value : '';
var onsite = sr.querySelector('.s-onsite').checked;
var travel = sr.querySelector('.s-travel').checked;
if (date) shifts.push({ date:date, start:start, end:end, onsite:onsite, travel:travel });
});
d.shifts = shifts;
return d;
}
function validateRow(tr, rowNum) {
var valid = true;
tr.querySelectorAll('[data-required]').forEach(function(el) {
var empty = !el.value || el.value === '' || el.value === '—';
el.classList.toggle('required-empty', empty);
if (empty) valid = false;
});
if (!valid) tr.classList.add('error-row');
else tr.classList.remove('error-row');
return valid;
}
// ── SUBMIT SINGLE ROW ──
function submitRow(rowId) {
var tr = document.getElementById(rowId);
if (!tr) return;
var name = tr.querySelector('[name="name"]');
if (!name || !name.value.trim()) {
setStatus('Please enter a name before submitting this row.', 'err');
return;
}
if (!validateRow(tr, 1)) {
setStatus('Please fill in all required fields in this row (highlighted red).', 'err');
return;
}
// Validate shifts — at least one shift with a date is required
var shiftRows = tr.querySelectorAll('.shift-row-inline');
var hasValidShift = false;
shiftRows.forEach(function(sr) {
if (sr.querySelector('.date-inp').value) hasValidShift = true;
});
if (!hasValidShift) {
// Highlight the shifts cell
var shiftsCell = tr.querySelector('.shifts-section');
if (shiftsCell) {
shiftsCell.style.boxShadow = 'inset 0 0 0 1.5px #CC2200';
shiftsCell.style.borderRadius = '2px';
setTimeout(function() {
shiftsCell.style.boxShadow = '';
}, 3000);
}
setStatus('Please add at least one shift date before submitting.', 'err');
return;
}
var data = getRowData(tr);
var festivalName = CONFIG.festivalName || data.show || 'BELO Productions';
sendToFormspree([data], festivalName, function(ok) {
if (ok) {
markRowSubmitted(rowId, data.name);
setStatus(data.name + ' submitted successfully. Add more crew or close the form.', 'ok');
}
});
}
// ── SUBMIT ALL UNSUBMITTED ROWS ──
function submitAll() {
var tbody = document.getElementById('crewBody');
var trs = Array.from(tbody.querySelectorAll('tr:not(.submitted-row)'));
var filledRows = trs.filter(function(tr) {
var name = tr.querySelector('[name="name"]');
return name && name.value.trim() !== '';
});
if (filledRows.length === 0) {
setStatus('No unsubmitted crew to send. Use the row Submit buttons or add more crew.', 'err');
return;
}
var allValid = true;
var missingShifts = [];
filledRows.forEach(function(tr, i) {
if (!validateRow(tr, i+1)) allValid = false;
// Check shifts
var shiftRows = tr.querySelectorAll('.shift-row-inline');
var hasShift = false;
shiftRows.forEach(function(sr) { if (sr.querySelector('.s-date').value) hasShift = true; });
if (!hasShift) {
allValid = false;
var nameEl = tr.querySelector('[name="name"]');
missingShifts.push(nameEl ? nameEl.value || 'Row ' + (i+1) : 'Row ' + (i+1));
var shiftsCell = tr.querySelector('.shifts-section');
if (shiftsCell) {
shiftsCell.style.boxShadow = 'inset 0 0 0 1.5px #CC2200';
shiftsCell.style.borderRadius = '2px';
}
}
});
if (!allValid) {
var msg = 'Please fill in all required fields (highlighted in red).';
if (missingShifts.length > 0) msg += ' Missing shifts for: ' + missingShifts.join(', ') + '.';
setStatus(msg, 'err');
return;
}
var crewData = filledRows.map(function(tr) { return getRowData(tr); });
var festivalName = CONFIG.festivalName || (crewData[0] && crewData[0].show) || 'BELO Productions';
sendToFormspree(crewData, festivalName, function(ok) {
if (ok) {
filledRows.forEach(function(tr) {
var nameEl = tr.querySelector('[name="name"]');
if (nameEl) markRowSubmitted(tr.id, nameEl.value);
});
setStatus(crewData.length + ' crew member(s) submitted successfully.', 'ok');
}
});
}
// ── MARK ROW AS SUBMITTED ──
function markRowSubmitted(rowId, name) {
var tr = document.getElementById(rowId);
if (!tr) return;
tr.classList.add('submitted-row');
tr.style.opacity = '0.6';
tr.style.background = '#F0FFF4';
// Replace submit button with tick + edit button
var btn = document.getElementById('sub_' + rowId);
if (btn) {
btn.parentNode.innerHTML =
'<div style="display:flex;flex-direction:column;gap:3px;align-items:center;">' +
'<span style="font-family:IBM Plex Mono,monospace;font-size:10px;color:#1A6B3C;font-weight:600;">✓ Sent</span>' +
'<button onclick="editRow(\'' + rowId + '\')" ' +
'style="background:none;border:1px solid #D8D8D2;border-radius:2px;padding:2px 6px;' +
'font-family:IBM Plex Mono,monospace;font-size:9px;color:#888;cursor:pointer;letter-spacing:0.05em;" ' +
'title="Edit and resubmit this row">Edit</button>' +
'</div>';
}
// Disable all inputs in this row
tr.querySelectorAll('input, select').forEach(function(el) { el.disabled = true; });
}
// ── UNLOCK ROW FOR EDITING ──
function editRow(rowId) {
var tr = document.getElementById(rowId);
if (!tr) return;
tr.classList.remove('submitted-row');
tr.style.opacity = '1';
tr.style.background = '#FFFDE7'; // yellow tint to show it needs resubmitting
// Re-enable all inputs
tr.querySelectorAll('input, select').forEach(function(el) { el.disabled = false; });
// Replace the sent/edit buttons with a resubmit button
var submitCell = tr.querySelector('td:nth-last-child(2)');
if (submitCell) {
submitCell.innerHTML =
'<button id="sub_' + rowId + '" onclick="resubmitRow(\'' + rowId + '\')" ' +
'style="background:#CC7700;color:#fff;border:none;border-radius:2px;padding:5px 8px;' +
'font-size:10px;font-family:IBM Plex Mono,monospace;letter-spacing:0.05em;cursor:pointer;white-space:nowrap;">' +
'Resubmit</button>';
}
}
// ── RESUBMIT EDITED ROW ──
function resubmitRow(rowId) {
var tr = document.getElementById(rowId);
if (!tr) return;
var name = tr.querySelector('[name="name"]');
if (!name || !name.value.trim()) {
setStatus('Please enter a name before resubmitting.', 'err');
return;
}
if (!validateRow(tr, 1)) {
setStatus('Please fill in all required fields in this row.', 'err');
return;
}
var data = getRowData(tr);
data._resubmit = true; // flag so you know it's a correction
var festivalName = CONFIG.festivalName || data.show || 'BELO Productions';
sendToFormspree([data], festivalName, function(ok) {
if (ok) {
tr.style.background = '';
markRowSubmitted(rowId, data.name);
setStatus(data.name + ' updated and resubmitted.', 'ok');
}
});
}
// ── CORE SEND FUNCTION ──
function sendToFormspree(crewData, festivalName, callback) {
var subject = festivalName + ' — Crew intake: ' + crewData.length + ' crew member(s)';
var emailBody = formatEmailBody(crewData, festivalName);
document.getElementById('overlay').classList.add('active');
fetch(CONFIG.formspreeEndpoint, {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({
_subject: subject,
festival: festivalName,
crew_count: crewData.length,
crew_summary: crewData.map(function(c){ return c.name + ' (' + c.role + ')'; }).join(', '),
crew_json: JSON.stringify(crewData),
details: emailBody
})
})
.then(function(res) {
document.getElementById('overlay').classList.remove('active');
if (res.ok) {
callback(true);
} else {
res.json().then(function(d) {
setStatus('Submission failed: ' + (d.error || 'Please try again.'), 'err');
callback(false);
});
}
})
.catch(function(err) {
document.getElementById('overlay').classList.remove('active');
setStatus('Network error. Check your connection and try again.', 'err');
callback(false);
});
}
function formatEmailBody(crew, festival) {
return crew.map(function(c, i) {
var shifts = (c.shifts||[]).map(function(s) {
if (s.travel) return s.date + ': TRAVEL DAY';
if (s.onsite) return s.date + ': ONSITE';
if (s.start && s.end) return s.date + ': ' + s.start + ' – ' + s.end;
return s.date;
}).join(', ') || 'No shifts entered';
return [
'--- Crew #' + (i+1) + ' ---',
'Name: ' + c.name,
'Role: ' + c.role,
'Company: ' + c.company,
'Show: ' + c.show,
'Department: ' + c.dept,
'Phone: ' + c.phone,
'Email: ' + c.email,
'Accred 1: ' + c.accred1,
'Accred 2: ' + c.accred2,
'Vehicle pass: ' + c.vehicle,
'Tee size: ' + c.tee,
'Allergies: ' + c.allergies,
'Accessibility: '+ c.access,
'Shifts: ' + shifts
].join('\n');
}).join('\n\n');
}
function setStatus(msg, type) {
var el = document.getElementById('statusMsg');
el.textContent = msg;
el.className = 'status-msg ' + type;
}
function showSuccess(count, festival) {
// No longer used — status shown inline
}
function addMore() {
// Just scroll back to table and add a new row — keep submitted rows visible
document.getElementById('successScreen').classList.remove('show');
document.getElementById('mainPage').style.display = 'block';
addRow();
updateCount();
window.scrollTo(0,0);
}
// Init — start with 3 blank rows
addRow(); addRow(); addRow();
</script>
</body>
</html>

