Complete Study Closeout

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Complete Study Closeout</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #f5f6f7; color: #1a1a1a; line-height: 1.6; padding: 24px 16px 48px; } .wrap { max-width: 720px; margin: 0 auto; } /* ── Header ── */ .page-header { background: #ffffff; border-radius: 10px; padding: 28px 32px 24px; margin-bottom: 20px; border-top: 4px solid #087a6a; } .header-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: #087a6a; margin-bottom: 8px; } .page-header h1 { font-size: 24px; font-weight: 700; color: #111; margin-bottom: 6px; } .header-sub { font-size: 13px; color: #555; margin-bottom: 16px; } .header-note { background: #f0faf8; border-left: 3px solid #087a6a; border-radius: 0 6px 6px 0; padding: 10px 14px; font-size: 13px; color: #333; line-height: 1.6; } .header-note strong { color: #111; font-weight: 600; } /* ── Progress bar ── */ .progress-wrap { background: #fff; border-radius: 10px; padding: 16px 24px; margin-bottom: 20px; display: flex; align-items: center; gap: 16px; } .progress-label { font-size: 13px; font-weight: 600; color: #333; white-space: nowrap; flex-shrink: 0; } .progress-track { flex: 1; height: 8px; background: #d0d0d0; border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; background: #087a6a; border-radius: 4px; transition: width 0.35s ease; width: 0%; } .progress-count { font-size: 13px; font-weight: 700; color: #087a6a; white-space: nowrap; flex-shrink: 0; min-width: 48px; text-align: right; } /* ── Section card ── */ .section-card { background: #fff; border-radius: 10px; margin-bottom: 14px; overflow: hidden; border: 1px solid #e4e4e4; transition: border-color 0.2s; } .section-card.all-done { border-color: #087a6a; } /* Section header is a <button> for full keyboard + screen-reader support */ .section-header { display: flex; align-items: center; gap: 12px; padding: 14px 20px; cursor: pointer; width: 100%; background: transparent; border: none; border-bottom: 1px solid #f0f0f0; text-align: left; transition: background 0.15s; font-family: inherit; } .section-header:hover { background: #f9f9f9; } .section-header:focus-visible { outline: 3px solid #087a6a; outline-offset: -3px; border-radius: 9px 9px 0 0; } .section-card.all-done .section-header { background: #f0faf8; border-bottom-color: #cceee8; } .section-num { width: 28px; height: 28px; border-radius: 50%; background: #087a6a; color: #fff; font-size: 12px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: background 0.2s; /* Hidden from AT — the button label provides context */ aria-hidden: true; } .section-card.all-done .section-num { background: #065a4f; } .section-title-wrap { flex: 1; } .section-title { font-size: 14px; font-weight: 700; color: #111; line-height: 1.3; } .section-subtitle { font-size: 12px; color: #666; margin-top: 1px; } .section-badge { font-size: 11px; font-weight: 600; padding: 3px 10px; border-radius: 20px; background: #e8e8e8; color: #444; flex-shrink: 0; transition: all 0.2s; } .section-card.all-done .section-badge { background: #d0ede8; color: #065a4f; } .section-chevron { font-size: 12px; color: #666; flex-shrink: 0; transition: transform 0.2s; /* Decorative — aria-expanded on the button conveys state */ } .section-card.collapsed .section-chevron { transform: rotate(-90deg); } /* ── Section body ── */ .section-body { padding: 4px 0 8px; } .section-card.collapsed .section-body { display: none; } /* ── Checklist items ── */ /* Each item is a <div role="checkbox"> with tabindex for keyboard nav */ .check-item { display: flex; align-items: flex-start; gap: 12px; padding: 10px 20px; cursor: pointer; transition: background 0.12s; border-radius: 6px; margin: 0 8px; } .check-item:hover { background: #f5fdf9; } .check-item:focus-visible { outline: 3px solid #087a6a; outline-offset: 1px; } .check-item.checked { opacity: 0.75; } .check-box { width: 18px; height: 18px; border: 2px solid #767676; border-radius: 4px; flex-shrink: 0; margin-top: 2px; display: flex; align-items: center; justify-content: center; transition: all 0.15s; background: #fff; } .check-item.checked .check-box { background: #087a6a; border-color: #087a6a; } .check-tick { display: none; color: #fff; font-size: 11px; font-weight: 700; line-height: 1; } .check-item.checked .check-tick { display: block; } .check-text { font-size: 13px; color: #222; line-height: 1.6; flex: 1; } .check-item.checked .check-text { text-decoration: line-through; color: #767676; } .check-text strong { font-weight: 600; color: #111; } .check-item.checked .check-text strong { color: #767676; } /* Sub-items (indented) */ .sub-items { margin: 0 8px 2px 52px; } .sub-item { display: flex; align-items: flex-start; gap: 10px; padding: 6px 12px 6px 0; cursor: pointer; border-radius: 6px; transition: background 0.12s; } .sub-item:hover { background: #f5fdf9; } .sub-item:focus-visible { outline: 3px solid #087a6a; outline-offset: 1px; } .sub-item.checked { opacity: 0.75; } .sub-box { width: 16px; height: 16px; border: 2px solid #767676; border-radius: 3px; flex-shrink: 0; margin-top: 3px; display: flex; align-items: center; justify-content: center; transition: all 0.15s; background: #fff; } .sub-item.checked .sub-box { background: #087a6a; border-color: #087a6a; } .sub-tick { display: none; color: #fff; font-size: 9px; font-weight: 700; } .sub-item.checked .sub-tick { display: block; } .sub-text { font-size: 13px; color: #222; line-height: 1.5; flex: 1; } .sub-item.checked .sub-text { text-decoration: line-through; color: #767676; } /* ── Completion banner ── */ .completion-banner { display: none; background: #065a4f; border-radius: 10px; padding: 20px 24px; margin-bottom: 20px; text-align: center; color: #fff; } .completion-banner.show { display: block; } .completion-banner h2 { font-size: 18px; font-weight: 700; margin-bottom: 6px; } .completion-banner p { font-size: 13px; color: rgba(255,255,255,0.9); margin-bottom: 14px; } .reset-btn { display: inline-block; padding: 8px 20px; border: 2px solid rgba(255,255,255,0.8); border-radius: 6px; color: #fff; font-size: 13px; font-weight: 600; cursor: pointer; background: transparent; transition: background 0.15s; font-family: inherit; } .reset-btn:hover { background: rgba(255,255,255,0.2); } .reset-btn:focus-visible { outline: 3px solid #fff; outline-offset: 2px; } /* Reduced motion */ @media (prefers-reduced-motion: reduce) { .progress-fill, .section-chevron, .check-box, .sub-box { transition: none; } } </style> </head> <body> <div class="wrap"> <!-- Header --> <div class="page-header"> <p class="header-eyebrow" aria-hidden="true">Certified Workflow &middot; Verily Viewpoint Site CTMS</p> <h1>Complete Study Closeout</h1> <p class="header-sub">TrialPath &nbsp;&middot;&nbsp; Finance &nbsp;&middot;&nbsp; Enterprise &nbsp;&middot;&nbsp; Insights</p> <div class="header-note" role="note"> <strong>Note:</strong> Sites may have varying internal processes for study closeout. Use this workflow to develop SOPs, support training, and define CTMS-related closeout activities. Check off each step in order to track your progress. </div> </div> <!-- Progress --> <div class="progress-wrap"> <p class="progress-label" id="progress-label">Overall progress</p> <div class="progress-track" role="progressbar" aria-labelledby="progress-label" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" id="progress-bar"> <div class="progress-fill" id="progress-fill"></div> </div> <p class="progress-count" id="progress-count" aria-live="polite" aria-atomic="true">0 / 0</p> </div> <!-- Completion banner --> <div class="completion-banner" id="completion-banner" role="status" aria-live="polite"> <h2>&#10003; Study closeout complete</h2> <p>All steps have been checked off. Make sure study documentation is archived and stakeholders have been notified.</p> <button class="reset-btn" onclick="resetAll()">Reset checklist</button> </div> <!-- ── Section 1: TrialPath — Participants & visits ── --> <div class="section-card" id="sec-1"> <button class="section-header" onclick="toggleSection('sec-1')" aria-expanded="true" aria-controls="body-sec-1" id="hdr-sec-1"> <span class="section-num" aria-hidden="true">1</span> <span class="section-title-wrap"> <span class="section-title">TrialPath &mdash; Participants &amp; visits</span> <span class="section-subtitle">Confirm participant data is finalized before proceeding to Finance</span> </span> <span class="section-badge" id="badge-sec-1" aria-hidden="true">0 / 6</span> <span class="section-chevron" aria-hidden="true">&#9660;</span> </button> <div class="section-body" id="body-sec-1" role="group" aria-labelledby="hdr-sec-1"> <div class="check-item" id="c-1-1" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-1-1')" onkeydown="handleKey(event,'c-1-1')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Confirm each participant is on the correct protocol version.</strong> If needed, migrate participants to the correct version. For more, see the <strong>Migrate Study Participants</strong> guide.</span> </div> <div class="check-item" id="c-1-2" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-1-2')" onkeydown="handleKey(event,'c-1-2')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Confirm all participants are linked to the correct consent version.</strong> If needed, update or add final consent versions. For more, see the <strong>Consent and Reconsent Study Participants</strong> guide.</span> </div> <div class="check-item" id="c-1-3" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-1-3')" onkeydown="handleKey(event,'c-1-3')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Complete all outstanding participant visits and activities</strong> to avoid leaving outstanding charges. For more, see the <strong>Complete Visits</strong> guide and the <strong>Complete Study Activities</strong> guide.</span> </div> <div class="check-item" id="c-1-4" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-1-4')" onkeydown="handleKey(event,'c-1-4')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Confirm all participant statuses have been updated</strong> to one of the following:</span> </div> <div class="sub-items" role="group" aria-label="Participant status options"> <div class="sub-item" id="c-1-5" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-1-5')" onkeydown="handleKey(event,'c-1-5')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text"><strong>Completed</strong> &mdash; Participant fully completed study.</span> </div> <div class="sub-item" id="c-1-6" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-1-6')" onkeydown="handleKey(event,'c-1-6')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text"><strong>Off Study</strong> &mdash; Participant dropped out, withdrew, etc. prior to study closeout.</span> </div> </div> </div> </div> <!-- ── Section 2: Finance ── --> <div class="section-card" id="sec-2"> <button class="section-header" onclick="toggleSection('sec-2')" aria-expanded="true" aria-controls="body-sec-2" id="hdr-sec-2"> <span class="section-num" aria-hidden="true">2</span> <span class="section-title-wrap"> <span class="section-title">Finance &mdash; Revenue, expenses, &amp; payments</span> <span class="section-subtitle">Requires Section 1 to be finalized first</span> </span> <span class="section-badge" id="badge-sec-2" aria-hidden="true">0 / 5</span> <span class="section-chevron" aria-hidden="true">&#9660;</span> </button> <div class="section-body" id="body-sec-2" role="group" aria-labelledby="hdr-sec-2"> <div class="check-item" id="c-2-1" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-2-1')" onkeydown="handleKey(event,'c-2-1')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Confirm all TrialPath participant data has been finalized</strong> (Section 1 above) to avoid leaving outstanding charges.</span> </div> <div class="check-item" id="c-2-2" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-2-2')" onkeydown="handleKey(event,'c-2-2')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Confirm all study-related activities are accounted for</strong> and all relevant dates have been entered. For more, see the <strong>Add Invoiceable Study Activities</strong> guide.</span> </div> <div class="check-item" id="c-2-3" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-2-3')" onkeydown="handleKey(event,'c-2-3')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Reconcile any pending accountables in Accounts Receivable (AR) and Accounts Payable (AP).</strong> For more, see the <strong>Manage Accounts Receivable</strong> guide and the <strong>Manage Accounts Payable</strong> guide.</span> </div> <div class="check-item" id="c-2-4" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-2-4')" onkeydown="handleKey(event,'c-2-4')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Reconcile and log all payments,</strong> applying them to invoices and/or accountables. Verify all payments have been correctly allocated &mdash; there should be no outstanding AR and AP items remaining. For more, see the <strong>Record Payments</strong> guide.</span> </div> <div class="check-item" id="c-2-5" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-2-5')" onkeydown="handleKey(event,'c-2-5')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Confirm budget end dates have been updated accordingly.</strong> If additional study-level charges or administrative fees are anticipated, budget end dates may be left blank for now &mdash; return later to enter a budget end date once all charges and/or fees are settled.</span> </div> </div> </div> <!-- ── Section 3: TrialPath — Site study closeout ── --> <div class="section-card" id="sec-3"> <button class="section-header" onclick="toggleSection('sec-3')" aria-expanded="true" aria-controls="body-sec-3" id="hdr-sec-3"> <span class="section-num" aria-hidden="true">3</span> <span class="section-title-wrap"> <span class="section-title">TrialPath &mdash; Site study closeout</span> <span class="section-subtitle">Update study details and team end dates at the site level</span> </span> <span class="section-badge" id="badge-sec-3" aria-hidden="true">0 / 4</span> <span class="section-chevron" aria-hidden="true">&#9660;</span> </button> <div class="section-body" id="body-sec-3" role="group" aria-labelledby="hdr-sec-3"> <div class="check-item" id="c-3-0" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-3-0')" onkeydown="handleKey(event,'c-3-0')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text">On the <strong>Study Details tab,</strong> complete the following. For more, see the <strong>Edit Site Study Details</strong> guide.</span> </div> <div class="sub-items" role="group" aria-label="Study Details tab steps"> <div class="sub-item" id="c-3-1" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-3-1')" onkeydown="handleKey(event,'c-3-1')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text"><strong>Update the site study status to Completed or Finished,</strong> as applicable. Site study status updates only apply to the site level.</span> </div> <div class="sub-item" id="c-3-2" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-3-2')" onkeydown="handleKey(event,'c-3-2')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text"><strong>Enter the Site Study End Date.</strong></span> </div> <div class="sub-item" id="c-3-3" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-3-3')" onkeydown="handleKey(event,'c-3-3')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text"><strong>Enter the Site Enrollment End Date.</strong></span> </div> </div> <div class="check-item" id="c-3-4" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-3-4')" onkeydown="handleKey(event,'c-3-4')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text">On the <strong>Site Team tab, add an End Date</strong> for each person assigned to the study.</span> </div> </div> </div> <!-- ── Section 4: Enterprise ── --> <div class="section-card" id="sec-4"> <button class="section-header" onclick="toggleSection('sec-4')" aria-expanded="true" aria-controls="body-sec-4" id="hdr-sec-4"> <span class="section-num" aria-hidden="true">4</span> <span class="section-title-wrap"> <span class="section-title">Enterprise &mdash; Network study closeout</span> <span class="section-subtitle">Only required if the study is closing across the entire network</span> </span> <span class="section-badge" id="badge-sec-4" aria-hidden="true">0 / 2</span> <span class="section-chevron" aria-hidden="true">&#9660;</span> </button> <div class="section-body" id="body-sec-4" role="group" aria-labelledby="hdr-sec-4"> <div class="check-item" id="c-4-1" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-4-1')" onkeydown="handleKey(event,'c-4-1')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Update the Network Study Status and Network Study Status Date</strong> in the Study Information tab. Updating the Enterprise status ensures the closure is visible in network-level reporting and portfolio data in Insights. For more, see the <strong>Add and Manage Network Studies</strong> guide.</span> </div> <div class="check-item" id="c-4-2" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-4-2')" onkeydown="handleKey(event,'c-4-2')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Update the Network Enrollment End Date.</strong></span> </div> </div> </div> <!-- ── Section 5: Insights ── --> <div class="section-card" id="sec-5"> <button class="section-header" onclick="toggleSection('sec-5')" aria-expanded="true" aria-controls="body-sec-5" id="hdr-sec-5"> <span class="section-num" aria-hidden="true">5</span> <span class="section-title-wrap"> <span class="section-title">Insights &mdash; Reporting &amp; validation</span> <span class="section-subtitle">Validate Finance reports and export per your site's SOP</span> </span> <span class="section-badge" id="badge-sec-5" aria-hidden="true">0 / 5</span> <span class="section-chevron" aria-hidden="true">&#9660;</span> </button> <div class="section-body" id="body-sec-5" role="group" aria-labelledby="hdr-sec-5"> <div class="check-item" id="c-5-0" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-5-0')" onkeydown="handleKey(event,'c-5-0')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Validate Finance reports</strong> to confirm the following. For more, see the <strong>Report Dictionary</strong> guide.</span> </div> <div class="sub-items" role="group" aria-label="Finance report validation items"> <div class="sub-item" id="c-5-1" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-5-1')" onkeydown="handleKey(event,'c-5-1')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text">Applicable revenue and payments are accurate.</span> </div> <div class="sub-item" id="c-5-2" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-5-2')" onkeydown="handleKey(event,'c-5-2')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text">No outstanding AR.</span> </div> <div class="sub-item" id="c-5-3" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-5-3')" onkeydown="handleKey(event,'c-5-3')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text">All payments have been fully logged and allocated correctly.</span> </div> <div class="sub-item" id="c-5-4" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-5-4')" onkeydown="handleKey(event,'c-5-4')"> <span class="sub-box" aria-hidden="true"><span class="sub-tick">&#10003;</span></span> <span class="sub-text">Budget end dates align with reconciled Finance, or update per SOP if left open for closeout fees.</span> </div> </div> <div class="check-item" id="c-5-5" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-5-5')" onkeydown="handleKey(event,'c-5-5')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Export required reports</strong> per your site's internal SOP.</span> </div> </div> </div> <!-- ── Section 6: Archive & communicate ── --> <div class="section-card" id="sec-6"> <button class="section-header" onclick="toggleSection('sec-6')" aria-expanded="true" aria-controls="body-sec-6" id="hdr-sec-6"> <span class="section-num" aria-hidden="true">6</span> <span class="section-title-wrap"> <span class="section-title">Archive and communicate closeout</span> <span class="section-subtitle">Final step &mdash; once all above sections are complete</span> </span> <span class="section-badge" id="badge-sec-6" aria-hidden="true">0 / 2</span> <span class="section-chevron" aria-hidden="true">&#9660;</span> </button> <div class="section-body" id="body-sec-6" role="group" aria-labelledby="hdr-sec-6"> <div class="check-item" id="c-6-1" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-6-1')" onkeydown="handleKey(event,'c-6-1')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Archive study documents</strong> by ensuring all documents are stored in accordance with site and sponsor policies.</span> </div> <div class="check-item" id="c-6-2" role="checkbox" aria-checked="false" tabindex="0" onclick="toggle('c-6-2')" onkeydown="handleKey(event,'c-6-2')"> <span class="check-box" aria-hidden="true"><span class="check-tick">&#10003;</span></span> <span class="check-text"><strong>Notify stakeholders</strong> by communicating study closure to relevant site, sponsor, and Site CTMS stakeholders.</span> </div> </div> </div> </div> <script> /* ── Section map: which item IDs belong to each section ── */ const SECTIONS = { 'sec-1': ['c-1-1','c-1-2','c-1-3','c-1-4','c-1-5','c-1-6'], 'sec-2': ['c-2-1','c-2-2','c-2-3','c-2-4','c-2-5'], 'sec-3': ['c-3-0','c-3-1','c-3-2','c-3-3','c-3-4'], 'sec-4': ['c-4-1','c-4-2'], 'sec-5': ['c-5-0','c-5-1','c-5-2','c-5-3','c-5-4','c-5-5'], 'sec-6': ['c-6-1','c-6-2'] }; const ALL_IDS = Object.values(SECTIONS).flat(); const TOTAL = ALL_IDS.length; /* Toggle a checkbox item */ function toggle(id) { const el = document.getElementById(id); const isChecked = el.classList.toggle('checked'); el.setAttribute('aria-checked', isChecked ? 'true' : 'false'); updateProgress(); } /* Keyboard support: Space/Enter activate the checkbox */ function handleKey(event, id) { if (event.key === ' ' || event.key === 'Enter') { event.preventDefault(); toggle(id); } } /* Toggle section expand/collapse */ function toggleSection(secId) { const card = document.getElementById(secId); const btn = card.querySelector('.section-header'); const body = card.querySelector('.section-body'); const isOpen = !card.classList.contains('collapsed'); card.classList.toggle('collapsed', isOpen); btn.setAttribute('aria-expanded', isOpen ? 'false' : 'true'); body.hidden = isOpen; } function countChecked(ids) { return ids.filter(id => document.getElementById(id).classList.contains('checked')).length; } function updateProgress() { const done = countChecked(ALL_IDS); const pct = TOTAL > 0 ? Math.round((done / TOTAL) * 100) : 0; /* Overall bar */ document.getElementById('progress-fill').style.width = pct + '%'; document.getElementById('progress-count').textContent = done + ' / ' + TOTAL; /* Update progressbar ARIA attributes */ const bar = document.getElementById('progress-bar'); bar.setAttribute('aria-valuenow', pct); bar.setAttribute('aria-valuetext', done + ' of ' + TOTAL + ' steps completed'); /* Per-section badges and done state */ Object.entries(SECTIONS).forEach(([secId, ids]) => { const secDone = countChecked(ids); const secTotal = ids.length; const badge = document.getElementById('badge-' + secId); const card = document.getElementById(secId); badge.textContent = secDone + ' / ' + secTotal; if (secDone === secTotal) { card.classList.add('all-done'); } else { card.classList.remove('all-done'); } }); /* Completion banner */ const banner = document.getElementById('completion-banner'); if (done === TOTAL) { banner.classList.add('show'); banner.removeAttribute('hidden'); } else { banner.classList.remove('show'); } } function resetAll() { ALL_IDS.forEach(id => { const el = document.getElementById(id); el.classList.remove('checked'); el.setAttribute('aria-checked', 'false'); }); updateProgress(); } /* Initialise counts */ updateProgress(); </script> </body> </html>