<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>


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 **TASK 4: Fix Review Prep S5 key bug**:


Edit

{ num: 5, label: 'S5', name: 'Professional Skills', cls: 's5', key: 'apex_std5_state_v6' }

{ num: 5, label: 'S5', name: 'Professional Skills', cls: 's5', key: 'apex_std5_v6' }


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)


Now **TASK 5: Create apex-kanban.js and update Standard1.html and Standard5.html**.

First, create the shared JS file:


Write

// 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 = `

                <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>` : ''}

                ▶

${cardData.title}

                    Experience Brief

${cardData.brief || 'Describe the experience...'}

                    💭 Associate Reflection
                    <textarea class="reflection-textarea" placeholder="How does this demonstrate growth?" onblur="saveToStorage()">${cardData.reflection || ''}</textarea>

                        <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>

`;
        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 = '
No items yet. Bookmark an artifact card to add it here.
';
            return;
        }
        list.innerHTML = queue.map(item => `

                ${item.title}

${item.desc || ''}

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

`).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;
}


File created successfully at: /Users/russgoerend/Desktop/Portfolio HTMLs/apex-kanban.js (file state is current in your context — no need to Read it back)


Now update `Standard1.html`. I need to:
1. Add `data-col` attributes to the 4 vibe-column divs
2. Replace the entire script block (from `const defaultCards = {` through `window.onload = init;`) plus the nav dropdown JS blocks with the new `<script src>` + `initKanban()` call

First, add `data-col` attributes:


Edit

<div class="vibe-column col-1" id="col-servant">

<div class="vibe-column col-1" id="col-servant" data-col="servant">


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


<div class="vibe-column col-2" id="col-client">

<div class="vibe-column col-2" id="col-client" data-col="client">


<div class="vibe-column col-3" id="col-team">

<div class="vibe-column col-3" id="col-team" data-col="team">


<div class="vibe-column col-4" id="col-brand">

<div class="vibe-column col-4" id="col-brand" data-col="brand">


Now replace the entire script block plus the two nav dropdown scripts at the bottom:


<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>
</body>
</html>


Now update `Standard5.html`. First rename `.instruction-text` to `.brief-text` in the CSS, then replace the script blocks:


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


Now replace the entire script block in Standard5.html (from `const COLS = [` through the end nav dropdown scripts):


<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>
</body>
</html>


<tool_use_error>String to replace not found in file.
String:

(note: Edit also tried swapping \uXXXX escapes and their characters; neither form matched, so the mismatch is likely elsewhere in old_string. Re-read the file and copy the exact surrounding text.)</tool_use_error>

Error: String to replace not found in file.
String:

(note: Edit also tried swapping \uXXXX escapes and their characters; neither form matched, so the mismatch is likely elsewhere in old_string. Re-read the file and copy the exact surrounding text.)


The `replace_all` for `.instruction-text` changed those strings in the JS too, so the old_string no longer matches. Let me read the current state of the script block in Standard5.html:


324
601
602
617


Good. Now I can see the current state. The `.instruction-text` rename already happened in some places (duplicateCard uses `.brief-text` now) but the HTML template inside `createCardHTML` still uses `class="instruction-text"`. I need to do that rename AND replace the whole script block. Let me do the script replacement with the correct current content:


<script>
    const COLS = ['digital-comm', 'prof-presence', 'task-mgmt', 'growth-net'];

<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>
<script>
    const COLS_UNUSED = ['digital-comm', 'prof-presence', 'task-mgmt', 'growth-net'];


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


That approach would leave the old script code in place. Let me take a different approach — I'll replace the old script content by finding a unique anchor. Let me replace from the old `const defaultCards` definition through the end of the file:


348	        }
349	    });
350	</script>
351	<script>
352	    const COLS_UNUSED = ['digital-comm', 'prof-presence', 'task-mgmt', 'growth-net'];
353
354	    const defaultCards = {
355	        'digital-comm': [
356	            { 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.', reflection: '', link: '', isCustom: false, done: false },
357	            { 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.', reflection: '', link: '', isCustom: false, done: false }


Good. Now I need to remove the old script block entirely (everything from `<script>\n    const COLS_UNUSED` through the end of the file) and replace with just the nav dropdown script and closing tags. Let me read what comes after line 600:


606	            const msg = document.createElement('div');
607	            msg.className = 'no-match-msg';
608	            msg.textContent = 'No matching artifacts.';
609	            document.querySelector(`[data-col="${col}"] .add-btn`).before(msg);
610	        });
611
612	        loadQueue();
613	        if (localStorage.getItem('s5_sidebar_open') === 'true') {
614	            document.getElementById('sidebar').classList.add('open');
615	            document.body.classList.add('body-sidebar-open');
616	        }
617	        applyFilter();
618	    }
619
620	    document.addEventListener('input', (e) => {
621	        if (e.target.classList.contains('reflection-textarea') || e.target.hasAttribute('contenteditable')) {
622	            saveToStorage();
623	        }
624	    });
625
626	    window.onload = init;
627	</script>
628
629	<script>
630	(function(){
631	    document.querySelectorAll('.nav-dropdown').forEach(function(el){
632	        var menu = el.querySelector('.nav-drop-menu');
633	        if (!menu) return;
634	        var t;
635	        function show(){ clearTimeout(t); menu.style.display = 'block'; }
636	        function hide(){ t = setTimeout(function(){ menu.style.display = ''; }, 200); }
637	        el.addEventListener('mouseenter', show);
638	        el.addEventListener('mouseleave', hide);
639	        menu.addEventListener('mouseenter', show);
640	        menu.addEventListener('mouseleave', hide);
641	    });
642	})();
643	</script>
644	<script>
645	document.querySelectorAll('.nav-dropdown').forEach(d => {


645	document.querySelectorAll('.nav-dropdown').forEach(d => {
646	    let t, m = d.querySelector('.nav-drop-menu');
647	    d.addEventListener('mouseenter', () => { clearTimeout(t); m.style.display = 'block'; });
648	    d.addEventListener('mouseleave', () => { t = setTimeout(() => { m.style.display = ''; }, 150); });
649	});
650	</script>
651	</body>
652	</html>
653


Now I'll replace the entire old `<script>` block from line 351 through the end with just `</body>\n</html>`:


<script>
    const COLS_UNUSED = ['digital-comm', 'prof-presence', 'task-mgmt', 'growth-net'];

    const 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.', reflection: '', link: '', isCustom: false, done: 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.', reflection: '', link: '', isCustom: false, done: false }
        ],

<!-- old script removed, logic now in apex-kanban.js -->
<script>
    const COLS_PLACEHOLDER = ['digital-comm'];


This approach of incrementally replacing is getting unwieldy. Let me take a cleaner approach - read the full current file and rewrite just the bottom portion cleanly:


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
325


The structure looks correct through line 324. The `<script src="apex-kanban.js">` and the `initKanban()` call are already in place. Now I need to remove the leftover old script block. Let me read from line 350 onwards to see what's there:


349	    });
350	</script>
351	<!-- old script removed, logic now in apex-kanban.js -->
352	<script>
353	    const COLS_PLACEHOLDER = ['digital-comm'];
354	        'prof-presence': [
355	            { id: 'handshake', title: '🤝👀 The First Impression', brief: 'Reflect on an interaction involving eye contact, body language, and a professional introduction.', reflection: '', link: '', isCustom: false, done: false },
356	            { id: 'dress-code', title: '👗👔 APEX Dress Code', brief: 'Provide a photo of your Outfit of the Day (OOTD) modeling APEX business casual standards.', reflection: '', link: '', isCustom: false, done: false }
357	        ],
358	        'task-mgmt': [
359	            { id: 'agenda', title: '📝⏱ The Pre-Meeting Agenda', brief: 'Provide a link to an agenda shared with your team and client *before* a scheduled meeting.', reflection: '', link: '', isCustom: false, done: false },
360	            { 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.', reflection: '', link: '', isCustom: false, done: false }
361	        ],
362	        'growth-net': [
363	            { id: 'linkedin', title: '🔗🌐 LinkedIn Optimization', brief: 'Update your profile with a headshot, APEX headline, and "About" section featuring your Career Thesis.', reflection: '', link: '', isCustom: false, done: false },
364	            { id: 'feedback', title: '🔄📉 The Feedback Loop', brief: 'Show how you applied constructive criticism from a client or peer to improve a product.', reflection: '', link: '', isCustom: false, done: false }
365	        ]
366	    };
367
368	    function saveToStorage() {


This is messy. The file now has the correct `initKanban()` block followed by a broken leftover script block. The cleanest fix is to rewrite the entire file from line 324 (after `</div>\n</div>`) onwards. Let me just find the cleanly correct ending point and replace everything after `</div>\n</div>`:


<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': [


322	</div>
323
324	REPLACE_MARKER_START
325	                { 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 },
326	                { 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 }
327	            ],
328	            'growth-net': [
329	                { 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 },
330	                { 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 }
331	            ]


The file is getting fragmented from the incremental edits. The cleanest path forward is to rewrite the entire Standard5.html file. I have the full CSS and HTML content from my earlier read (lines 1-322). Let me write the complete clean file:


Write

<!DOCTYPE html>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>APEX Portfolio | Standard 5: Professional Skills</title>

📌 Work Queue

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

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

            Dashboard

                <button class="nav-drop-btn active">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 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>

Standard 5: Professional Skills

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

        📊 S5 Professional Skills Proficiency Indicators

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

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

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

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

🏗 Portfolio Strands

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

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

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

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

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

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

📱💬 Digital Communication

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

👔✨ Professional Presence

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

⏳🗓 Task Management

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

🤝🌱 Networking & Growth

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


Now let me verify all files look correct with a quick spot-check on each:


Bash

grep -n "nav-dropdown\|initKanban\|S4BSU_KEY\|apex_std5_v6\|STD_SOURCES\|apex-kanban" "/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Review_Prep.html" | head -20

Check Review Prep for nav-dropdown and S5 key fix


30:        .nav-dropdown { position: relative; }
32:        .nav-dropdown:hover .nav-drop-btn { color: var(--secondary); background: rgba(255,255,255,0.1); }
34:        .nav-dropdown:hover .nav-drop-btn.active { background: var(--secondary); color: var(--primary); opacity: 0.85; }
36:        .nav-dropdown:hover .nav-drop-menu { display: block; }
155:

165:

219:        { num: 5, label: 'S5', name: 'Professional Skills', cls: 's5', key: 'apex_std5_v6' }
495:document.querySelectorAll('.nav-dropdown').forEach(d => {


grep -n "nav-dropdown\|Task Boards" "/Users/russgoerend/Desktop/Portfolio HTMLs/Project Task Boards.html" | head -10

Check Project Task Boards for nav-dropdown


6:    <title>Project Task Boards Dashboard</title>
69:        .nav-dropdown { position: relative; }
71:        .nav-dropdown:hover .nav-drop-btn { color: var(--secondary); background: rgba(255,255,255,0.1); }
73:        .nav-dropdown:hover .nav-drop-btn.active { background: var(--secondary); color: var(--primary); opacity: 0.85; }
75:        .nav-dropdown:hover .nav-drop-menu { display: block; }
123:

133:

144:            Task Boards
150:
Project Task Boards Dashboard

322:document.querySelectorAll('.nav-dropdown').forEach(d => {


grep -n "S4BSU_KEY\|saveS4BSUState\|apex_std4bsu_v1\|savedLink" "/Users/russgoerend/Desktop/Portfolio HTMLs/Standard4BSU.html" | head -20

Check S4BSU for all new localStorage pattern pieces


689:    const S4BSU_KEY = 'apex_std4bsu_v1';
691:    function saveLink(id, value) { saveS4BSUState(); }
733:        saveS4BSUState();
737:    function saveS4BSUState() {
754:        localStorage.setItem(S4BSU_KEY, JSON.stringify(cards));
769:    function saveReflection(cardId, value) { saveS4BSUState(); }
956:        const s4Raw = localStorage.getItem(S4BSU_KEY);
986:            const savedLink = cs ? cs.link : (localStorage.getItem(cardId) || '');
992:            if (existingLinkInput && savedLink) existingLinkInput.value = savedLink;
1061:        saveS4BSUState();


grep -n "STD_SOURCES\|apex_std4bsu_v1\|apex_std5_v6\|apex_v37" "/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Professional_Portfolio.html" | head -15

Check Portfolio page for badge fix


369:        const STD_SOURCES = {
371:            3: { key: 'apex_v37',           fmt: 'phase'  },
372:            4: { key: 'apex_std4bsu_v1',    fmt: 'bsu',   fallback: 'apex_std4_state_v6' },
373:            5: { key: 'apex_std5_v6',        fmt: 'kanban' }
379:                const src = STD_SOURCES[i];


grep -n "initKanban\|apex-kanban\|data-col" "/Users/russgoerend/Desktop/Portfolio HTMLs/Standard1.html" | head -15

Check Standard1 for initKanban and data-col


437:

446:

455:

464:

475:
477:    initKanban({


grep -n "initKanban\|apex-kanban\|data-col\|brief-text" "/Users/russgoerend/Desktop/Portfolio HTMLs/Standard5.html" | head -15

Check Standard5 for initKanban, data-col, brief-text


127:        .brief-text { padding-top: 8px; min-height: 20px; outline: none; line-height: 1.4; }
128:        .brief-text[contenteditable="true"]:focus { background: white; padding: 5px; border-radius: 4px; }
286:

295:

304:

313:

324:
326:    initKanban({


# Check that Portfolio page has only one dropdown script (the IIFE one that also adds menu listener)
grep -c "nav-dropdown" "/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Professional_Portfolio.html"
# Also confirm no duplicate script blocks
grep -n "querySelectorAll.*nav-dropdown" "/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Professional_Portfolio.html"

Check Portfolio page dropdown script count


8
417:    document.querySelectorAll('.nav-dropdown').forEach(function(el){


# Verify Standard1 has no leftover old script functions
grep -c "function saveToStorage\|function createCardHTML\|function init()" "/Users/russgoerend/Desktop/Portfolio HTMLs/Standard1.html"

Check Standard1 has no leftover old JS functions


# Verify Standard5 has no leftover old JS
grep -c "function saveToStorage\|function createCardHTML\|function init()\|COLS_PLACEHOLDER\|COLS_UNUSED" "/Users/russgoerend/Desktop/Portfolio HTMLs/Standard5.html"
# And check apex-kanban.js was created correctly
wc -l "/Users/russgoerend/Desktop/Portfolio HTMLs/apex-kanban.js"

Verify Standard5 is clean and apex-kanban.js exists


0
     268 /Users/russgoerend/Desktop/Portfolio HTMLs/apex-kanban.js


# Verify Portfolio page - confirm the IIFE script is still there and the simple one was removed
grep -A3 "querySelectorAll.*nav-dropdown" "/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Professional_Portfolio.html"

Confirm Portfolio page has only the IIFE nav-dropdown script


    document.querySelectorAll('.nav-dropdown').forEach(function(el){
        var menu = el.querySelector('.nav-drop-menu');
        if (!menu) return;
        var t;


# Check S4BSU markDone no longer has the individual localStorage.setItem for _done
grep -A8 "function markDone" "/Users/russgoerend/Desktop/Portfolio HTMLs/Standard4BSU.html" | head -12

Verify markDone no longer sets individual _done key


    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();


All checks pass. Let me do one final check to confirm the `markDone` in `Standard4BSU.html` no longer has `localStorage.setItem(cardId + '_done'`:


Confirm no more individual _done or _reflection setItem calls in S4BSU


(Bash completed with no output)


All tasks are complete. Here is a summary of what was done:

---

**Task 1 — Nav dropdowns added to Review Prep and Task Boards**

- `/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Review_Prep.html`: Added nav dropdown CSS block (after `.nav-links a:hover` rule), replaced nav-links HTML with Portfolio/Playbooks dropdowns (keeping the Copy/Print buttons), added hover-timer JS before `</body>`.
- `/Users/russgoerend/Desktop/Portfolio HTMLs/Project Task Boards.html`: Same CSS and JS additions; replaced the old flat nav links with the dropdown structure, retaining the `active` class on "Task Boards".

**Task 2 — S4BSU unified localStorage pattern**

- `/Users/russgoerend/Desktop/Portfolio HTMLs/Standard4BSU.html`:
  - Added `const S4BSU_KEY = 'apex_std4bsu_v1'`
  - Replaced `saveStd4State()` with `saveS4BSUState()` (saves full card objects to `apex_std4bsu_v1`, still writes `apex_std4_state_v6` in Review Prep summary format)
  - `saveLink()` and `saveReflection()` now delegate to `saveS4BSUState()`
  - `markDone()` no longer writes individual `_done` keys
  - `window.onload` now loads `s4State` from the unified key with legacy fallback for each field, restores link inputs, and commits unified state at the end

**Task 3 — Portfolio progress display fixed**

- `/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Professional_Portfolio.html`: Replaced the broken `for i = 1..5` badge loop with `STD_SOURCES` map using correct keys (`apex_v37` for S3, `apex_std5_v6` for S5, `apex_std4bsu_v1` for S4 with fallback). Badges now show `X / Y done` (or `X / 4 phases` for S3). Removed the duplicate simpler dropdown script (kept the IIFE version that also binds menu hover listeners).

**Task 4 — Review Prep S5 key bug fixed**

- `/Users/russgoerend/Desktop/Portfolio HTMLs/APEX_Review_Prep.html`: Changed S5 key from `apex_std5_state_v6` to `apex_std5_v6`.

**Task 5 — Shared kanban JS + DRY up S1 and S5**

- Created `/Users/russgoerend/Desktop/Portfolio HTMLs/apex-kanban.js` (268 lines) with `initKanban(config)` encapsulating all shared kanban logic.
- `/Users/russgoerend/Desktop/Portfolio HTMLs/Standard1.html`: Added `data-col` attributes to all 4 vibe-column divs; replaced entire old script block + duplicate nav dropdown scripts with `<script src="apex-kanban.js">` + `initKanban()` call.
- `/Users/russgoerend/Desktop/Portfolio HTMLs/Standard5.html`: Renamed `.instruction-text` to `.brief-text` in CSS; replaced entire old script block + duplicate nav dropdown scripts with `<script src="apex-kanban.js">` + `initKanban()` call (full file rewrite to cleanly remove all remnants).