Coach — Check In Form
An energetic weekly check-in form for online fitness coaching that logs bodyweight and tape measurements, captures energy, sleep and adherence with glowing lime sliders, accepts drag-and-drop progress photos, and rolls every entry into a live summary card the moment a client hits submit.
MCP
Code
:root {
--bg: #0f1115;
--surface: #171a21;
--surface-2: #1f232c;
--lime: #c2f542;
--lime-d: #a3d62f;
--orange: #ff6b35;
--ink: #f2f4f0;
--muted: #9aa0a6;
--line: rgba(255, 255, 255, 0.10);
--line-2: rgba(255, 255, 255, 0.18);
--white: #fff;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--red: #ff5470;
--amber: #ffb347;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: "Inter", system-ui, -apple-system, sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
}
.glow {
position: fixed;
inset: 0;
pointer-events: none;
background:
radial-gradient(600px 400px at 85% -5%, rgba(194, 245, 66, 0.12), transparent 60%),
radial-gradient(500px 380px at 0% 20%, rgba(255, 107, 53, 0.10), transparent 60%);
z-index: 0;
}
.wrap {
position: relative;
z-index: 1;
max-width: 960px;
margin: 0 auto;
padding: 32px 20px 140px;
}
/* MASTHEAD */
.masthead {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 18px;
}
.brand { display: flex; align-items: center; gap: 14px; }
.brand-mark {
display: grid;
place-items: center;
width: 46px;
height: 46px;
border-radius: var(--r-md);
background: linear-gradient(135deg, var(--lime), var(--lime-d));
color: #10130a;
font-size: 20px;
font-weight: 800;
box-shadow: 0 0 24px rgba(194, 245, 66, 0.35);
}
.kicker {
margin: 0;
font-size: 12px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--lime);
font-weight: 700;
}
h1 {
margin: 0;
font-family: "Barlow Condensed", "Inter", sans-serif;
font-size: 34px;
line-height: 1;
letter-spacing: 0.02em;
text-transform: uppercase;
font-weight: 800;
}
.week-pill {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 14px;
border: 1px solid var(--line-2);
border-radius: 999px;
background: var(--surface);
font-size: 13px;
font-weight: 600;
color: var(--muted);
}
.week-pill .dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--lime);
box-shadow: 0 0 10px var(--lime);
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.35; }
}
.lede {
margin: 0 0 26px;
max-width: 62ch;
color: var(--muted);
font-size: 15px;
}
.lede strong { color: var(--ink); }
/* GRID */
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
}
.card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 22px;
transition: border-color 0.2s ease, transform 0.2s ease;
}
.card:hover { border-color: var(--line-2); }
.card:nth-of-type(3),
.card:nth-of-type(4) { grid-column: 1 / -1; }
.card-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 18px;
}
h2 {
margin: 0;
font-family: "Barlow Condensed", "Inter", sans-serif;
font-size: 21px;
letter-spacing: 0.03em;
text-transform: uppercase;
font-weight: 700;
}
.badge {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 999px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
background: rgba(194, 245, 66, 0.14);
color: var(--lime);
}
.badge-line {
background: transparent;
border: 1px solid var(--line-2);
color: var(--muted);
}
/* FIELDS */
.field { display: flex; flex-direction: column; gap: 7px; margin-bottom: 14px; }
.field.mt { margin-top: 6px; margin-bottom: 0; }
.field:last-child { margin-bottom: 0; }
label {
font-size: 13px;
font-weight: 600;
color: var(--ink);
}
.req { color: var(--orange); }
.input-suffix { position: relative; display: flex; align-items: center; }
input[type="number"],
textarea {
width: 100%;
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: var(--r-md);
color: var(--ink);
font: inherit;
font-size: 15px;
padding: 12px 14px;
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
input[type="number"] { padding-right: 44px; }
input[type="number"]:hover,
textarea:hover { border-color: var(--line-2); }
input[type="number"]:focus,
textarea:focus {
outline: none;
border-color: var(--lime);
box-shadow: 0 0 0 3px rgba(194, 245, 66, 0.22);
background: #23272f;
}
input.invalid {
border-color: var(--red);
box-shadow: 0 0 0 3px rgba(255, 84, 112, 0.18);
animation: shake 0.3s;
}
@keyframes shake {
25% { transform: translateX(-4px); }
75% { transform: translateX(4px); }
}
.suffix {
position: absolute;
right: 14px;
font-size: 13px;
font-weight: 600;
color: var(--muted);
pointer-events: none;
}
.measure-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.measure-grid .field { margin-bottom: 0; }
.err {
margin: 2px 0 0;
font-size: 12px;
font-weight: 600;
color: var(--red);
min-height: 0;
}
textarea { resize: vertical; min-height: 96px; }
/* SLIDERS */
.slider-row { margin-bottom: 18px; }
.slider-row:last-of-type { margin-bottom: 0; }
.slider-top {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 9px;
}
.slider-out { display: inline-flex; align-items: center; gap: 8px; }
.slider-out b {
font-family: "Barlow Condensed", sans-serif;
font-size: 20px;
font-weight: 800;
color: var(--lime);
min-width: 22px;
text-align: right;
}
.verdict {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
padding: 2px 8px;
border-radius: 999px;
}
.verdict.low { background: rgba(255, 84, 112, 0.16); color: var(--red); }
.verdict.mid { background: rgba(255, 179, 71, 0.16); color: var(--amber); }
.verdict.high { background: rgba(194, 245, 66, 0.16); color: var(--lime); }
input[type="range"] {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 8px;
border-radius: 999px;
background: var(--surface-2);
outline: none;
cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
height: 8px;
border-radius: 999px;
background: linear-gradient(90deg, var(--lime) var(--fill, 45%), var(--surface-2) var(--fill, 45%));
}
input[type="range"]::-moz-range-track {
height: 8px;
border-radius: 999px;
background: var(--surface-2);
}
input[type="range"]::-moz-range-progress {
height: 8px;
border-radius: 999px;
background: var(--lime);
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 22px;
height: 22px;
margin-top: -7px;
border-radius: 50%;
background: var(--white);
border: 3px solid var(--lime-d);
box-shadow: 0 0 14px rgba(194, 245, 66, 0.55);
transition: transform 0.12s ease;
}
input[type="range"]::-moz-range-thumb {
width: 22px;
height: 22px;
border-radius: 50%;
background: var(--white);
border: 3px solid var(--lime-d);
box-shadow: 0 0 14px rgba(194, 245, 66, 0.55);
}
input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.15); }
input[type="range"]:focus-visible::-webkit-slider-thumb {
box-shadow: 0 0 0 4px rgba(194, 245, 66, 0.3);
}
/* CHIPS */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
border: 1px solid var(--line-2);
background: var(--surface-2);
color: var(--muted);
font: inherit;
font-size: 13px;
font-weight: 600;
padding: 8px 14px;
border-radius: 999px;
cursor: pointer;
transition: all 0.15s ease;
}
.chip:hover { border-color: var(--lime); color: var(--ink); }
.chip:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgba(194, 245, 66, 0.3);
}
.chip.is-on {
background: var(--lime);
color: #10130a;
border-color: var(--lime);
box-shadow: 0 0 16px rgba(194, 245, 66, 0.4);
}
/* DROPZONE */
.dropzone {
border: 2px dashed var(--line-2);
border-radius: var(--r-md);
padding: 26px 16px;
text-align: center;
cursor: pointer;
transition: all 0.18s ease;
background: rgba(255, 255, 255, 0.015);
}
.dropzone:hover,
.dropzone:focus-visible {
outline: none;
border-color: var(--lime);
background: rgba(194, 245, 66, 0.06);
}
.dropzone.drag {
border-color: var(--lime);
background: rgba(194, 245, 66, 0.10);
transform: scale(1.01);
}
.drop-ico {
display: inline-grid;
place-items: center;
width: 42px;
height: 42px;
border-radius: 50%;
background: var(--surface-2);
color: var(--lime);
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
}
.drop-title { margin: 0; font-weight: 600; font-size: 15px; }
.drop-title .link { color: var(--lime); text-decoration: underline; }
.drop-sub { margin: 4px 0 0; font-size: 12px; color: var(--muted); }
.thumbs {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 14px;
}
.thumbs:empty { display: none; }
.thumb {
position: relative;
width: 84px;
height: 84px;
border-radius: var(--r-sm);
overflow: hidden;
border: 1px solid var(--line-2);
animation: pop 0.25s ease;
}
@keyframes pop {
from { transform: scale(0.8); opacity: 0; }
}
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb .rm {
position: absolute;
top: 4px;
right: 4px;
width: 22px;
height: 22px;
border: none;
border-radius: 50%;
background: rgba(15, 17, 21, 0.85);
color: var(--white);
font-size: 14px;
line-height: 1;
cursor: pointer;
display: grid;
place-items: center;
}
.thumb .rm:hover { background: var(--red); }
.thumb .tag {
position: absolute;
left: 0;
bottom: 0;
right: 0;
font-size: 10px;
font-weight: 700;
text-align: center;
padding: 2px;
background: rgba(15, 17, 21, 0.7);
color: var(--lime);
text-transform: uppercase;
letter-spacing: 0.04em;
}
/* SUBMIT BAR */
.submitbar {
grid-column: 1 / -1;
position: sticky;
bottom: 16px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
flex-wrap: wrap;
padding: 14px 18px;
background: rgba(23, 26, 33, 0.9);
backdrop-filter: blur(12px);
border: 1px solid var(--line-2);
border-radius: var(--r-lg);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
.submit-hint { margin: 0; font-size: 13px; color: var(--muted); }
.submit-hint.ok { color: var(--lime); }
.cta {
border: none;
font: inherit;
font-weight: 800;
font-size: 15px;
letter-spacing: 0.03em;
text-transform: uppercase;
padding: 13px 26px;
border-radius: var(--r-md);
background: linear-gradient(135deg, var(--lime), var(--lime-d));
color: #10130a;
cursor: pointer;
box-shadow: 0 0 22px rgba(194, 245, 66, 0.45);
transition: transform 0.12s ease, box-shadow 0.2s ease, opacity 0.2s;
}
.cta:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 0 32px rgba(194, 245, 66, 0.65); }
.cta:active:not(:disabled) { transform: translateY(0); }
.cta:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(194, 245, 66, 0.4); }
.cta:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; }
/* SUMMARY */
.summary {
margin-top: 24px;
background: var(--surface);
border: 1px solid var(--lime);
border-radius: var(--r-lg);
padding: 26px;
box-shadow: 0 0 40px rgba(194, 245, 66, 0.12);
animation: rise 0.4s ease;
}
@keyframes rise {
from { transform: translateY(16px); opacity: 0; }
}
.sum-head {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 18px;
}
.sum-check {
display: grid;
place-items: center;
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--lime);
color: #10130a;
font-size: 20px;
font-weight: 800;
}
.sum-head h2 { margin: 0; }
.sum-head p { margin: 0; font-size: 13px; color: var(--muted); }
.sum-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px;
margin-bottom: 18px;
}
.stat {
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 12px 14px;
}
.stat .k { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 700; }
.stat .v {
font-family: "Barlow Condensed", sans-serif;
font-size: 26px;
font-weight: 800;
color: var(--ink);
line-height: 1.1;
}
.stat .v small { font-size: 13px; color: var(--muted); font-weight: 600; }
.sum-verdicts { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.streak {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
border-radius: var(--r-md);
background: linear-gradient(135deg, rgba(255, 107, 53, 0.18), rgba(194, 245, 66, 0.12));
border: 1px solid var(--line-2);
font-weight: 600;
font-size: 14px;
}
.streak .fire { font-size: 20px; }
.sum-notes {
margin-top: 14px;
font-size: 14px;
color: var(--muted);
border-left: 3px solid var(--lime);
padding: 4px 0 4px 14px;
}
.sum-notes:empty { display: none; }
/* TOAST */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 20px);
background: var(--surface-2);
border: 1px solid var(--lime);
color: var(--ink);
padding: 13px 20px;
border-radius: var(--r-md);
font-size: 14px;
font-weight: 600;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
z-index: 50;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* RESPONSIVE */
@media (max-width: 520px) {
.wrap { padding: 22px 14px 130px; }
h1 { font-size: 28px; }
.grid { grid-template-columns: 1fr; }
.card:nth-of-type(3),
.card:nth-of-type(4) { grid-column: auto; }
.measure-grid { grid-template-columns: 1fr 1fr; }
.masthead { gap: 12px; }
.week-pill { font-size: 12px; }
.submitbar { flex-direction: column; align-items: stretch; }
.cta { width: 100%; }
.submit-hint { text-align: center; }
}(function () {
"use strict";
var form = document.getElementById("checkin");
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
/* ---------- SLIDERS ---------- */
function verdictFor(v) {
if (v <= 3) return { cls: "low", label: "Low" };
if (v <= 6) return { cls: "mid", label: "OK" };
return { cls: "high", label: "Strong" };
}
function paintSlider(input) {
var min = +input.min, max = +input.max, val = +input.value;
var pct = ((val - min) / (max - min)) * 100;
input.style.setProperty("--fill", pct + "%");
var key = input.id;
var out = document.querySelector('[data-out="' + key + '"]');
var vEl = document.querySelector('[data-verdict="' + key + '"]');
if (out) out.textContent = val;
if (vEl) {
var vd = verdictFor(val);
vEl.textContent = vd.label;
vEl.className = "verdict " + vd.cls;
}
}
var sliders = Array.prototype.slice.call(document.querySelectorAll('input[type="range"]'));
sliders.forEach(function (s) {
paintSlider(s);
s.addEventListener("input", function () { paintSlider(s); });
});
/* ---------- HUNGER CHIPS ---------- */
var hunger = "Manageable";
var chips = Array.prototype.slice.call(document.querySelectorAll(".chip"));
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
chips.forEach(function (c) { c.classList.remove("is-on"); c.setAttribute("aria-pressed", "false"); });
chip.classList.add("is-on");
chip.setAttribute("aria-pressed", "true");
hunger = chip.getAttribute("data-hunger");
});
});
/* ---------- PHOTOS ---------- */
var drop = document.getElementById("drop");
var fileInput = document.getElementById("files");
var thumbs = document.getElementById("thumbs");
var countEl = document.getElementById("photo-count");
var photos = [];
var TAGS = ["Front", "Side", "Back", "Extra"];
function renderPhotos() {
thumbs.innerHTML = "";
photos.forEach(function (p, i) {
var t = document.createElement("div");
t.className = "thumb";
var img = document.createElement("img");
img.src = p.url;
img.alt = "Progress photo " + (i + 1);
var tag = document.createElement("span");
tag.className = "tag";
tag.textContent = TAGS[i] || "Extra";
var rm = document.createElement("button");
rm.type = "button";
rm.className = "rm";
rm.innerHTML = "×";
rm.setAttribute("aria-label", "Remove photo " + (i + 1));
rm.addEventListener("click", function () {
URL.revokeObjectURL(p.url);
photos.splice(i, 1);
renderPhotos();
});
t.appendChild(img);
t.appendChild(tag);
t.appendChild(rm);
thumbs.appendChild(t);
});
countEl.textContent = photos.length + " added";
}
function addFiles(list) {
var added = 0;
Array.prototype.forEach.call(list, function (f) {
if (!f.type || f.type.indexOf("image/") !== 0) return;
if (photos.length >= 6) return;
photos.push({ url: URL.createObjectURL(f), name: f.name });
added++;
});
if (added) { renderPhotos(); toast(added + " photo" + (added > 1 ? "s" : "") + " added"); }
}
drop.addEventListener("click", function () { fileInput.click(); });
drop.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); fileInput.click(); }
});
fileInput.addEventListener("change", function () { addFiles(fileInput.files); fileInput.value = ""; });
["dragenter", "dragover"].forEach(function (ev) {
drop.addEventListener(ev, function (e) { e.preventDefault(); drop.classList.add("drag"); });
});
["dragleave", "drop"].forEach(function (ev) {
drop.addEventListener(ev, function (e) { e.preventDefault(); drop.classList.remove("drag"); });
});
drop.addEventListener("drop", function (e) {
if (e.dataTransfer && e.dataTransfer.files) addFiles(e.dataTransfer.files);
});
/* ---------- NOTES CHAR COUNT ---------- */
var notes = document.getElementById("notes");
var charcount = document.getElementById("charcount");
notes.addEventListener("input", function () { charcount.textContent = notes.value.length; });
/* ---------- VALIDATION / GATING ---------- */
var weight = document.getElementById("weight");
var waist = document.getElementById("waist");
var hips = document.getElementById("hips");
var arm = document.getElementById("arm");
var thigh = document.getElementById("thigh");
var submitBtn = document.getElementById("submit");
var hint = document.getElementById("hint");
function hasMeasure() {
return [waist, hips, arm, thigh].some(function (el) { return el.value.trim() !== "" && +el.value > 0; });
}
function weightOk() { return weight.value.trim() !== "" && +weight.value > 0; }
function refreshGate() {
var ok = weightOk() && hasMeasure();
submitBtn.disabled = !ok;
if (ok) {
hint.textContent = "Ready — your coach is standing by.";
hint.classList.add("ok");
} else {
hint.textContent = "Add weight + at least one measurement to unlock.";
hint.classList.remove("ok");
}
}
[weight, waist, hips, arm, thigh].forEach(function (el) {
el.addEventListener("input", function () {
el.classList.remove("invalid");
var errEl = document.querySelector('[data-err="' + el.id + '"]');
if (errEl) errEl.textContent = "";
refreshGate();
});
});
refreshGate();
/* ---------- SUBMIT ---------- */
function verdictBadge(label, v) {
var vd = verdictFor(v);
return '<span class="verdict ' + vd.cls + '">' + label + " " + v + "/10 · " + vd.label + "</span>";
}
form.addEventListener("submit", function (e) {
e.preventDefault();
var bad = false;
if (!weightOk()) {
weight.classList.add("invalid");
document.querySelector('[data-err="weight"]').textContent = "Enter this week's bodyweight.";
bad = true;
}
if (!hasMeasure()) {
waist.classList.add("invalid");
document.querySelector('[data-err="waist"]').textContent = "Log at least one measurement.";
bad = true;
}
if (bad) {
toast("Fill the required fields first");
var firstBad = form.querySelector(".invalid");
if (firstBad) firstBad.focus();
return;
}
var e2 = +document.getElementById("energy").value;
var s2 = +document.getElementById("sleep").value;
var a2 = +document.getElementById("adherence").value;
var avg = ((e2 + s2 + a2) / 3);
function stat(k, v, unit) {
return '<div class="stat"><div class="k">' + k + '</div><div class="v">' + v +
(unit ? ' <small>' + unit + "</small>" : "") + "</div></div>";
}
var statsHtml =
stat("Weight", weight.value, "kg") +
(waist.value ? stat("Waist", waist.value, "cm") : "") +
(hips.value ? stat("Hips", hips.value, "cm") : "") +
(arm.value ? stat("Arm", arm.value, "cm") : "") +
(thigh.value ? stat("Thigh", thigh.value, "cm") : "") +
stat("Hunger", hunger, "");
var streakMsg;
if (avg >= 8) streakMsg = "Elite week. Locked in — keep this exact momentum rolling.";
else if (avg >= 5.5) streakMsg = "Solid week. Small tweaks and you'll break through the plateau.";
else streakMsg = "Tough week — that's the job. Coach Nadia will adjust your plan.";
var summary = document.getElementById("summary");
summary.innerHTML =
'<div class="sum-head">' +
'<div class="sum-check" aria-hidden="true">✓</div>' +
"<div><h2>Check-In Logged</h2><p>Week 07 · Cut Phase · sent to Nadia Reyes</p></div>" +
"</div>" +
'<div class="sum-stats">' + statsHtml + "</div>" +
'<div class="sum-verdicts">' +
verdictBadge("Energy", e2) + verdictBadge("Sleep", s2) + verdictBadge("Adherence", a2) +
"</div>" +
'<div class="streak"><span class="fire" aria-hidden="true">🔥</span><span>' +
photos.length + " progress photo" + (photos.length === 1 ? "" : "s") + " attached — " + streakMsg +
"</span></div>" +
(notes.value.trim() ? '<p class="sum-notes">“' + escapeHtml(notes.value.trim()) + "”</p>" : "");
summary.hidden = false;
toast("Check-in submitted 💪");
summary.scrollIntoView({ behavior: "smooth", block: "start" });
});
function escapeHtml(str) {
return str.replace(/[&<>"']/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Weekly Check-In — Apex Coaching</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Barlow+Condensed:wght@600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="glow"></div>
<main class="wrap">
<header class="masthead">
<div class="brand">
<span class="brand-mark" aria-hidden="true">▲</span>
<div>
<p class="kicker">Apex Coaching</p>
<h1>Weekly Check-In</h1>
</div>
</div>
<div class="week-pill">
<span class="dot" aria-hidden="true"></span>
Week 07 · Cut Phase
</div>
</header>
<p class="lede">
Log this week's numbers, rate how you felt, and drop your progress shots.
Your coach <strong>Nadia Reyes</strong> reviews every check-in within 24 hours.
</p>
<form id="checkin" class="grid" novalidate>
<!-- METRICS -->
<section class="card" aria-labelledby="metrics-h">
<div class="card-head">
<h2 id="metrics-h">Body Metrics</h2>
<span class="badge badge-line">Required</span>
</div>
<div class="field">
<label for="weight">Bodyweight <span class="req" aria-hidden="true">*</span></label>
<div class="input-suffix">
<input id="weight" name="weight" type="number" inputmode="decimal" step="0.1" min="0" placeholder="0.0" aria-required="true" />
<span class="suffix">kg</span>
</div>
<p class="err" data-err="weight" role="alert"></p>
</div>
<div class="measure-grid">
<div class="field">
<label for="waist">Waist <span class="req" aria-hidden="true">*</span></label>
<div class="input-suffix">
<input id="waist" name="waist" type="number" inputmode="decimal" step="0.1" min="0" placeholder="0.0" />
<span class="suffix">cm</span>
</div>
</div>
<div class="field">
<label for="hips">Hips</label>
<div class="input-suffix">
<input id="hips" name="hips" type="number" inputmode="decimal" step="0.1" min="0" placeholder="0.0" />
<span class="suffix">cm</span>
</div>
</div>
<div class="field">
<label for="arm">Arm</label>
<div class="input-suffix">
<input id="arm" name="arm" type="number" inputmode="decimal" step="0.1" min="0" placeholder="0.0" />
<span class="suffix">cm</span>
</div>
</div>
<div class="field">
<label for="thigh">Thigh</label>
<div class="input-suffix">
<input id="thigh" name="thigh" type="number" inputmode="decimal" step="0.1" min="0" placeholder="0.0" />
<span class="suffix">cm</span>
</div>
</div>
</div>
<p class="err" data-err="waist" role="alert"></p>
</section>
<!-- FEELINGS SLIDERS -->
<section class="card" aria-labelledby="feel-h">
<div class="card-head">
<h2 id="feel-h">How You Felt</h2>
<span class="badge badge-line">1–10</span>
</div>
<div class="slider-row" data-slider>
<div class="slider-top">
<label for="energy">Energy</label>
<span class="slider-out"><b data-out="energy">5</b><span class="verdict" data-verdict="energy"></span></span>
</div>
<input id="energy" name="energy" type="range" min="1" max="10" value="5" />
</div>
<div class="slider-row" data-slider>
<div class="slider-top">
<label for="sleep">Sleep quality</label>
<span class="slider-out"><b data-out="sleep">5</b><span class="verdict" data-verdict="sleep"></span></span>
</div>
<input id="sleep" name="sleep" type="range" min="1" max="10" value="5" />
</div>
<div class="slider-row" data-slider>
<div class="slider-top">
<label for="adherence">Plan adherence</label>
<span class="slider-out"><b data-out="adherence">5</b><span class="verdict" data-verdict="adherence"></span></span>
</div>
<input id="adherence" name="adherence" type="range" min="1" max="10" value="5" />
</div>
<div class="field mt">
<label for="hunger">Hunger this week</label>
<div class="chips" role="radiogroup" aria-label="Hunger this week" id="hunger">
<button type="button" class="chip" data-hunger="Low">Low</button>
<button type="button" class="chip is-on" data-hunger="Manageable" aria-pressed="true">Manageable</button>
<button type="button" class="chip" data-hunger="High">High</button>
<button type="button" class="chip" data-hunger="Brutal">Brutal</button>
</div>
</div>
</section>
<!-- PHOTOS -->
<section class="card" aria-labelledby="photo-h">
<div class="card-head">
<h2 id="photo-h">Progress Photos</h2>
<span class="badge" id="photo-count">0 added</span>
</div>
<div id="drop" class="dropzone" tabindex="0" role="button" aria-label="Upload progress photos">
<span class="drop-ico" aria-hidden="true">+</span>
<p class="drop-title">Drop photos or <span class="link">browse</span></p>
<p class="drop-sub">Front · Side · Back — JPG or PNG</p>
<input id="files" type="file" accept="image/*" multiple hidden />
</div>
<div id="thumbs" class="thumbs" aria-live="polite"></div>
</section>
<!-- NOTES -->
<section class="card" aria-labelledby="notes-h">
<div class="card-head">
<h2 id="notes-h">Notes to Coach</h2>
<span class="badge badge-line"><span id="charcount">0</span>/400</span>
</div>
<textarea id="notes" name="notes" maxlength="400" rows="4"
placeholder="Wins, struggles, cravings, training PRs, questions…"></textarea>
</section>
<!-- SUBMIT BAR -->
<div class="submitbar">
<p class="submit-hint" id="hint">Add weight + at least one measurement to unlock.</p>
<button id="submit" class="cta" type="submit" disabled>Submit Check-In</button>
</div>
</form>
<!-- SUMMARY -->
<section id="summary" class="summary" hidden aria-live="polite"></section>
</main>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>A bold, dark-mode weekly check-in built for online coaching clients. The layout pairs a metrics column — bodyweight, waist, hips and arm measurements — with a set of electric-lime range sliders for energy, sleep quality and plan adherence. Each slider updates a live numeric readout and a coloured badge, so a client instantly sees whether they landed in the red, amber or lime zone for the week.
Progress photos drop into a dashed upload zone that accepts clicks or drag-and-drop, rendering thumbnail previews with removable chips and a running count. A notes textarea captures wins and struggles with a live character meter. Everything is validated inline: the sticky submit bar stays disabled until weight and at least one measurement are filled, and invalid fields flash an accessible error state.
On submit the form assembles a summary card — key stats, slider verdicts, photo count and a motivational streak line — then fires a toast and scrolls the recap into view. The whole thing is vanilla JS with keyboard-usable controls, visible focus rings and a responsive single-column collapse under 520px.