You're working on an offline APEX portfolio system — standalone HTML/CSS/JS files that use localStorage for persistence. You have 4 concrete tasks to complete. All files are in `/Users/russgoerend/Desktop/Portfolio HTMLs/`.

---

## TASK 1 — Add nav dropdowns to Review Prep and Task Boards

Both pages were missed in a previous nav update. Every other page already has this structure: `Dashboard | Portfolio ▾ | Playbooks ▾` using CSS hover dropdowns and a JS hover timer.

**CSS to add** (after `.nav-links a.active` rule, or `.nav-links a:hover` if no `.active` rule exists):
```css
        /* --- NAV DROPDOWNS --- */
        .nav-dropdown { position: relative; }
        .nav-drop-btn { color: rgba(255,255,255,0.9); background: none; border: none; font-size: 0.8rem; font-weight: 700; padding: 8px 14px; border-radius: 6px; text-transform: uppercase; letter-spacing: 0.03em; transition: all 0.2s; cursor: pointer; font-family: inherit; }
        .nav-dropdown:hover .nav-drop-btn { color: var(--secondary); background: rgba(255,255,255,0.1); }
        .nav-drop-btn.active { background: var(--secondary); color: var(--primary); }
        .nav-dropdown:hover .nav-drop-btn.active { background: var(--secondary); color: var(--primary); opacity: 0.85; }
        .nav-drop-menu { display: none; position: absolute; top: calc(100% + 8px); left: 0; background: white; border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); min-width: 210px; z-index: 1001; padding: 6px 0; border: 1px solid #E5E7EB; }
        .nav-dropdown:hover .nav-drop-menu { display: block; }
        .nav-drop-menu a { display: block; padding: 9px 16px; color: #1F2937; text-decoration: none; font-size: 0.82rem; font-weight: 600; transition: background 0.15s; white-space: nowrap; }
        .nav-drop-menu a:hover { background: #F3F4F6; color: var(--primary); }
        .nav-drop-menu a.active { color: var(--primary); font-weight: 800; background: #F5F3FF; }
```

**JS to add** (before `</body>`):
```html
<script>
document.querySelectorAll('.nav-dropdown').forEach(d => {
    let t, m = d.querySelector('.nav-drop-menu');
    d.addEventListener('mouseenter', () => { clearTimeout(t); m.style.display = 'block'; });
    d.addEventListener('mouseleave', () => { t = setTimeout(() => { m.style.display = ''; }, 150); });
});
</script>
```

**`APEX_Review_Prep.html`** — current nav-links HTML is:
```html
        <div class="nav-links">
            <a href="APEX_Professional_Dashboard.html">Dashboard</a>
            <button class="btn-copy" onclick="copyToClipboard()">📋 Copy Text</button>
            <button class="btn-print" onclick="window.print()">🖨 Print / PDF</button>
        </div>
```
The `.nav-links a:hover` rule exists on this page (no `.active` rule). Replace nav-links with:
```html
        <div class="nav-links">
            <a href="APEX_Professional_Dashboard.html">Dashboard</a>
            <div class="nav-dropdown">
                <button class="nav-drop-btn">Portfolio ▾</button>
                <div class="nav-drop-menu">
                    <a href="Standard1.html">S1 · Servant Leadership</a>
                    <a href="Standard2.html">S2</a>
                    <a href="Standard3.html">S3 · Career Exploration</a>
                    <a href="Standard4.html">S4 · Technical Skills</a>
                    <a href="Standard5.html">S5 · Professional Skills</a>
                </div>
            </div>
            <div class="nav-dropdown">
                <button class="nav-drop-btn">Playbooks ▾</button>
                <div class="nav-drop-menu">
                    <a href="Video Production Playbook.html">Video Production</a>
                    <a href="Social Media Playbook.html">Social Media</a>
                    <a href="Marketing Analytics Playbook.html">Marketing Analytics</a>
                    <a href="Podcast Production Playbook.html">Podcast Production</a>
                    <a href="Graphic Design Playbook.html">Graphic Design</a>
                    <a href="Photography Playbook.html">Photography</a>
                </div>
            </div>
            <button class="btn-copy" onclick="copyToClipboard()">📋 Copy Text</button>
            <button class="btn-print" onclick="window.print()">🖨 Print / PDF</button>
        </div>
```

**`Project Task Boards.html`** — current nav-links HTML is:
```html
        <div class="nav-links">
            <a href="APEX_Professional_Dashboard.html">Dashboard</a>
            <a href="APEX_Professional_Portfolio.html">Portfolio</a>
            <a href="Video Production Playbook.html">Video Playbook</a>
            <a href="Social Media Playbook.html">Social Media</a>
            <a href="Marketing Analytics Playbook.html">Analytics</a>
            <a href="Project Task Boards.html" class="active">Task Boards</a>
        </div>
```
Has `.nav-links a.active` rule. Replace nav-links with:
```html
        <div class="nav-links">
            <a href="APEX_Professional_Dashboard.html">Dashboard</a>
            <div class="nav-dropdown">
                <button class="nav-drop-btn">Portfolio ▾</button>
                <div class="nav-drop-menu">
                    <a href="Standard1.html">S1 · Servant Leadership</a>
                    <a href="Standard2.html">S2</a>
                    <a href="Standard3.html">S3 · Career Exploration</a>
                    <a href="Standard4.html">S4 · Technical Skills</a>
                    <a href="Standard5.html">S5 · Professional Skills</a>
                </div>
            </div>
            <div class="nav-dropdown">
                <button class="nav-drop-btn">Playbooks ▾</button>
                <div class="nav-drop-menu">
                    <a href="Video Production Playbook.html">Video Production</a>
                    <a href="Social Media Playbook.html">Social Media</a>
                    <a href="Marketing Analytics Playbook.html">Marketing Analytics</a>
                    <a href="Podcast Production Playbook.html">Podcast Production</a>
                    <a href="Graphic Design Playbook.html">Graphic Design</a>
                    <a href="Photography Playbook.html">Photography</a>
                </div>
            </div>
            <a href="Project Task Boards.html" class="active">Task Boards</a>
        </div>
```

---

## TASK 2 — Fix S4BSU localStorage pattern

`Standard4BSU.html` currently saves card state as individual localStorage keys (`bmc-sprint_done`, `bmc-sprint_reflection`, etc.), which is fragile. Change it to save a single unified JSON blob like S1 and S5 do.

Read the full `Standard4BSU.html` file first so you know the exact current code. Then make these changes:

**A.** Add `const S4BSU_KEY = 'apex_std4bsu_v1';` before `function saveLink`.

**B.** Replace `function saveLink(id, value) { localStorage.setItem(id, value); }` with:
```javascript
function saveLink(id, value) { saveS4BSUState(); }
```

**C.** Replace the entire `saveStd4State()` function with `saveS4BSUState()`:
```javascript
function saveS4BSUState() {
    const cards = {};
    document.querySelectorAll('.sprint-card').forEach(card => {
        if (!card.id) return;
        const linkInput = card.querySelector('input[type="text"]');
        const reflTA = card.querySelector('.reflection-textarea');
        const h4 = card.querySelector('h4');
        const title = h4 ? [...h4.childNodes]
            .filter(n => n.nodeType === Node.TEXT_NODE)
            .map(n => n.textContent).join('').trim() : '';
        cards[card.id] = {
            done: card.dataset.done === 'true',
            link: linkInput ? linkInput.value.trim() : '',
            reflection: reflTA ? reflTA.value.trim() : '',
            title
        };
    });
    localStorage.setItem(S4BSU_KEY, JSON.stringify(cards));
    // Keep Review Prep summary format
    const allCards = Object.entries(cards).map(([id, d]) => ({
        id, title: d.title, reflection: d.reflection, done: d.done
    }));
    localStorage.setItem('apex_std4_state_v6', JSON.stringify({ sprints: allCards }));
}
```

**D.** Replace `function saveReflection(cardId, value) { localStorage.setItem(cardId + '_reflection', value); }` with:
```javascript
function saveReflection(cardId, value) { saveS4BSUState(); }
```

**E.** In `markDone`, remove the `localStorage.setItem(cardId + '_done', ...)` line and replace the `saveStd4State()` call with `saveS4BSUState()`.

**F.** In `window.onload`, there's a block that restores link inputs by reading individual keys:
```javascript
    // Restore saved link inputs
    document.querySelectorAll('input[type="text"]').forEach(input => {
        const attr = input.getAttribute('onchange');
        if (attr) {
            const match = attr.match(/'([^']+)'/);
            if (match) {
                const saved = localStorage.getItem(match[1]);
                if (saved) input.value = saved;
            }
        }
    });
```
Replace this entire block with a unified state load:
```javascript
    // Load unified card state (with migration from individual keys)
    let s4State = {};
    const s4Raw = localStorage.getItem(S4BSU_KEY);
    if (s4Raw) {
        try { s4State = JSON.parse(s4Raw); } catch(e) {}
    }
```

**G.** In the card transform loop inside `window.onload`, find:
```javascript
            // Restore done state
            const isDone = localStorage.getItem(cardId + '_done') === 'true';
            card.dataset.done = isDone ? 'true' : 'false';

            // Restore reflection
            const savedReflection = localStorage.getItem(cardId + '_reflection') || '';
```
Replace with:
```javascript
            // Restore state (unified key with fallback to legacy individual keys)
            const cs = s4State[cardId];
            const isDone = cs ? cs.done : localStorage.getItem(cardId + '_done') === 'true';
            const savedLink = cs ? cs.link : (localStorage.getItem(cardId) || '');
            const savedReflection = cs ? cs.reflection : (localStorage.getItem(cardId + '_reflection') || '');
            card.dataset.done = isDone ? 'true' : 'false';
```

**H.** In the same card transform loop, find where `linkInput` is created:
```javascript
        const linkInput = document.createElement('input');
        linkInput.type = 'text';
        linkInput.placeholder = 'Paste presentation link here...';
        linkInput.onchange = () => saveLink(newId, linkInput.value);
```
Add `if (savedLink) linkInput.value = savedLink;` right after the `linkInput.onchange` line.

**I.** Near the end of `window.onload`, before `loadQueue()`, add:
```javascript
        // Commit unified state (migrates any legacy individual-key data)
        saveS4BSUState();
```

---

## TASK 3 — Fix portfolio progress display

`APEX_Professional_Portfolio.html` has a `loadProfile` function with this buggy progress code:
```javascript
        for (let i = 1; i <= 5; i++) {
            const stdData = localStorage.getItem(`apex_std${i}_state_v6`);
            if (stdData) {
                const badge = document.getElementById(`status-${i}`);
                if (badge) {
                    badge.innerText = 'Evidence Logged';
                    badge.classList.add('complete');
                }
            }
        }
```

Bugs:
- S3 uses key `apex_v37` not `apex_std3_state_v6` → badge never updates
- S5 uses key `apex_std5_v6` not `apex_std5_state_v6` → badge never updates
- Shows only binary "Evidence Logged" — no count

Replace with this improved version that shows actual counts ("X / Y done") and handles each standard's correct key and data format:

```javascript
        const STD_SOURCES = {
            1: { key: 'apex_std1_state_v6', fmt: 'kanban' },
            3: { key: 'apex_v37',           fmt: 'phase'  },
            4: { key: 'apex_std4bsu_v1',    fmt: 'bsu',   fallback: 'apex_std4_state_v6' },
            5: { key: 'apex_std5_v6',        fmt: 'kanban' }
        };
        [1, 3, 4, 5].forEach(i => {
            const badge = document.getElementById(`status-${i}`);
            if (!badge) return;
            try {
                const src = STD_SOURCES[i];
                let raw = localStorage.getItem(src.key);
                if (!raw && src.fallback) raw = localStorage.getItem(src.fallback);
                if (!raw) return;
                const state = JSON.parse(raw);
                let total = 0, done = 0, unit = 'done';
                if (src.fmt === 'kanban') {
                    Object.values(state).forEach(col => {
                        if (!Array.isArray(col)) return;
                        total += col.length;
                        done += col.filter(c => c.done === true || c.done === 'true').length;
                    });
                } else if (src.fmt === 'phase') {
                    total = 4; done = (state.visited || []).length; unit = 'phases';
                } else if (src.fmt === 'bsu') {
                    const cards = Object.values(state);
                    if (cards[0] && cards[0].sprints) {
                        // old summary format
                        total = cards[0].sprints.length;
                        done = cards[0].sprints.filter(c => c.done).length;
                    } else {
                        total = cards.length;
                        done = cards.filter(c => c.done).length;
                    }
                }
                if (total > 0) {
                    badge.innerText = `${done} / ${total} ${unit}`;
                    badge.classList.add('complete');
                }
            } catch(e) {}
        });
```

Also, the Portfolio page currently has two duplicate dropdown scripts at the bottom — remove the older/duplicate one (keep the one that also adds listeners on the menu element for extra reliability).

---

## TASK 4 — Fix Review Prep S5 key bug

In `APEX_Review_Prep.html`, the `STANDARDS` array has this for S5:
```javascript
        { num: 5, label: 'S5', name: 'Professional Skills', cls: 's5', key: 'apex_std5_state_v6' }
```
The actual S5 localStorage key is `apex_std5_v6` (no "state" in the middle). Change the key.

---

## TASK 5 — Create shared kanban file + DRY up S1 and S5

S1 (`Standard1.html`) and S5 (`Standard5.html`) have ~90% identical JS. Extract the shared logic into a new file `apex-kanban.js`, then simplify both pages to just define their config and call `initKanban(config)`.

**Create `/Users/russgoerend/Desktop/Portfolio HTMLs/apex-kanban.js`** with this content:

```javascript
// apex-kanban.js — Shared kanban logic for APEX Portfolio standards
// Used by: Standard1.html, Standard5.html

function initKanban(config) {
    const { cols, storageKey, sidebarKey, pageUrl, defaultCards } = config;
    let activeFilter = 'all';

    function saveToStorage(btn) {
        if (btn && btn.classList.contains('save-btn')) {
            btn.innerText = '✓ Saved';
            btn.classList.add('saved');
            setTimeout(() => { btn.innerText = 'Done'; btn.classList.remove('saved'); }, 2000);
        }
        const state = {};
        cols.forEach(col => {
            const cards = [];
            document.querySelectorAll(`#cards-${col} .sprint-card`).forEach(card => {
                cards.push({
                    id: card.dataset.id,
                    title: card.querySelector('.title-text').innerText,
                    brief: card.querySelector('.brief-text').innerText,
                    link: card.querySelector('.link-input').value,
                    reflection: card.querySelector('.reflection-textarea').value,
                    isCustom: card.dataset.custom === 'true',
                    done: card.dataset.done === 'true'
                });
            });
            state[col] = cards;
        });
        localStorage.setItem(storageKey, JSON.stringify(state));
    }

    function createCardHTML(col, cardData) {
        const isCustom = cardData.isCustom || String(cardData.id).startsWith('custom-') || String(cardData.id).startsWith('dup-');
        const isDone = cardData.done === true;
        const card = document.createElement('div');
        card.className = 'sprint-card';
        card.dataset.id = cardData.id;
        card.dataset.custom = isCustom;
        card.dataset.done = isDone ? 'true' : 'false';
        card.innerHTML = `
            <div class="card-actions">
                <button class="bookmark-btn" onclick="bookmarkCard(this)">📌 Bookmark</button>
                <button class="duplicate-btn" onclick="duplicateCard(this, '${col}')">Duplicate</button>
                ${isCustom ? `<button class="delete-btn" onclick="if(confirm('Delete this artifact?')){this.closest('.sprint-card').remove(); saveToStorage(); updateProgress('${col}');}">✕ Delete</button>` : ''}
            </div>
            <div class="card-header" onclick="toggleCard(this)">
                <span class="card-chevron">▶</span>
                <div class="editable-title title-text" contenteditable="true" onclick="event.stopPropagation()" onblur="saveToStorage()">${cardData.title}</div>
            </div>
            <div class="card-body">
                <details class="brief-container">
                    <summary>Experience Brief</summary>
                    <div class="brief-text" contenteditable="true" onblur="saveToStorage()">${cardData.brief || 'Describe the experience...'}</div>
                </details>
                <details class="reflection-box" ${cardData.reflection ? 'open' : ''}>
                    <summary>💭 Associate Reflection</summary>
                    <textarea class="reflection-textarea" placeholder="How does this demonstrate growth?" onblur="saveToStorage()">${cardData.reflection || ''}</textarea>
                </details>
                <div class="action-area">
                    <div class="link-row">
                        <input type="text" class="link-input" placeholder="Paste link here..." value="${cardData.link || ''}" onblur="saveToStorage()">
                        <button class="save-btn ${isDone ? 'saved-done' : ''}" onclick="markDone(this, '${col}')">${isDone ? '✓ Done' : 'Done'}</button>
                    </div>
                </div>
            </div>`;
        return card;
    }

    function duplicateCard(btn, col) {
        const orig = btn.closest('.sprint-card');
        const newCard = createCardHTML(col, {
            id: 'dup-' + Date.now(),
            title: orig.querySelector('.title-text').innerText,
            brief: orig.querySelector('.brief-text').innerText,
            link: '', reflection: '', isCustom: true
        });
        orig.after(newCard);
        saveToStorage();
    }

    function addNewCard(col) {
        const container = document.getElementById(`cards-${col}`);
        const newCard = createCardHTML(col, {
            id: 'custom-' + Date.now(),
            title: '✨ Click to name your custom artifact',
            brief: 'Describe the experience here...',
            link: '', reflection: '', isCustom: true
        });
        container.appendChild(newCard);
        saveToStorage();
        activeFilter = 'all';
        document.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
        document.querySelector('[data-filter="all"]').classList.add('active');
        document.getElementById('filterSearch').value = '';
        applyFilter();
    }

    function bookmarkCard(btn) {
        const card = btn.closest('.sprint-card');
        const title = card.querySelector('.title-text').innerText;
        const brief = card.querySelector('.brief-text').innerText;
        addToQueue(title, pageUrl, brief);
        btn.innerText = '✓ Bookmarked';
        btn.style.background = '#10B981';
        btn.style.color = 'white';
        setTimeout(() => {
            btn.innerText = '📌 Bookmark';
            btn.style.background = '#FEF3C7';
            btn.style.color = '#92400E';
        }, 2000);
    }

    function addToQueue(title, url, desc) {
        const queue = JSON.parse(localStorage.getItem('apex_work_queue') || '[]');
        queue.push({ id: Date.now().toString(), title, url, desc, addedAt: new Date().toISOString() });
        localStorage.setItem('apex_work_queue', JSON.stringify(queue));
    }

    function markDone(btn, col) {
        const card = btn.closest('.sprint-card');
        const isNowDone = card.dataset.done !== 'true';
        card.dataset.done = isNowDone ? 'true' : 'false';
        btn.innerText = isNowDone ? '✓ Done' : 'Done';
        btn.classList.toggle('saved-done', isNowDone);
        saveToStorage();
        updateProgress(col);
        applyFilter();
    }

    function updateProgress(col) {
        const cards = document.querySelectorAll(`#cards-${col} .sprint-card`);
        const doneCount = [...cards].filter(c => c.dataset.done === 'true').length;
        const pips = document.querySelectorAll(`#progress-${col} .progress-pip`);
        pips.forEach((pip, i) => pip.classList.toggle('lit', i < doneCount));
    }

    function toggleCard(headerEl) {
        const body = headerEl.closest('.sprint-card').querySelector('.card-body');
        const isOpen = headerEl.classList.contains('open');
        headerEl.classList.toggle('open', !isOpen);
        body.classList.toggle('open', !isOpen);
    }

    function setFilter(filter, btn) {
        activeFilter = filter;
        document.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
        btn.classList.add('active');
        applyFilter();
    }

    function applyFilter() {
        const query = document.getElementById('filterSearch').value.toLowerCase().trim();
        cols.forEach(col => {
            let anyVisible = false;
            document.querySelectorAll(`#cards-${col} .sprint-card`).forEach(card => {
                const isDone = card.dataset.done === 'true';
                const link = card.querySelector('.link-input').value.trim();
                const reflection = card.querySelector('.reflection-textarea').value.trim();
                const title = card.querySelector('.title-text').innerText.toLowerCase();
                let statusMatch;
                if (activeFilter === 'all') statusMatch = true;
                else if (activeFilter === 'done') statusMatch = isDone;
                else if (activeFilter === 'in-progress') statusMatch = !isDone && (link !== '' || reflection !== '');
                else statusMatch = !isDone && link === '' && reflection === '';
                const show = statusMatch && (!query || title.includes(query));
                card.style.display = show ? '' : 'none';
                if (show) anyVisible = true;
            });
            const noMsg = document.querySelector(`[data-col="${col}"] .no-match-msg`);
            if (noMsg) noMsg.style.display = anyVisible ? 'none' : 'block';
        });
    }

    function toggleSidebar() {
        const sidebar = document.getElementById('sidebar');
        const isOpen = sidebar.classList.contains('open');
        sidebar.classList.toggle('open', !isOpen);
        document.body.classList.toggle('body-sidebar-open', !isOpen);
        localStorage.setItem(sidebarKey, !isOpen);
    }

    function loadQueue() {
        const queue = JSON.parse(localStorage.getItem('apex_work_queue') || '[]');
        displayQueue(queue);
    }

    function displayQueue(queue) {
        const list = document.getElementById('queueList');
        if (!list) return;
        if (queue.length === 0) {
            list.innerHTML = '<div class="empty-queue">No items yet. Bookmark an artifact card to add it here.</div>';
            return;
        }
        list.innerHTML = queue.map(item => `
            <div class="queue-item">
                <a href="${item.url}" target="_blank">${item.title}</a>
                <p>${item.desc || ''}</p>
                <button class="remove-btn" onclick="removeFromQueue('${item.id}')">×</button>
            </div>`).join('');
    }

    function removeFromQueue(id) {
        const queue = JSON.parse(localStorage.getItem('apex_work_queue') || '[]');
        localStorage.setItem('apex_work_queue', JSON.stringify(queue.filter(item => item.id !== id)));
        displayQueue(JSON.parse(localStorage.getItem('apex_work_queue') || '[]'));
    }

    function init() {
        const saved = localStorage.getItem(storageKey);
        const state = saved ? JSON.parse(saved) : defaultCards;
        cols.forEach(col => {
            const container = document.getElementById(`cards-${col}`);
            if (!container) return;
            container.innerHTML = '';
            (state[col] || []).forEach(cardData => {
                if (cardData.brief === undefined) {
                    const def = (defaultCards[col] || []).find(c => c.id === cardData.id);
                    cardData.brief = def ? def.brief : 'Experience details...';
                }
                container.appendChild(createCardHTML(col, cardData));
            });
            updateProgress(col);
        });
        cols.forEach(col => {
            const msg = document.createElement('div');
            msg.className = 'no-match-msg';
            msg.textContent = 'No matching artifacts.';
            document.querySelector(`[data-col="${col}"] .add-btn`).before(msg);
        });
        loadQueue();
        if (localStorage.getItem(sidebarKey) === 'true') {
            document.getElementById('sidebar').classList.add('open');
            document.body.classList.add('body-sidebar-open');
        }
        applyFilter();
    }

    // Expose as globals for HTML onclick attributes
    window.saveToStorage = saveToStorage;
    window.addNewCard = addNewCard;
    window.bookmarkCard = bookmarkCard;
    window.duplicateCard = duplicateCard;
    window.markDone = markDone;
    window.updateProgress = updateProgress;
    window.toggleCard = toggleCard;
    window.toggleSidebar = toggleSidebar;
    window.removeFromQueue = removeFromQueue;
    window.setFilter = setFilter;
    window.applyFilter = applyFilter;

    document.addEventListener('DOMContentLoaded', () => {
        const sb = document.getElementById('sidebarToggle');
        const cl = document.getElementById('closeSidebar');
        if (sb) sb.addEventListener('click', toggleSidebar);
        if (cl) cl.addEventListener('click', toggleSidebar);
        const fs = document.getElementById('filterSearch');
        if (fs) fs.addEventListener('input', applyFilter);
    });

    document.addEventListener('input', e => {
        if (e.target.classList.contains('reflection-textarea') || e.target.hasAttribute('contenteditable')) {
            saveToStorage();
        }
    });

    window.onload = init;
}
```

**Update `Standard1.html`:**

1. Add `data-col` attributes to the 4 vibe-column divs in the HTML. The current divs are:
```html
            <div class="vibe-column col-1" id="col-servant">
            <div class="vibe-column col-2" id="col-client">
            <div class="vibe-column col-3" id="col-team">
            <div class="vibe-column col-4" id="col-brand">
```
Change to add `data-col="servant"`, `data-col="client"`, etc. Keep the existing id.

2. Replace the entire `<script>` block (starting with `const defaultCards = {` and ending with `window.onload = init;`) plus the nav dropdown JS block that follows, with:
```html
<script src="apex-kanban.js"></script>
<script>
    initKanban({
        cols: ['servant', 'client', 'team', 'brand'],
        storageKey: 'apex_std1_state_v6',
        sidebarKey: 's1_sidebar_open',
        pageUrl: 'Standard1.html',
        defaultCards: {
            servant: [
                { id: 'vol-proj', title: '🙋♂🛠 Volunteering for a Project', brief: 'Evidence of stepping up to assist a peer or support a team goal.', link: '', reflection: '', isCustom: false },
                { id: 'peer-rev', title: '📝🤝 Constructive Peer Review', brief: 'Actionable, kind, and specific feedback on a teammate\'s work.', link: '', reflection: '', isCustom: false },
                { id: 'wilc-steward', title: '🧹🏫 WILC Stewardship', brief: 'Maintaining the professional environment (resetting rooms, guiding guests).', link: '', reflection: '', isCustom: false }
            ],
            client: [
                { id: 'c-email', title: '📧✍ Professional Email to Client', brief: 'Email with clear subject, 5 Ws and H, and specific next steps.', link: '', reflection: '', isCustom: false },
                { id: 'c-cal', title: '📅✅ Google Calendar Event', brief: 'Evidence of professional scheduling with all guests invited.', link: '', reflection: '', isCustom: false },
                { id: 'c-up', title: '🔄📈 Weekly Client Update', brief: 'Screenshot of project progress, roadblocks, and next steps.', link: '', reflection: '', isCustom: false }
            ],
            team: [
                { id: 'ind-tour', title: '🏭🗺 Organizing an Industry Tour', brief: 'Coordinating logistics or preparing team questions for a tour.', link: '', reflection: '', isCustom: false },
                { id: 'kan-champ', title: '📊📌 Kanban Board Champion', brief: 'Maintaining a Trello or Slack Canvas task list.', link: '', reflection: '', isCustom: false },
                { id: 'lead-stand', title: '🗣📋 Leading the Stand-Up', brief: 'Evidence of leading a daily scrum or team meeting.', link: '', reflection: '', isCustom: false }
            ],
            brand: [
                { id: 't-fair', title: '🎤🏫 Timberline Career Fair', brief: 'Communicating the APEX value proposition to a public audience.', link: '', reflection: '', isCustom: false },
                { id: 'pitch', title: '🗣👔 The Elevator Pitch', brief: 'Video or script of your 60-second professional introduction.', link: '', reflection: '', isCustom: false },
                { id: 'bus-casual', title: '👔✨ Business Casual Excellence', brief: 'Demonstrating professional appearance standards in client settings.', link: '', reflection: '', isCustom: false }
            ]
        }
    });
</script>
```

**Update `Standard5.html`:**

1. The CSS has `.instruction-text` — rename all occurrences to `.brief-text` in the CSS.

2. Replace the entire `<script>` block (starting with `const COLS = ['digital-comm'...` through `window.onload = init;`) plus any following nav-dropdown JS, with:
```html
<script src="apex-kanban.js"></script>
<script>
    initKanban({
        cols: ['digital-comm', 'prof-presence', 'task-mgmt', 'growth-net'],
        storageKey: 'apex_std5_v6',
        sidebarKey: 's5_sidebar_open',
        pageUrl: 'Standard5.html',
        defaultCards: {
            'digital-comm': [
                { id: 'slack-mastery', title: '✅💬 Slack Mastery', brief: 'Show evidence that you have configured your notifications to "Always" and actively use "Read & React" in team channels.', link: '', reflection: '', isCustom: false },
                { id: 'cc-protocol', title: '📧👥 The "CC" Protocol', brief: 'Capture a screenshot of an email sent to a client where you successfully CC\'d your instructor and partners.', link: '', reflection: '', isCustom: false }
            ],
            'prof-presence': [
                { id: 'handshake', title: '🤝👀 The First Impression', brief: 'Reflect on an interaction involving eye contact, body language, and a professional introduction.', link: '', reflection: '', isCustom: false },
                { id: 'dress-code', title: '👗👔 APEX Dress Code', brief: 'Provide a photo of your Outfit of the Day (OOTD) modeling APEX business casual standards.', link: '', reflection: '', isCustom: false }
            ],
            'task-mgmt': [
                { id: 'agenda', title: '📝⏱ The Pre-Meeting Agenda', brief: 'Provide a link to an agenda shared with your team and client *before* a scheduled meeting.', link: '', reflection: '', isCustom: false },
                { id: 'micro-deliverable', title: '🎯✅ Weekly Micro-Deliverable', brief: 'Evidence of moving a task from "Doing" to "Done" on your team\'s Trello board or Kanban.', link: '', reflection: '', isCustom: false }
            ],
            'growth-net': [
                { id: 'linkedin', title: '🔗🌐 LinkedIn Optimization', brief: 'Update your profile with a headshot, APEX headline, and "About" section featuring your Career Thesis.', link: '', reflection: '', isCustom: false },
                { id: 'feedback', title: '🔄📉 The Feedback Loop', brief: 'Show how you applied constructive criticism from a client or peer to improve a product.', link: '', reflection: '', isCustom: false }
            ]
        }
    });
</script>
```

---

## Important notes

- Read any file before editing it
- The Standard1 and Standard5 scripts are large — make sure you capture the FULL script block when replacing, including the nav-dropdown JS that appears after `window.onload = init;`
- For S1, the `<script>` block starts with `const defaultCards = {` and the entire section (including any following nav dropdown scripts before `</body>`) should be replaced
- For S5, the `<script>` block starts with `const COLS = [`
- When replacing S4BSU individual functions, use exact string matches to avoid touching surrounding code
- The `removeFromQueue` function in the shared file should re-read localStorage after saving instead of using the filtered array directly (to stay consistent)
- Do NOT modify Standard4BSU.html's CSS or HTML structure — only the JS functions and window.onload handler


- update-config: Use this skill to configure the Claude Code harness via settings.json. Automated behaviors ("from now on when X", "each time X", "whenever X", "before/after X") require hooks configured in settings.json - the harness executes these, not Claude, so memory/preferences cannot fulfill them. Also use for: permissions ("allow X", "add permission", "move permission to"), env vars ("set X=Y"), hook troubleshooting, or any changes to settings.json/settings.local.json files. Examples: "allow npm commands", "add bq permission to global settings", "move permission to user settings", "set DEBUG=true", "when claude stops show X". For simple settings like theme/model, suggest the /config command.
- keybindings-help: Use when the user wants to customize keyboard shortcuts, rebind keys, add chord bindings, or modify ~/.claude/keybindings.json. Examples: "rebind ctrl+s", "add a chord shortcut", "change the submit key", "customize keybindings".
- simplify: Review changed code for reuse, quality, and efficiency, then fix any issues found.
- fewer-permission-prompts: Scan your transcripts for common read-only Bash and MCP tool calls, then add a prioritized allowlist to project .claude/settings.json to reduce permission prompts.
- loop: Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo). Omit the interval to let the model self-pace. - When the user wants to set up a recurring task, poll for status, or run something repeatedly on an interval (e.g. "check the deploy every 5 minutes", "keep running /babysit-prs"). Do NOT invoke for one-off tasks.
- schedule: Create, update, list, or run scheduled remote agents (routines) that execute on a cron schedule. - When the user wants to schedule a recurring remote agent, set up automated tasks, create a cron job for Claude Code, or manage their scheduled agents/routines. Also use when the user wants a one-time scheduled run ("run this once at 3pm", "remind me to check X tomorrow").
- claude-api: Build, debug, and optimize Claude API / Anthropic SDK apps. Apps built with this skill should include prompt caching. Also handles migrating existing Claude API code between Claude model versions (4.5 → 4.6, 4.6 → 4.7, retired-model replacements).
TRIGGER when: code imports `anthropic`/`@anthropic-ai/sdk`; user asks for the Claude API, Anthropic SDK, or Managed Agents; user adds/modifies/tunes a Claude feature (caching, thinking, compaction, tool use, batch, files, citations, memory) or model (Opus/Sonnet/Haiku) in a file; questions about prompt caching / cache hit rate in an Anthropic SDK project.
SKIP: file imports `openai`/other-provider SDK, filename like `*-openai.py`/`*-generic.py`, provider-neutral code, general programming/ML.
- init: Initialize a new CLAUDE.md file with codebase documentation
- review: Review a pull request
- security-review: Complete a security review of the pending changes on the current branch


I'll work through these tasks systematically. Let me start by reading all the relevant files.


Bash

List files in Portfolio HTMLs directory


APEX Background Info
APEX Vertical.png
APEX_Professional_Dashboard.html
APEX_Professional_Portfolio.html
APEX_Review_Prep.html
Graphic Design Playbook.html
Marketing Analytics Playbook.html
Photography Playbook.html
Podcast Production Playbook.html
Project Task Boards.html
Social Media Playbook.html
Standard1.html
Standard3.html
Standard4.html
Standard4BSU.html
Standard4DCS.html
Standard5.html
Video Production Playbook.html


Read

/Users/russgoerend/Desktop/Portfolio HTMLs/Project Task Boards.html


1	<!DOCTYPE html>
2
3
4	    <meta charset="UTF-8">
5	    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6	    <title>APEX | Performance Review Prep</title>
7	    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
8
133
134
135
136
137

138
139
140
141	        📋 Performance Review Prep
142

143	            Dashboard
144	            <button class="btn-copy" onclick="copyToClipboard()">📋 Copy Text</button>
145	            <button class="btn-print" onclick="window.print()">🖨 Print / PDF</button>
146

147

148
149
150

151
152
153

154

155
Your Completed Work

156
Click any card to add it to your review. Aim for 2–4 per standard.

157

158

159
160

161

162
163
164

165
166

167
🎓

168

169
Associate Name

170
APEX Strand

171

172

173

174
175
176

177
178

179

180
181
461
462
463
464


1	<!DOCTYPE html>
2
3
4	    <meta charset="UTF-8">
5	    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6	    <title>Project Task Boards Dashboard</title>
7	    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
8
103
104
105
106

107
108
109
110

111	            Dashboard
112	            Portfolio
113	            Video Playbook
114	            Social Media
115	            Analytics
116	            Task Boards
117

118

119
120

121
122
Project Task Boards Dashboard

123
One place to view and manage every project task board across Video, Social Media, and Marketing Analytics projects.

124
125

126	        Task Management
127
All project boards in one place

128
Each project board is pulled from the playbook stores saved locally in your browser. Use this page to see tasks across all projects, update status, and jump back to the relevant playbook.

129

130

131

132
No project boards were found yet.

133
Open a playbook, create a project, and add a few tasks to populate this dashboard.

134

135	    © 2026 Waukee APEX Aspiring Professional Portfolio | Built for Excellence
136

137
293
294
295


Now let me read the other files needed for tasks 2-5:


1	<!DOCTYPE html>
2
3
4	    <meta charset="UTF-8">
5	    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6	    <title>APEX Professional Portfolio</title>
7	    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
8
242
243
244
245
246

247
248
249
250
251

252	            Dashboard
253

254	                <button class="nav-drop-btn active">Portfolio ▾</button>
255

256	                    S1 · Servant Leadership
257	                    S2
258	                    S3 · Career Exploration
259	                    S4 · Technical Skills
260	                    S5 · Professional Skills
261

262

263

264	                <button class="nav-drop-btn">Playbooks ▾</button>
265

266	                    Video Production
267	                    Social Media
268	                    Marketing Analytics
269	                    Podcast Production
270	                    Graphic Design
271	                    Photography
272

273

274

275

276
277
278
279

280
APEX Professional Portfolio

281
Innovation. Leadership. Professionalism.

282

283
284
285

286

287
🎓

288

289	            <input type="text" class="associate-name" id="userName" placeholder="Associate Name" onblur="saveProfile()">
290	            <input type="text" class="associate-strand" id="userStrand" placeholder="APEX Strand (e.g., Business Startup)" onblur="saveProfile()">
291

292

293
294

295
296

297	                Standard 1
298
Servant Leadership & Client Relationships

299
Documenting community impact, professional communication, and project stewardship.

300

301
In Progress

302
303
304
305

306	                Standard 2
307
Professionalism & Ethics

308
Demonstrating integrity, punctuality, and professional workplace behaviors.

309

310
In Progress

311
312
313
314

315	                Standard 3
316
Career Exploration

317
Researching career paths, building a personal brand, and connecting with professionals in your field.

318

319
In Progress

320
321
322
323

324	                Standard 4
325
Technical Skills

326
Mastering industry-specific tools and platforms relevant to your APEX strand.

327

328
In Progress

329
330
331
332

333	                Standard 5
334
Professional Skills

335
Developing the communication, collaboration, and workplace habits that define a standout professional.

336

337
In Progress

338
339

340
341
342	        © 2026 Waukee APEX Aspiring Professional Portfolio | Built for Excellence
343
344

345
346
Profile Saved ✓

347
348
384
385
400
407
408


1	<!DOCTYPE html>
2
3
4	    <meta charset="UTF-8">
5	    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6	    <title>APEX Portfolio | Standard 4: Technical Skills — BSU</title>
7
262
263
264
265

266

267
📌 Work Queue

268	        <button id="closeSidebar">×</button>
269

270

271
No items yet. Bookmark a sprint card to add it here.

272

273

274
275
276

277
278
279
280

281	            Dashboard
282

283	                <button class="nav-drop-btn active">Portfolio ▾</button>
284

285	                    S1 · Servant Leadership
286	                    S2
287	                    S3 · Career Exploration
288	                    S4 · Technical Skills
289	                    S5 · Professional Skills
290

291

292

293	                <button class="nav-drop-btn">Playbooks ▾</button>
294

295	                    Video Production
296	                    Social Media
297	                    Marketing Analytics
298	                    Podcast Production
299	                    Graphic Design
300	                    Photography
301

302

303	            <button id="sidebarToggle" style="color:rgba(255,255,255,0.9);font-size:0.8rem;font-weight:700;padding:8px 14px;border-radius:6px;text-transform:uppercase;letter-spacing:0.03em;transition:all 0.2s;background:none;border:none;cursor:pointer;">📌 Queue</button>
304

305

306
307
308

309
310
Standard 4: Technical Skills

311
Business Startup · Professional Sprint Portfolio. Choose your sprint, master the narrative, and link your evidence.

312
313
314

315

316	            <button class="chip active" data-filter="all" onclick="setFilter('all', this)">All</button>
317	            <button class="chip" data-filter="not-started" onclick="setFilter('not-started', this)">Not Started</button>
318	            <button class="chip" data-filter="in-progress" onclick="setFilter('in-progress', this)">In Progress</button>
319	            <button class="chip" data-filter="done" onclick="setFilter('done', this)">Done</button>
320

321	        <input type="text" id="filterSearch" placeholder="Search sprints...">
322

323
324

325
326

327
🏗🚀 The Builders

328
Best for associates actively developing or testing a business idea.

329
330

331
🏗🚀 The BMC Sprint <button class="bookmark-btn" onclick="bookmarkCard('bmc-sprint')">📌 Bookmark</button>

332
333	                    Sprint Brief
334

335	                        Your mission is to quickly brainstorm and pitch three completely different business ideas. For each, define:
336
Value Proposition: What specific problem are you solving, and how does your product/service create unique value?

337
Customer Segment: Who exactly is your ideal target customer? Be specific.

338
Revenue Streams: How will your business make money?

339
Sustainable Competitive Advantage: What is your unfair advantage that makes your business hard to copy?

340

341
342

343	                    Launch Google Slides
344	                    Launch Canva Deck
345	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('bmc-sprint', this.value)">
346

347

348
349

350
🕵💬 The Customer Discovery Sprint <button class="bookmark-btn" onclick="bookmarkCard('customer-discovery')">📌 Bookmark</button>

351
352	                    Sprint Brief
353

354	                        Prove or disprove a core assumption through direct user interviews.
355
Identify a Problem/Persona: Define the specific problem and the exact type of person you need to talk to.

356
Present Open-Ended Questions: Design 5-7 "ask" questions to uncover true pain points.

357
Reveal the Pivot: Based on your results, explain one major change or "pivot" you would make.

358

359
360

361	                    Launch Google Slides
362	                    Launch Canva Deck
363	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('customer-discovery', this.value)">
364

365

366
367

368
🧩💡 The Gap Analysis

369
370	                    Sprint Brief
371

372	                        Solve a local problem by defining the opportunity, a quick fix, and market size.
373
Identify a Friction Point: Pinpoint something in the Waukee community causing annoyance or inefficiency.

374
Low-Fi Solution: Propose a simple, easy-to-implement solution that could be built in a weekend.

375
Potential Market Size: Estimate how many people are affected and potential revenue/savings.

376

377
378

379	                    Launch Google Slides
380	                    Launch Canva Deck
381	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('gap-analysis', this.value)">
382

383

384
385

386
☕🔥 The 1MC Pressure Cooker

387
388	                    Sprint Brief
389

390	                        Practice high-stakes pitching in a fast-paced environment.
391
3-Minute Pitch: Deliver a concise, powerful pitch of your current business idea using your existing deck.

392
"Hot Seat" Q&A: Immediately follow with a challenging Q&A session designed to pressure-test your assumptions.

393

394
395

396	                    Launch Google Slides
397	                    Launch Canva Deck
398	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('one-mc-pressure', this.value)">
399

400

401
402

403
🛑📉 The Anti-Pitch

404
405	                    Sprint Brief
406

407	                        Identify and mitigate the biggest threats to your business.
408
"Pre-Mortem": Present the top 3 reasons your current business idea could fail in the next 12 months.

409
The One Move That Saves It: Propose the crucial strategic pivot you would take to save the business.

410

411
412

413	                    Launch Google Slides
414	                    Launch Canva Deck
415	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('anti-pitch', this.value)">
416

417

418
419

420
⭐🔄 The 1-Star Review Pivot

421
422	                    Sprint Brief
423

424	                        Use public feedback to find a hidden business opportunity.
425
Find a Recurring Complaint: Identify a common complaint in local 1-star Google/Yelp reviews.

426
Pitch a Fix: Propose an actionable fix for the business, or pitch a new competing service that solves it better.

427

428
429

430	                    Launch Google Slides
431	                    Launch Canva Deck
432	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('one-star-pivot', this.value)">
433

434

435

436
437

438
📊🔢 The Analysts

439
Best for associates who love deconstructing how things work.

440
441

442
💰🧐 The VC Reverse Pitch

443
444	                    Sprint Brief
445

446	                        Step into the role of a Venture Capitalist to analyze a real-world investment.
447
Analyze a Funding Round: Choose a startup that recently announced a major funding round.

448
Would You Invest?: Present a compelling argument for why it was a brilliant move or a costly mistake.

449

450
451

452	                    Launch Google Slides
453	                    Launch Canva Deck
454	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('vc-reverse', this.value)">
455

456

457
458

459
📊🔢 The Unit Economics Breakdown

460
461	                    Sprint Brief
462

463	                        Get into the detailed math of how a business generates profit.
464
Deconstruct a Sale: Select a consumer product/service and break down its financial components.

465
Calculate: Determine the COGS, Gross Margin, and estimate units needed to hit Breakeven.

466

467
468

469	                    Launch Google Slides
470	                    Launch Canva Deck
471	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('unit-economics', this.value)">
472

473

474
475

476
🤖⚡ The AI Efficiency Audit

477
478	                    Sprint Brief
479

480	                        Identify opportunities to streamline business processes using AI tools.
481
Identify a Manual Process: Choose a repetitive, time-consuming process in a common business setting.

482
Pitch an AI Workflow: Propose a specific AI tool/workflow to automate it, and calculate estimated savings.

483

484
485

486	                    Launch Google Slides
487	                    Launch Canva Deck
488	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('ai-audit', this.value)">
489

490

491
492

493
🦈✅ The Shark Tank Fact Check

494
495	                    Sprint Brief
496

497	                        Follow the real-world trajectory of a pitched company.
498
Research a Pitch (2+ Years Ago): Select a company that appeared on Shark Tank at least two years ago.

499
Where Are They Now?: Did the deal close? Track the company's progress and current status in the market.

500

501
502

503	                    Launch Google Slides
504	                    Launch Canva Deck
505	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('shark-tank', this.value)">
506

507

508
509

510
📱🛠 The UX Teardown

511
512	                    Sprint Brief
513

514	                        Practice critical analysis of digital product design and functionality.
515
Identify Friction: Find a local company's site and identify two moments where UX causes confusion.

516
Present a Fix: Propose one specific UI/UX fix and explain why it drastically improves the user journey.

517

518
519

520	                    Launch Google Slides
521	                    Launch Canva Deck
522	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('ux-teardown', this.value)">
523

524

525
526

527
💸⚙ The Revenue Model Breakdown

528
529	                    Sprint Brief
530

531	                        Understand how "free" products actually pay for themselves.
532
The "Hidden Engine": Pick a popular product/service that seems free or too cheap (TikTok, Spotify).

533
Detail the Model: Explain the non-obvious ways the company generates revenue (data licensing, ad exchanges).

534

535
536

537	                    Launch Google Slides
538	                    Launch Canva Deck
539	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('rev-model', this.value)">
540

541

542
543

544
💻🛠 The Tech Stack Audit

545
546	                    Sprint Brief
547

548	                        Design the foundational tools for an efficient project.
549
Pitch a "Stack": Select an APEX project and curate 3-5 software tools necessary to execute it.

550
10x Faster: Justify your choices by explaining how these tools maximize efficiency and speed.

551

552
553

554	                    Launch Google Slides
555	                    Launch Canva Deck
556	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('tech-stack', this.value)">
557

558

559

560
561

562
🤝🧠 The Networkers

563
Best for associates focused on career, community, and industry stories.

564
565

566
🎙🧠 The Podcast Breakdown

567
568	                    Sprint Brief
569

570	                        Analyze the mindset and critical moments of a successful entrepreneur.
571
Summarize a Founder's Journey: Listen to an episode of "How I Built This" and summarize their story.

572
Identify Their "Tipping Point": Pinpoint the single critical decision that propelled the business to success.

573

574
575

576	                    Launch Google Slides
577	                    Launch Canva Deck
578	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('podcast-breakdown', this.value)">
579

580

581
582

583
💎🔍 The Hidden Gem Brand

584
585	                    Sprint Brief
586

587	                        Identify and champion an underrated business.
588
Pitch an Obscure Brand: Find a small, niche brand you admire (under 50k followers).

589
Why It Works: Break down why their specific marketing strategy or community is so effective.

590

591
592

593	                    Launch Google Slides
594	                    Launch Canva Deck
595	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('hidden-gem', this.value)">
596

597

598
599

600
🎢🔄 The Founder Pivot Story

601
602	                    Sprint Brief
603

604	                        Learn from a story of entrepreneurial resilience.
605
The "Near-Death" Moment: Research a local Iowa entrepreneur when their business was nearly bankrupt.

606
Their Comeback: Detail the creative move they made to pivot, survive, and find success.

607

608
609

610	                    Launch Google Slides
611	                    Launch Canva Deck
612	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('founder-pivot', this.value)">
613

614

615
616

617
✉🤝 The Dream Mentor Outreach

618
619	                    Sprint Brief
620

621	                        Develop skills for making impactful professional connections.
622
Present Your Target Mentor: Identify a successful person in your desired field you want to connect with.

623
Your "Hook" Email & Offer: Draft the email. It must have a "hook" and state specific value you can offer them.

624

625
626

627	                    Launch Google Slides
628	                    Launch Canva Deck
629	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('dream-mentor', this.value)">
630

631

632
633

634
🌽🏛 The Local Legend Origin Story

635
636	                    Sprint Brief
637

638	                        Research the foundational growth of an Iowa institution.
639
Research the "Day 1": Choose a massive Iowa-based company (Casey’s, Hy-Vee, Vermeer) and research its beginning.

640
Their Scaling Secret: Identify the key strategy that allowed them to scale from a small venture to a major player.

641

642
643

644	                    Launch Google Slides
645	                    Launch Canva Deck
646	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('local-legend', this.value)">
647

648

649
650

651
🗺✨ Career Exploration 2.0

652
653	                    Sprint Brief
654

655	                        Synthesize your career learning and next steps.
656
Updated Career Thesis: Reflect on recent interviews and present a revised thesis about your desired role.

657
The "Reality Check": Share the most unexpected or surprising piece of information you discovered.

658

659
660

661	                    Launch Google Slides
662	                    Launch Canva Deck
663	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('career-exp-2', this.value)">
664

665

666
667

668
🌐🌲 The Ecosystem Scout

669
670	                    Sprint Brief
671

672	                        Research how to leverage local entrepreneurial resources.
673
Research a Resource: Choose an institution dedicated to supporting startups (Gravitate, IEDA, Techstars Iowa).

674
Pitch How to Use It: Present an actionable plan for how a startup could use their resources in the next 3 months.

675

676
677

678	                    Launch Google Slides
679	                    Launch Canva Deck
680	                    <input type="text" placeholder="Paste presentation link here..." onchange="saveLink('ecosystem-scout', this.value)">
681

682

683

684
685

686

687
688
1080
1081
1096
1103
1104


Now let me read Standard1.html and Standard5.html:


1	<!DOCTYPE html>
2
3
4	    <meta charset="UTF-8">
5	    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6	    <title>APEX Portfolio | Standard 1: Servant Leadership</title>
7
331
332
333
334

335

336
📌 Work Queue

337	        <button id="closeSidebar">×</button>
338

339

340
No items yet. Bookmark an artifact card to add it here.

341

342

343
344
345

346
347
348
349

350	            Dashboard
351

352	                <button class="nav-drop-btn active">Portfolio ▾</button>
353

354	                    S1 · Servant Leadership
355	                    S2
356	                    S3 · Career Exploration
357	                    S4 · Technical Skills
358	                    S5 · Professional Skills
359

360

361

362	                <button class="nav-drop-btn">Playbooks ▾</button>
363

364	                    Video Production
365	                    Social Media
366	                    Marketing Analytics
367	                    Podcast Production
368	                    Graphic Design
369	                    Photography
370

371

372	            <button id="sidebarToggle" style="color:rgba(255,255,255,0.9);font-size:0.8rem;font-weight:700;padding:8px 14px;border-radius:6px;text-transform:uppercase;letter-spacing:0.03em;transition:all 0.2s;background:none;border:none;cursor:pointer;">📌 Queue</button>
373

374

375
376
377

378
379
Standard 1: Servant Leadership & Client Relationships

380
Documenting professional growth, client communication, and community impact.

381
382
383
384	        📊 S1 Servant Leadership Proficiency Indicators
385

386

387	                Exceeds
388	                Associate has displayed immense involvement throughout the semester, far beyond the expectations that have been laid out by the instructor.
389

390

391	                Secure
392	                Takes roles and responsibilities in project work seriously and is actively engaged. Clearly models AGILE methodologies.
393

394

395	                Developing
396	                Occasionally takes initiative on projects but is not always actively engaged. Doesn't always seek feedback.
397

398

399	                Beginning
400	                Does not participate in project work except for meetings. Cannot communicate project goals.
401

402

403
404
405

406

407
🏗 Portfolio Strands

408
The columns below represent the specific areas of focus for this standard. Collect evidence for each strand to build your overall proficiency rating.

409

410

411

412	                1. Choose
413	                Select a card that matches a recent task or experience.
414

415

416	                2. Link & Reflect
417	                Add your artifact link and write a brief growth reflection.
418

419

420	                3. Add Custom
421	                Use the "+ Add" button to document unique experiences.
422

423

424

425
426

427

428	            <button class="chip active" data-filter="all" onclick="setFilter('all', this)">All</button>
429	            <button class="chip" data-filter="not-started" onclick="setFilter('not-started', this)">Not Started</button>
430	            <button class="chip" data-filter="in-progress" onclick="setFilter('in-progress', this)">In Progress</button>
431	            <button class="chip" data-filter="done" onclick="setFilter('done', this)">Done</button>
432

433	        <input type="text" id="filterSearch" placeholder="Search artifacts...">
434

435
436

437

438
🤲🌟 Servant Leadership

439

440

441

442

443	            <button class="add-btn" onclick="addNewCard('servant')">+ Add Artifact Card</button>
444

445
446

447
🤝💼 Client Relationships

448

449

450

451

452	            <button class="add-btn" onclick="addNewCard('client')">+ Add Artifact Card</button>
453

454
455

456
👥🏗 Team Building

457

458

459

460

461	            <button class="add-btn" onclick="addNewCard('team')">+ Add Artifact Card</button>
462

463
464

465
📣🎯 Brand Ambassador

466

467

468

469

470	            <button class="add-btn" onclick="addNewCard('brand')">+ Add Artifact Card</button>
471

472

473

474
475
770
771
786
793
794


1	<!DOCTYPE html>
2
3
4	    <meta charset="UTF-8">
5	    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6	    <title>APEX Portfolio | Standard 5: Professional Skills</title>
7
189
190
191
192

193

194
📌 Work Queue

195	        <button id="closeSidebar">×</button>
196

197

198
No items yet. Bookmark an artifact card to add it here.

199

200

201
202
203

204
205
206
207

208	            Dashboard
209

210	                <button class="nav-drop-btn active">Portfolio ▾</button>
211

212	                    S1 · Servant Leadership
213	                    S2
214	                    S3 · Career Exploration
215	                    S4 · Technical Skills
216	                    S5 · Professional Skills
217

218

219

220	                <button class="nav-drop-btn">Playbooks ▾</button>
221

222	                    Video Production
223	                    Social Media
224	                    Marketing Analytics
225	                    Podcast Production
226	                    Graphic Design
227	                    Photography
228

229

230	            <button id="sidebarToggle" style="color:rgba(255,255,255,0.9);font-size:0.8rem;font-weight:700;padding:8px 14px;border-radius:6px;text-transform:uppercase;letter-spacing:0.03em;transition:all 0.2s;background:none;border:none;cursor:pointer;">📌 Queue</button>
231

232

233
234
235

236
237
Standard 5: Professional Skills

238
Mastering the day-to-day habits of an aspiring professional: communication, presence, time management, and networking.

239
240
241
242	        📊 S5 Professional Skills Proficiency Indicators
243

244

245	                Exceeds
246	                Consistently models high-level professional habits and acts as a mentor for peers in communication and management.
247

248

249	                Secure
250	                Reliably communicates through digital channels, maintains professional presence, and manages tasks effectively.
251

252

253	                Developing
254	                Professional skills are inconsistent. Requires reminders for communication etiquette or task management.
255

256

257	                Beginning
258	                Lacks basic professional habits. Communication is unprofessional or non-existent; presence does not meet APEX standards.
259

260

261
262
263

264

265
🏗 Portfolio Strands

266
Mastering professional skills requires consistent practice across these four areas. Use the cards below to document your habits and growth.

267

268

269
1. IdentifySelect a habit card you've practiced this week.

270
2. Link & ReflectAdd evidence (screenshots/photos) and a reflection.

271
3. CustomizeAdd your own cards to document unique professional milestones.

272

273

274
275

276

277	            <button class="chip active" data-filter="all" onclick="setFilter('all', this)">All</button>
278	            <button class="chip" data-filter="not-started" onclick="setFilter('not-started', this)">Not Started</button>
279	            <button class="chip" data-filter="in-progress" onclick="setFilter('in-progress', this)">In Progress</button>
280	            <button class="chip" data-filter="done" onclick="setFilter('done', this)">Done</button>
281

282	        <input type="text" id="filterSearch" placeholder="Search artifacts...">
283

284
285

286

287
📱💬 Digital Communication

288

289

290

291

292	            <button class="add-btn" onclick="addNewCard('digital-comm')">+ Add Artifact Card</button>
293

294
295

296
👔✨ Professional Presence

297

298

299

300

301	            <button class="add-btn" onclick="addNewCard('prof-presence')">+ Add Artifact Card</button>
302

303
304

305
⏳🗓 Task Management

306

307

308

309

310	            <button class="add-btn" onclick="addNewCard('task-mgmt')">+ Add Artifact Card</button>
311

312
313

314
🤝🌱 Networking & Growth

315

316

317

318

319	            <button class="add-btn" onclick="addNewCard('growth-net')">+ Add Artifact Card</button>
320

321

322

323
324
601
602
617
624
625
626


I now have all the information I need. Let me execute all the tasks. I'll work through them in order.

**TASK 1: Review Prep — add nav dropdown CSS and JS, update nav-links HTML**


Edit

        .nav-links a:hover { color: var(--secondary); background: rgba(255,255,255,.1); }
        .nav-title { color: var(--secondary);

        .nav-links a:hover { color: var(--secondary); background: rgba(255,255,255,.1); }
        /* --- NAV DROPDOWNS --- */
        .nav-dropdown { position: relative; }
        .nav-drop-btn { color: rgba(255,255,255,0.9); background: none; border: none; font-size: 0.8rem; font-weight: 700; padding: 8px 14px; border-radius: 6px; text-transform: uppercase; letter-spacing: 0.03em; transition: all 0.2s; cursor: pointer; font-family: inherit; }
        .nav-dropdown:hover .nav-drop-btn { color: var(--secondary); background: rgba(255,255,255,0.1); }
        .nav-drop-btn.active { background: var(--secondary); color: var(--primary); }
        .nav-dropdown:hover .nav-drop-btn.active { background: var(--secondary); color: var(--primary); opacity: 0.85; }
        .nav-drop-menu { display: none; position: absolute; top: calc(100% + 8px); left: 0; background: white; border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); min-width: 210px; z-index: 1001; padding: 6px 0; border: 1px solid #E5E7EB; }
        .nav-dropdown:hover .nav-drop-menu { display: block; }
        .nav-drop-menu a { display: block; padding: 9px 16px; color: #1F2937; text-decoration: none; font-size: 0.82rem; font-weight: 600; transition: background 0.15s; white-space: nowrap; }
        .nav-drop-menu a:hover { background: #F3F4F6; color: var(--primary); }
        .nav-drop-menu a.active { color: var(--primary); font-weight: 800; background: #F5F3FF; }
        .nav-title { color: var(--secondary);


The file /Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Review_Prep.html has been updated successfully. (file state is current in your context — no need to Read it back)


            Dashboard
            <button class="btn-copy" onclick="copyToClipboard()">📋 Copy Text</button>
            <button class="btn-print" onclick="window.print()">🖨 Print / PDF</button>

            Dashboard

                <button class="nav-drop-btn">Portfolio ▾</button>

                    S1 · Servant Leadership
                    S2
                    S3 · Career Exploration
                    S4 · Technical Skills
                    S5 · Professional Skills

                <button class="nav-drop-btn">Playbooks ▾</button>

                    Video Production
                    Social Media
                    Marketing Analytics
                    Podcast Production
                    Graphic Design
                    Photography

            <button class="btn-copy" onclick="copyToClipboard()">📋 Copy Text</button>
            <button class="btn-print" onclick="window.print()">🖨 Print / PDF</button>


    window.onload = init;
</script>

</body>
</html>

    window.onload = init;
</script>

<script>
document.querySelectorAll('.nav-dropdown').forEach(d => {
    let t, m = d.querySelector('.nav-drop-menu');
    d.addEventListener('mouseenter', () => { clearTimeout(t); m.style.display = 'block'; });
    d.addEventListener('mouseleave', () => { t = setTimeout(() => { m.style.display = ''; }, 150); });
});
</script>

</body>
</html>


Now Task 1 for Project Task Boards — add CSS, update nav-links HTML, add JS:


/Users/russgoerend/Desktop/Portfolio HTMLs/Project Task Boards.html

        .nav-links a.active { background: var(--secondary); color: var(--primary); }
        .container {

        .nav-links a.active { background: var(--secondary); color: var(--primary); }
        /* --- NAV DROPDOWNS --- */
        .nav-dropdown { position: relative; }
        .nav-drop-btn { color: rgba(255,255,255,0.9); background: none; border: none; font-size: 0.8rem; font-weight: 700; padding: 8px 14px; border-radius: 6px; text-transform: uppercase; letter-spacing: 0.03em; transition: all 0.2s; cursor: pointer; font-family: inherit; }
        .nav-dropdown:hover .nav-drop-btn { color: var(--secondary); background: rgba(255,255,255,0.1); }
        .nav-drop-btn.active { background: var(--secondary); color: var(--primary); }
        .nav-dropdown:hover .nav-drop-btn.active { background: var(--secondary); color: var(--primary); opacity: 0.85; }
        .nav-drop-menu { display: none; position: absolute; top: calc(100% + 8px); left: 0; background: white; border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); min-width: 210px; z-index: 1001; padding: 6px 0; border: 1px solid #E5E7EB; }
        .nav-dropdown:hover .nav-drop-menu { display: block; }
        .nav-drop-menu a { display: block; padding: 9px 16px; color: #1F2937; text-decoration: none; font-size: 0.82rem; font-weight: 600; transition: background 0.15s; white-space: nowrap; }
        .nav-drop-menu a:hover { background: #F3F4F6; color: var(--primary); }
        .nav-drop-menu a.active { color: var(--primary); font-weight: 800; background: #F5F3FF; }
        .container {


The file /Users/russgoerend/Desktop/Portfolio HTMLs/Project Task Boards.html has been updated successfully. (file state is current in your context — no need to Read it back)


/Users/russgoerend/Desktop/Portfolio HTMLs/Project Task Boards.html

            Dashboard
            Portfolio
            Video Playbook
            Social Media
            Analytics
            Task Boards

            Dashboard

                <button class="nav-drop-btn">Portfolio ▾</button>

                    S1 · Servant Leadership
                    S2
                    S3 · Career Exploration
                    S4 · Technical Skills
                    S5 · Professional Skills

                <button class="nav-drop-btn">Playbooks ▾</button>

                    Video Production
                    Social Media
                    Marketing Analytics
                    Podcast Production
                    Graphic Design
                    Photography

            Task Boards


/Users/russgoerend/Desktop/Portfolio HTMLs/Project Task Boards.html

    window.onload = renderBoards;
</script>
</body>
</html>

    window.onload = renderBoards;
</script>
<script>
document.querySelectorAll('.nav-dropdown').forEach(d => {
    let t, m = d.querySelector('.nav-drop-menu');
    d.addEventListener('mouseenter', () => { clearTimeout(t); m.style.display = 'block'; });
    d.addEventListener('mouseleave', () => { t = setTimeout(() => { m.style.display = ''; }, 150); });
});
</script>
</body>
</html>


Now **TASK 2: Fix S4BSU localStorage pattern**. I'll work through each sub-step:


    function saveLink(id, value) {
        localStorage.setItem(id, value);
    }

    const S4BSU_KEY = 'apex_std4bsu_v1';

    function saveLink(id, value) { saveS4BSUState(); }


The file /Users/russgoerend/Desktop/Portfolio HTMLs/Standard4BSU.html has been updated successfully. (file state is current in your context — no need to Read it back)


    function saveStd4State() {
        // Write a prep-page-readable summary of all S4 cards
        const allCards = [];
        document.querySelectorAll('.sprint-card').forEach(card => {
            const h4 = card.querySelector('h4');
            if (!h4) return;
            const titleText = [...h4.childNodes]
                .filter(n => n.nodeType === Node.TEXT_NODE)
                .map(n => n.textContent).join('').trim();
            const reflTA = card.querySelector('.reflection-textarea');
            const colEl = card.closest('.vibe-column');
            const colTitle = colEl ? (colEl.querySelector('.vibe-title')?.textContent || '') : '';
            allCards.push({
                id: card.id,
                title: titleText,
                reflection: reflTA ? reflTA.value : '',
                column: colTitle,
                done: card.dataset.done === 'true'
            });
        });
        localStorage.setItem('apex_std4_state_v6', JSON.stringify({ sprints: allCards }));
    }

    function saveS4BSUState() {
        const cards = {};
        document.querySelectorAll('.sprint-card').forEach(card => {
            if (!card.id) return;
            const linkInput = card.querySelector('input[type="text"]');
            const reflTA = card.querySelector('.reflection-textarea');
            const h4 = card.querySelector('h4');
            const title = h4 ? [...h4.childNodes]
                .filter(n => n.nodeType === Node.TEXT_NODE)
                .map(n => n.textContent).join('').trim() : '';
            cards[card.id] = {
                done: card.dataset.done === 'true',
                link: linkInput ? linkInput.value.trim() : '',
                reflection: reflTA ? reflTA.value.trim() : '',
                title
            };
        });
        localStorage.setItem(S4BSU_KEY, JSON.stringify(cards));
        // Keep Review Prep summary format
        const allCards = Object.entries(cards).map(([id, d]) => ({
            id, title: d.title, reflection: d.reflection, done: d.done
        }));
        localStorage.setItem('apex_std4_state_v6', JSON.stringify({ sprints: allCards }));
    }


    function saveReflection(cardId, value) {
        localStorage.setItem(cardId + '_reflection', value);
    }

function saveReflection(cardId, value) { saveS4BSUState(); }


Now fix `markDone` — remove the individual `localStorage.setItem` and replace `saveStd4State()` with `saveS4BSUState()`:


    function markDone(btn, cardId, colEl) {
        const card = document.getElementById(cardId);
        const isNowDone = card.dataset.done !== 'true';
        card.dataset.done = isNowDone ? 'true' : 'false';
        localStorage.setItem(cardId + '_done', isNowDone ? 'true' : 'false');
        btn.innerText = isNowDone ? '✓ Done' : 'Done';
        btn.classList.toggle('saved-done', isNowDone);
        updateProgress(colEl);
        saveStd4State();
        applyFilter();
    }

    function markDone(btn, cardId, colEl) {
        const card = document.getElementById(cardId);
        const isNowDone = card.dataset.done !== 'true';
        card.dataset.done = isNowDone ? 'true' : 'false';
        btn.innerText = isNowDone ? '✓ Done' : 'Done';
        btn.classList.toggle('saved-done', isNowDone);
        updateProgress(colEl);
        saveS4BSUState();
        applyFilter();
    }


Now fix `window.onload` — replace the old restore-link-inputs block with the unified state load:


        // Restore saved link inputs
        document.querySelectorAll('input[type="text"]').forEach(input => {
            const attr = input.getAttribute('onchange');
            if (attr) {
                const match = attr.match(/'([^']+)'/);
                if (match) {
                    const saved = localStorage.getItem(match[1]);
                    if (saved) input.value = saved;
                }
            }
        });

        // Load unified card state (with migration from individual keys)
        let s4State = {};
        const s4Raw = localStorage.getItem(S4BSU_KEY);
        if (s4Raw) {
            try { s4State = JSON.parse(s4Raw); } catch(e) {}
        }


Now replace the old restore-done-state and restore-reflection lines in the card transform loop, and add the savedLink variable:


            // Restore done state
            const isDone = localStorage.getItem(cardId + '_done') === 'true';
            card.dataset.done = isDone ? 'true' : 'false';

            // Restore reflection
            const savedReflection = localStorage.getItem(cardId + '_reflection') || '';

            // Restore state (unified key with fallback to legacy individual keys)
            const cs = s4State[cardId];
            const isDone = cs ? cs.done : localStorage.getItem(cardId + '_done') === 'true';
            const savedLink = cs ? cs.link : (localStorage.getItem(cardId) || '');
            const savedReflection = cs ? cs.reflection : (localStorage.getItem(cardId + '_reflection') || '');
            card.dataset.done = isDone ? 'true' : 'false';


Now add `if (savedLink) linkInput.value = savedLink;` after the `linkInput.onchange` line. I need to find that exact context in the card transform loop:


        const linkInput = document.createElement('input');
        linkInput.type = 'text';
        linkInput.placeholder = 'Paste presentation link here...';
        linkInput.onchange = () => saveLink(newId, linkInput.value);

        const linkInput = document.createElement('input');
        linkInput.type = 'text';
        linkInput.placeholder = 'Paste presentation link here...';
        linkInput.onchange = () => saveLink(newId, linkInput.value);
        if (savedLink) linkInput.value = savedLink;


Wait — I need to check the context here. In the `window.onload` there are two places with `linkInput` — one in the `duplicateCard` function and one in the card transform loop. Let me check the current state of the file to make sure I edited the right one:


840	        const actionArea = document.createElement('div');
841	        actionArea.className = 'action-area';
842	        const createLink = document.createElement('a');
843	        createLink.href = 'https://slides.google.com/create';
844	        createLink.target = '_blank';
845	        createLink.className = 'btn btn-create';
846	        createLink.textContent = 'Launch Google Slides';
847	        const canvaLink = document.createElement('a');
848	        canvaLink.href = 'https://canva.me/presentation';
849	        canvaLink.target = '_blank';
850	        canvaLink.className = 'btn btn-canva';
851	        canvaLink.textContent = 'Launch Canva Deck';
852	        const linkInput = document.createElement('input');
853	        linkInput.type = 'text';
854	        linkInput.placeholder = 'Paste presentation link here...';
855	        linkInput.onchange = () => saveLink(newId, linkInput.value);
856	        if (savedLink) linkInput.value = savedLink;
857	        const doneBtn = document.createElement('button');
858	        doneBtn.className = 'save-btn';
859	        doneBtn.innerText = 'Done';
860	        doneBtn.onclick = () => markDone(doneBtn, newId, colEl);
861	        actionArea.appendChild(createLink);
862	        actionArea.appendChild(canvaLink);
863	        actionArea.appendChild(linkInput);
864	        actionArea.appendChild(doneBtn);
865
866	        body.appendChild(briefDetails);
867	        body.appendChild(reflBox);
868	        body.appendChild(actionArea);
869
870	        newCard.appendChild(actions);
871	        newCard.appendChild(header);
872	        newCard.appendChild(body);
873
874	        card.after(newCard);
875	        updateProgress(colEl);
876	    }
877
878	    // --- BOOKMARK QUEUE ---
879	    function toggleSidebar() {
880	        const sidebar = document.getElementById('sidebar');
881	        const isOpen = sidebar.classList.contains('open');
882	        sidebar.classList.toggle('open', !isOpen);
883	        document.body.classList.toggle('body-sidebar-open', !isOpen);
884	        localStorage.setItem('s4_sidebar_open', !isOpen);
885	    }
886
887	    function loadQueue() {
888	        const queue = JSON.parse(localStorage.getItem('apex_work_queue') || '[]');
889	        displayQueue(queue);
890	    }
891
892	    function displayQueue(queue) {
893	        const list = document.getElementById('queueList');
894	        if (!list) return;
895	        if (queue.length === 0) {
896	            list.innerHTML = '
No items yet. Bookmark a sprint card to add it here.
';
897	            return;
898	        }
899	        list.innerHTML = queue.map(item => `
900

901	                ${item.title}
902
${item.desc || ''}

903	                <button class="remove-btn" onclick="removeFromQueue('${item.id}')">×</button>
904

905	        `).join('');
906	    }
907
908	    function removeFromQueue(id) {
909	        const queue = JSON.parse(localStorage.getItem('apex_work_queue') || '[]');
910	        const updated = queue.filter(item => item.id !== id);
911	        localStorage.setItem('apex_work_queue', JSON.stringify(updated));
912	        displayQueue(updated);
913	    }
914
915	    document.getElementById('sidebarToggle').addEventListener('click', toggleSidebar);
916	    document.getElementById('closeSidebar').addEventListener('click', toggleSidebar);
917
918	    let activeFilter = 'all';
919


That's in the `duplicateCard` function. The `savedLink` variable referenced there is from the `window.onload` outer scope — but wait, `duplicateCard` is defined outside `window.onload`. Let me check where this `linkInput` code lives relative to `window.onload`:


770
771	    function duplicateCard(btn) {
772	        const card = btn.closest('.sprint-card');
773	        const colEl = card.closest('.vibe-column');
774	        const newId = 'dup-' + Date.now();
775
776	        // Capture title text (text nodes only, excluding the chevron span)
777	        const h4 = card.querySelector('h4');
778	        const titleText = [...h4.childNodes]
779	            .filter(n => n.nodeType === Node.TEXT_NODE)
780	            .map(n => n.textContent).join('').trim();
781
782	        // Capture sprint brief content
783	        const instructionEl = card.querySelector('.instruction-text');
784	        const instructionHTML = instructionEl ? instructionEl.innerHTML : '';
785
786	        // Build new card
787	        const newCard = document.createElement('div');
788	        newCard.className = 'sprint-card';
789	        newCard.id = newId;
790	        newCard.dataset.done = 'false';
791
792	        const actions = document.createElement('div');
793	        actions.className = 'card-actions';
794	        const bmkBtn = document.createElement('button');
795	        bmkBtn.className = 'bookmark-btn';
796	        bmkBtn.innerText = '📌 Bookmark';
797	        bmkBtn.onclick = e => { e.stopPropagation(); bookmarkCard(newId); };
798	        const dupBtn = document.createElement('button');
799	        dupBtn.className = 'duplicate-btn';
800	        dupBtn.innerText = 'Duplicate';
801	        dupBtn.onclick = () => duplicateCard(dupBtn);
802	        actions.appendChild(bmkBtn);
803	        actions.appendChild(dupBtn);
804
805	        const header = document.createElement('div');
806	        header.className = 'card-header';
807	        header.onclick = () => toggleCard(header);
808	        const chevron = document.createElement('span');
809	        chevron.className = 'card-chevron';
810	        chevron.textContent = '▶';
811	        const newH4 = document.createElement('h4');
812	        newH4.textContent = titleText + ' (copy)';
813	        newH4.onclick = e => e.stopPropagation();
814	        header.appendChild(chevron);
815	        header.appendChild(newH4);
816
817	        const body = document.createElement('div');
818	        body.className = 'card-body';
819
820	        const briefDetails = document.createElement('details');
821	        const briefSummary = document.createElement('summary');
822	        briefSummary.textContent = 'Sprint Brief';
823	        const instrDiv = document.createElement('div');
824	        instrDiv.className = 'instruction-text';
825	        instrDiv.innerHTML = instructionHTML;
826	        briefDetails.appendChild(briefSummary);
827	        briefDetails.appendChild(instrDiv);
828
829	        const reflBox = document.createElement('details');
830	        reflBox.className = 'reflection-box';
831	        const reflSummary = document.createElement('summary');
832	        reflSummary.textContent = '💭 Associate Reflection';
833	        const reflTA = document.createElement('textarea');
834	        reflTA.className = 'reflection-textarea';
835	        reflTA.placeholder = 'How does this sprint demonstrate your growth?';
836	        reflTA.onblur = () => saveReflection(newId, reflTA.value);
837	        reflBox.appendChild(reflSummary);
838	        reflBox.appendChild(reflTA);
839
840	        const actionArea = document.createElement('div');
841	        actionArea.className = 'action-area';
842	        const createLink = document.createElement('a');
843	        createLink.href = 'https://slides.google.com/create';
844	        createLink.target = '_blank';
845	        createLink.className = 'btn btn-create';
846	        createLink.textContent = 'Launch Google Slides';
847	        const canvaLink = document.createElement('a');
848	        canvaLink.href = 'https://canva.me/presentation';
849	        canvaLink.target = '_blank';
850	        canvaLink.className = 'btn btn-canva';
851	        canvaLink.textContent = 'Launch Canva Deck';
852	        const linkInput = document.createElement('input');
853	        linkInput.type = 'text';
854	        linkInput.placeholder = 'Paste presentation link here...';
855	        linkInput.onchange = () => saveLink(newId, linkInput.value);
856	        if (savedLink) linkInput.value = savedLink;
857	        const doneBtn = document.createElement('button');
858	        doneBtn.className = 'save-btn';
859	        doneBtn.innerText = 'Done';
860	        doneBtn.onclick = () => markDone(doneBtn, newId, colEl);
861	        actionArea.appendChild(createLink);
862	        actionArea.appendChild(canvaLink);
863	        actionArea.appendChild(linkInput);
864	        actionArea.appendChild(doneBtn);
865
866	        body.appendChild(briefDetails);
867	        body.appendChild(reflBox);
868	        body.appendChild(actionArea);
869


I see the issue — I added `if (savedLink) linkInput.value = savedLink;` in the `duplicateCard` function, not in the `window.onload` card transform loop. `savedLink` doesn't exist in that scope. I need to remove it from `duplicateCard` and add it to the correct location in `window.onload`.

Let me look at where the `linkInput` is in the card transform loop inside `window.onload`:


975
976	        // Transform each card
977	        document.querySelectorAll('.sprint-card').forEach(card => {
978	            const h4 = card.querySelector('h4');
979	            const details = card.querySelector('details');
980	            const actionArea = card.querySelector('.action-area');
981	            const cardId = card.id;
982	            const colEl = card.closest('.vibe-column');
983
984	            // Restore state (unified key with fallback to legacy individual keys)
985	            const cs = s4State[cardId];
986	            const isDone = cs ? cs.done : localStorage.getItem(cardId + '_done') === 'true';
987	            const savedLink = cs ? cs.link : (localStorage.getItem(cardId) || '');
988	            const savedReflection = cs ? cs.reflection : (localStorage.getItem(cardId + '_reflection') || '');
989	            card.dataset.done = isDone ? 'true' : 'false';
990
991	            // --- Build hover-only card-actions with bookmark ---
992	            const actions = document.createElement('div');
993	            actions.className = 'card-actions';
994	            const bookmarkBtn = document.createElement('button');
995	            bookmarkBtn.className = 'bookmark-btn';
996	            bookmarkBtn.innerText = '📌 Bookmark';
997	            bookmarkBtn.onclick = e => { e.stopPropagation(); bookmarkCard(cardId); };
998	            const dupBtn2 = document.createElement('button');
999	            dupBtn2.className = 'duplicate-btn';
1000	            dupBtn2.innerText = 'Duplicate';
1001	            dupBtn2.onclick = () => duplicateCard(dupBtn2);
1002	            actions.appendChild(bookmarkBtn);
1003	            actions.appendChild(dupBtn2);
1004
1005	            // --- Build collapsible header ---
1006	            const header = document.createElement('div');
1007	            header.className = 'card-header';
1008	            header.onclick = () => toggleCard(header);
1009	            const chevron = document.createElement('span');
1010	            chevron.className = 'card-chevron';
1011	            chevron.textContent = '▶';
1012
1013	            // Strip any existing inline bookmark from h4, stop click propagation
1014	            const existingBmk = h4.querySelector('.bookmark-btn');
1015	            if (existingBmk) existingBmk.remove();
1016	            h4.onclick = e => e.stopPropagation();
1017	            header.appendChild(chevron);
1018	            header.appendChild(h4);
1019
1020	            // --- Build reflection box ---
1021	            const reflectionBox = document.createElement('details');
1022	            reflectionBox.className = 'reflection-box';
1023	            const reflectionSummary = document.createElement('summary');
1024	            reflectionSummary.textContent = '💭 Associate Reflection';
1025	            const reflectionTextarea = document.createElement('textarea');
1026	            reflectionTextarea.className = 'reflection-textarea';
1027	            reflectionTextarea.placeholder = 'How does this sprint demonstrate your growth?';
1028	            reflectionTextarea.value = savedReflection;
1029	            reflectionTextarea.onblur = () => saveReflection(cardId, reflectionTextarea.value);
1030	            reflectionBox.appendChild(reflectionSummary);
1031	            reflectionBox.appendChild(reflectionTextarea);
1032
1033	            // --- Build collapsible body ---
1034	            const body = document.createElement('div');
1035	            body.className = 'card-body';
1036	            body.appendChild(details);
1037	            body.appendChild(reflectionBox);
1038	            body.appendChild(actionArea);
1039
1040	            // --- Add Done button ---
1041	            const doneBtn = document.createElement('button');
1042	            doneBtn.className = 'save-btn' + (isDone ? ' saved-done' : '');
1043	            doneBtn.innerText = isDone ? '✓ Done' : 'Done';
1044	            doneBtn.onclick = () => markDone(doneBtn, cardId, colEl);
1045	            actionArea.appendChild(doneBtn);
1046
1047	            // --- Rebuild card ---
1048	            card.innerHTML = '';
1049	            card.appendChild(actions);
1050	            card.appendChild(header);
1051	            card.appendChild(body);
1052	        });
1053
1054	        // Initialise all progress bars
1055	        document.querySelectorAll('.vibe-column').forEach(col => updateProgress(col));
1056
1057	        // Load queue and restore sidebar state
1058	        loadQueue();
1059	        if (localStorage.getItem('s4_sidebar_open') === 'true') {
1060	            document.getElementById('sidebar').classList.add('open');
1061	            document.body.classList.add('body-sidebar-open');
1062	        }
1063
1064	        document.querySelectorAll('.vibe-column').forEach(col => {
1065	            const msg = document.createElement('div');
1066	            msg.className = 'no-match-msg';
1067	            msg.textContent = 'No matching artifacts.';
1068	            col.appendChild(msg);
1069	        });
1070
1071	        document.getElementById('filterSearch').addEventListener('input', applyFilter);
1072	        applyFilter();
1073	    };
1074	</script>
1075
1076	<script>
1077	(function(){
1078	    document.querySelectorAll('.nav-dropdown').forEach(function(el){
1079	        var menu = el.querySelector('.nav-drop-menu');
1080	        if (!menu) return;
1081	        var t;
1082	        function show(){ clearTimeout(t); menu.style.display = 'block'; }
1083	        function hide(){ t = setTimeout(function(){ menu.style.display = ''; }, 200); }
1084	        el.addEventListener('mouseenter', show);
1085	        el.addEventListener('mouseleave', hide);
1086	        menu.addEventListener('mouseenter', show);
1087	        menu.addEventListener('mouseleave', hide);
1088	    });
1089	})();
1090	</script>
1091	<script>
1092	document.querySelectorAll('.nav-dropdown').forEach(d => {
1093	    let t, m = d.querySelector('.nav-drop-menu');
1094	    d.addEventListener('mouseenter', () => { clearTimeout(t); m.style.display = 'block'; });


Good. I can see the issue clearly now. The `savedLink` variable IS declared in the card transform loop (line 987) correctly inside `window.onload`. The problem is I accidentally also added `if (savedLink) linkInput.value = savedLink;` inside `duplicateCard` where `savedLink` doesn't exist.

I need to:
1. Remove the bogus `if (savedLink)` line from `duplicateCard`
2. Find where the existing HTML link input is within the card transform loop (the `actionArea` already contains the original `<input>`) and restore it

Looking at the card transform loop, the HTML `<input>` elements already exist in `actionArea` (it comes from the HTML template). The task says to add the savedLink restore after `linkInput.onchange` — but in `window.onload`'s card transform loop, the inputs come from the original HTML, not built with `document.createElement`. Let me look more carefully.

The card transform loop uses `const actionArea = card.querySelector('.action-area');` — so `actionArea` already contains the existing HTML `<input type="text">`. I need to restore `savedLink` into that input. Let me add that after setting the savedLink variable, right when building the card body:


        const linkInput = document.createElement('input');
        linkInput.type = 'text';
        linkInput.placeholder = 'Paste presentation link here...';
        linkInput.onchange = () => saveLink(newId, linkInput.value);
        if (savedLink) linkInput.value = savedLink;

        const linkInput = document.createElement('input');
        linkInput.type = 'text';
        linkInput.placeholder = 'Paste presentation link here...';
        linkInput.onchange = () => saveLink(newId, linkInput.value);


Now add the `savedLink` restore in the card transform loop, right after the existing input is in the `actionArea`. The right place is right after `const actionArea = card.querySelector('.action-area');` and the state restore block — I'll add it after getting `savedLink` by restoring the existing input value:


            // Restore state (unified key with fallback to legacy individual keys)
            const cs = s4State[cardId];
            const isDone = cs ? cs.done : localStorage.getItem(cardId + '_done') === 'true';
            const savedLink = cs ? cs.link : (localStorage.getItem(cardId) || '');
            const savedReflection = cs ? cs.reflection : (localStorage.getItem(cardId + '_reflection') || '');
            card.dataset.done = isDone ? 'true' : 'false';

            // --- Build hover-only card-actions with bookmark ---

            // Restore state (unified key with fallback to legacy individual keys)
            const cs = s4State[cardId];
            const isDone = cs ? cs.done : localStorage.getItem(cardId + '_done') === 'true';
            const savedLink = cs ? cs.link : (localStorage.getItem(cardId) || '');
            const savedReflection = cs ? cs.reflection : (localStorage.getItem(cardId + '_reflection') || '');
            card.dataset.done = isDone ? 'true' : 'false';

            // Restore link input value
            const existingLinkInput = actionArea ? actionArea.querySelector('input[type="text"]') : null;
            if (existingLinkInput && savedLink) existingLinkInput.value = savedLink;

            // --- Build hover-only card-actions with bookmark ---


Now add the `saveS4BSUState()` commit before `loadQueue()` (step I):


        // Load queue and restore sidebar state
        loadQueue();

        // Commit unified state (migrates any legacy individual-key data)
        saveS4BSUState();

        // Load queue and restore sidebar state
        loadQueue();


Now **TASK 3: Fix portfolio progress display** in `APEX_Professional_Portfolio.html`. Replace the buggy badge loop and remove the duplicate dropdown script:


        // Automated Badge Logic for all 5 Standards
        for (let i = 1; i <= 5; i++) {
            const stdData = localStorage.getItem(`apex_std${i}_state_v6`);
            if (stdData) {
                const badge = document.getElementById(`status-${i}`);
                if (badge) {
                    badge.innerText = 'Evidence Logged';
                    badge.classList.add('complete');
                }
            }
        }

        const STD_SOURCES = {
            1: { key: 'apex_std1_state_v6', fmt: 'kanban' },
            3: { key: 'apex_v37',           fmt: 'phase'  },
            4: { key: 'apex_std4bsu_v1',    fmt: 'bsu',   fallback: 'apex_std4_state_v6' },
            5: { key: 'apex_std5_v6',        fmt: 'kanban' }
        };
        [1, 3, 4, 5].forEach(i => {
            const badge = document.getElementById(`status-${i}`);
            if (!badge) return;
            try {
                const src = STD_SOURCES[i];
                let raw = localStorage.getItem(src.key);
                if (!raw && src.fallback) raw = localStorage.getItem(src.fallback);
                if (!raw) return;
                const state = JSON.parse(raw);
                let total = 0, done = 0, unit = 'done';
                if (src.fmt === 'kanban') {
                    Object.values(state).forEach(col => {
                        if (!Array.isArray(col)) return;
                        total += col.length;
                        done += col.filter(c => c.done === true || c.done === 'true').length;
                    });
                } else if (src.fmt === 'phase') {
                    total = 4; done = (state.visited || []).length; unit = 'phases';
                } else if (src.fmt === 'bsu') {
                    const cards = Object.values(state);
                    if (cards[0] && cards[0].sprints) {
                        // old summary format
                        total = cards[0].sprints.length;
                        done = cards[0].sprints.filter(c => c.done).length;
                    } else {
                        total = cards.length;
                        done = cards.filter(c => c.done).length;
                    }
                }
                if (total > 0) {
                    badge.innerText = `${done} / ${total} ${unit}`;
                    badge.classList.add('complete');
                }
            } catch(e) {}
        });


The file /Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Professional_Portfolio.html has been updated successfully. (file state is current in your context — no need to Read it back)


Now remove the older/duplicate dropdown script (keep the one that also adds listeners on the menu element):