diff --git a/Status.md b/Status.md
index 9a7060f1..a6d083b2 100644
--- a/Status.md
+++ b/Status.md
@@ -1,14 +1,13 @@
# HVAC Community Events - Project Status
**Last Updated:** February 9, 2026
-**Current Session:** Marker Visibility Toggle Checkbox Refactor
**Version:** 2.2.18 (Deployed to Production)
---
-## ๐ฏ NEXT SESSION - CAPTCHA IMPLEMENTATION
+## NEXT SESSION - CAPTCHA IMPLEMENTATION
-### Status: ๐ **PLANNED**
+### Status: PLANNED
**Objective:** Add CAPTCHA to all user-facing forms to prevent spam and bot submissions.
@@ -20,9 +19,9 @@
---
-## ๐ฏ CURRENT SESSION - MARKER VISIBILITY TOGGLE CHECKBOX REFACTOR (Feb 9, 2026)
+## CURRENT SESSION - MARKER VISIBILITY TOGGLE CHECKBOX REFACTOR (Feb 9, 2026)
-### Status: โ
**COMPLETE - Deployed to Production (v2.2.18)**
+### Status: COMPLETE - Deployed to Production (v2.2.18)
**Objective:** Refactor the marker visibility toggles on the Find Training page from standalone colored dots into inline checkboxes beside each category tab heading.
@@ -32,22 +31,14 @@
- Removed standalone `hvac-visibility-toggles` div with 3 colored dot toggles
- Moved each checkbox inline into its corresponding tab button (`Events`, `Trainers`, `Venues`)
- `onclick="event.stopPropagation()"` on labels prevents checkbox clicks from triggering tab switches
- - Checkbox IDs unchanged (`hvac-show-events`, `hvac-show-trainers`, `hvac-show-venues`) โ no JS changes needed
+ - Checkbox IDs unchanged โ no JS changes needed
2. **Custom Checkbox Styling** (`assets/css/find-training-map.css`)
- - Replaced old dot-based toggle CSS with custom checkbox styles
- - 14x14px checkboxes with rounded corners, white background, CSS checkmark
- - Category-specific colors when checked: teal for events (`#0ebaa6`), green for trainers (`#6aad1e`), green for venues (`#89c92e`)
- - Unchecked state: grey-bordered empty box
- - Tablet: smaller 12px checkboxes
- - Mobile (<768px): checkboxes hidden (same behavior as before)
+ - 14x14px custom checkboxes with category-specific fill colors when checked
+ - Trainer checkbox uses explicit `#6aad1e` (CSS variable `--hvac-trainer-color` is too light)
+ - Tablet: 12px checkboxes; Mobile (<768px): hidden
-3. **Trainer Checkbox Color Fix** (`assets/css/find-training-map.css`)
- - `--hvac-trainer-color` CSS variable is `#f0f7e8` (near-white), too light for checkbox fill
- - Overrode trainer checkbox specifically with `#6aad1e` for visible green
-
-4. **Version Bump** (`includes/class-hvac-plugin.php`)
- - Bumped `HVAC_VERSION` and `HVAC_PLUGIN_VERSION` from `2.2.17` to `2.2.18` for CDN cache busting
+3. **Version Bump** (`includes/class-hvac-plugin.php`) โ `2.2.17` โ `2.2.18`
### Files Modified
@@ -57,1291 +48,83 @@
| `assets/css/find-training-map.css` | Replaced dot toggle CSS with checkbox styles, responsive adjustments |
| `includes/class-hvac-plugin.php` | Version bump `2.2.17` โ `2.2.18` |
-### Verification
-
-- โ
All 3 checkboxes render inline beside tab headings with category colors
-- โ
Unchecking a checkbox removes that category's markers from map
-- โ
Re-checking restores markers
-- โ
Tab switching works independently of checkbox state
-- โ
Counts display correctly: Events (8), Trainers (42), Venues (9)
-- โ
No JS changes required โ existing event handlers work with unchanged checkbox IDs
-
----
-
-## ๐ PREVIOUS SESSION - FIND TRAINING TAB REORDER, MARKER HIGHLIGHTING & MAP RESET (Feb 9, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Production (v2.2.17)**
-
-**Objective:** Reorder Find Training page tabs to make Events the default, add visual marker highlighting when switching tabs, add a map reset button, and fix mobile overflow caused by the changes.
-
-### Changes Made
-
-1. **Tab Reorder: Events First** (`templates/page-find-training.php`, `assets/js/find-training-map.js`)
- - Moved Events tab from 3rd to 1st position (default active tab)
- - Tab order is now: **Events | Trainers | Venues**
- - Updated search placeholder to "Search events..."
- - Updated skip link to target `#hvac-event-grid`
- - Updated filter bar aria-label for all three categories
- - Reordered tab panels to match (Events panel active with loading spinner)
-
-2. **Marker Highlighting on Tab Selection** (`assets/js/find-training-map.js`)
- - Added 4 highlighted icon methods: `getTrainerIconHighlighted()`, `getChampionIconHighlighted()`, `getVenueIconHighlighted()`, `getEventIconHighlighted()`
- - Highlighted icons are larger (scale +4) with brighter/thicker strokes (strokeWeight 3)
- - URL-based icons scale from 32x32 to 40x40 with adjusted anchors
- - Added `highlightMarkersForTab(tab)` method with no-map guard
- - Highlighted markers get `zIndex: 100` (vs default `1`) to render on top
- - Called from both `switchTab()` and `updateMarkers()`
-
-3. **Map Reset Button** (`templates/page-find-training.php`, `assets/js/find-training-map.js`, `assets/css/find-training-map.css`)
- - Added reset button (rotate icon) positioned bottom-right of map container
- - Calls `fitBounds()` to restore original zoom encompassing all markers
- - Styled to match Google Maps UI controls (white, rounded, shadow)
-
-4. **Mobile Overflow Fix** (`assets/css/find-training-map.css`)
- - **Symptom:** Making Events the default tab exposed long event titles (e.g., "measureQuick 101: Cooling and Heat Pump Commissioning") that pushed sidebar beyond viewport width
- - **Root Cause:** Tablet media query had `overflow: visible !important` on `.hvac-sidebar`, overriding base `overflow: hidden`
- - **Fix:** Changed to `overflow-x: hidden !important; overflow-y: visible !important;`
- - Also added `overflow: hidden` and `min-width: 0; text-overflow: ellipsis` to tab buttons
-
-5. **Version Bump** (`includes/class-hvac-plugin.php`)
- - Bumped `HVAC_VERSION` and `HVAC_PLUGIN_VERSION` from `2.2.14` to `2.2.17`
- - Intermediate bumps (2.2.15, 2.2.16) needed during debugging to bust CSS cache
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `templates/page-find-training.php` | Reorder tabs/panels (Events first), update placeholder/skip link/aria, add reset button |
-| `assets/js/find-training-map.js` | Default to `'events'`, 4 highlighted icon methods, `highlightMarkersForTab()`, `resetMapView()`, dynamic `showLoading()` |
-| `assets/css/find-training-map.css` | Reset button styles, mobile overflow fix (`overflow-x: hidden`), tab overflow protection |
-| `includes/class-hvac-plugin.php` | Version bump `2.2.14` โ `2.2.17` |
-
### Git Commit
-- `9dbe472c` - feat(find-training): Reorder tabs (Events first), add marker highlighting and map reset
-
-### Verification
-
-- โ
Events tab active and first on page load, placeholder says "Search events..."
-- โ
Event markers highlighted (larger, brighter) by default
-- โ
Switching tabs highlights corresponding marker category, others revert to normal
-- โ
Highlighted markers render on top (zIndex 100)
-- โ
Reset button restores original zoom/bounds after zooming in
-- โ
Mobile (375px): no horizontal overflow, sidebar fits viewport
-- โ
Keyboard tab navigation still works (arrow keys)
+- `95382ac3` - feat(find-training): Refactor marker visibility dots into inline tab checkboxes
---
-## ๐ PREVIOUS SESSION - MOBILE FIND TRAINING SCROLL FIX (Feb 9, 2026)
+## PREVIOUS SESSIONS (Reverse Chronological)
-### Status: โ
**COMPLETE - Deployed to Production (v2.2.14)**
+### Find Training Tab Reorder, Marker Highlighting & Map Reset โ Feb 9, 2026 (v2.2.17)
+Reordered tabs to Events first (default), added marker highlighting on tab switch (larger/brighter icons, zIndex 100), added map reset button, fixed mobile overflow from long event titles. `9dbe472c`
-**Objective:** Fix mobile scrolling on the Find Training page โ users could not scroll down to see the trainer, venue, and event lists.
+### Mobile Find Training Scroll Fix โ Feb 9, 2026 (v2.2.14)
+Fixed mobile scrolling: switched from fixed-viewport (`100vh; overflow: hidden`) to natural page scrolling on screens โค991px. Sticky filter bar. `4104c806`
-### Issue Found & Fixed
+### Map Tile Drift Fix & Event Cost Display โ Feb 9, 2026 (v2.2.13)
+Fixed Google Maps tile/marker drift at zoom 1-2 by setting `minZoom: 3`. Fixed event cost HTML entities (`$50` โ `$50`) via `html_entity_decode()`. `f123c7a5`
-1. **Mobile Page Not Scrollable** (`assets/css/find-training-map.css`)
- - **Symptom:** On mobile, the Find Training page rendered correctly but users could not scroll down past the map to browse trainer/venue/event cards
- - **Root Cause:** The page used a fixed-viewport layout (`height: 100vh; overflow: hidden`) with nested scrolling. On mobile, the sidebar content area was only 158px tall (out of 940px of content) โ touch scrolling in such a tiny nested region was unreliable/impossible on real phones
- - **Fix:** On screens โค991px, switched from fixed-viewport to natural page scrolling:
- - Page container: `height: auto; overflow: visible` (was `100vh; hidden`)
- - Map layout grid: `overflow: visible`, sidebar row `auto` (was `1fr`)
- - Sidebar: `overflow: visible; max-height: none` (was `hidden; 50vh`)
- - Filter bar: `position: sticky` so it stays visible while scrolling
- - Desktop layout (>991px) unchanged
+### Zoho CRM Sync Production Fix โ Feb 6, 2026 (v2.2.11)
+Fixed silent sync failure: search criteria not sent to Zoho API (GET ignores `$data`), error reporting priority, phone validation, Last_Name fallback. Result: 64/64 trainers syncing. `4c22b9db`
-2. **Version Bump for Cache Busting** (`includes/class-hvac-plugin.php`)
- - Bumped `HVAC_VERSION` and `HVAC_PLUGIN_VERSION` from `2.2.13` to `2.2.14`
+### Zoho CRM Sync Architecture Fix โ Feb 6, 2026
+Fixed "silent failure" architecture: added `validate_api_response()`, hash-only-on-success for all 5 sync methods, staging mode detection via hostname parsing, admin hash reset button. `03b9bce5`
-### Files Modified
+### Near Me Button Mobile Fix โ Feb 6, 2026
+Fixed `.hvac-btn-text` wrapper missing from Near Me button state changes (5 locations). Added empty results notification for Near Me filter.
-| File | Change |
-|------|--------|
-| `assets/css/find-training-map.css` | Mobile layout: natural page scrolling, sticky filter bar, removed overflow constraints |
-| `includes/class-hvac-plugin.php` | Version bump `2.2.13` โ `2.2.14` |
+### Champion Differentiation on Find Training โ Feb 2, 2026
+Added `is_champion` flag, distinct white-outline marker icon, non-clickable sidebar cards (state only), sorted to end of list. 18 champions differentiated from trainers.
-### Verification
+### Tabbed Interface for Find Training โ Feb 1, 2026
+Refactored sidebar from single trainer list to Trainers | Venues | Events tabs with ARIA accessibility, venue/event cards, info modal, context-aware search, visibility toggle dots.
-- โ
Production mobile (375x812): page scrollable, all 42 trainer cards accessible
-- โ
Production mobile: filter bar stays sticky at top while scrolling
-- โ
Production mobile: sidebar content 940px fully visible (was 158px)
-- โ
Production desktop (1400x900): side-by-side layout unchanged, no regression
+### measureQuick Approved Training Labs โ Feb 1, 2026
+Created venue taxonomies (`venue_type`, `venue_equipment`, `venue_amenities`), configured 9 approved labs, filtered map data by taxonomy, enhanced venue modal with equipment/amenities badges and contact form.
+
+### Find Training Page Enhancements โ Feb 1, 2026
+Added viewport sync (sidebar shows only visible-in-map trainers), marker hover info windows, legacy URL redirects (`/find-a-trainer/` โ `/find-training/`).
+
+### Find Training Page Implementation โ Jan 31โFeb 1, 2026
+Built `/find-training` from scratch with Google Maps API replacing buggy MapGeo. 8 new files. Features: markers, clustering, filters, geolocation, modals, contact form, auto-geocoding. Multi-model code review fixed 6 issues (1 critical, 1 high).
+
+### E2E Testing & Bug Fixes โ Feb 1, 2026
+Deployed 12 security fixes, ran E2E tests, fixed empty trainers table (SQL rewrite) and blank event pages (template path mismatch). Added staging email filter.
+
+### Multi-Model Security Code Review โ Jan 31, 2026
+4-model review (GPT-5, Gemini 3, Kimi K2.5, Zen MCP) across 11 files. Found and fixed 12 issues: 2 critical (password transients, O(3600) DoS loop), 4 high, 4 medium, 2 low.
+
+### Master Trainer Profile Edit Enhancement โ Jan 9, 2026
+Fixed button styling, added all 6 profile field sections, added password reset button with AJAX handler.
+
+### TEC Community Events Dependency Analysis โ Jan 5, 2026
+Plugin still relies on TEC CE for event creation. Removal estimated 9-14 days. Deferred as technical debt.
+
+### Zoho Scheduled Sync, Batch Sync, Attendee Sync โ Dec 17-20, 2025
+WP-Cron scheduled sync with configurable intervals, batch pagination with progress bar, attendee/RSVP sync to Zoho Contacts + Campaign Members. 64/64 trainers, 50/50 attendees syncing.
+
+### Earlier Sessions (Nov-Dec 2025)
+Nonce fix (v2.1.7), technical debt cleanup (v2.1.6), z-index fix (v2.1.5), Gemini environment setup, PHP 8+ compatibility, nav dropdown fix, MapGeo interceptor strategy.
---
-## ๐ PREVIOUS SESSION - MAP TILE DRIFT FIX & EVENT COST DISPLAY (Feb 9, 2026)
+## ENVIRONMENTS
-### Status: โ
**COMPLETE - Deployed to Production (v2.2.13)**
+| Environment | URL | Version |
+|-------------|-----|---------|
+| **Production** | https://upskillhvac.com | 2.2.18 |
+| **Staging** | https://upskill-staging.measurequick.com | 2.2.18 |
-**Objective:** Fix Google Maps tile/marker drift at low zoom levels on the Find Training page, and fix event cost display showing HTML entities.
-
-### Issues Found & Fixed
-
-1. **Map Tile/Marker Drift at Low Zoom** (`assets/js/find-training-map.js`)
- - **Symptom:** When zooming out to zoom 1-2, map tiles shifted ~190px right, placing markers over the ocean instead of over the US
- - **Root Cause:** Google Maps WebGL renderer reads viewport width (1400px) instead of container width (1020px) in CSS Grid layouts. Tile drift = exactly `(1400 - 1020) / 2 = 190px`
- - **Attempted fixes that did NOT work:** `google.maps.event.trigger(map, 'resize')`, CSS `contain: layout`, body `display: block` override, map destroy/recreate, `requestAnimationFrame` timing
- - **Fix:** Added `minZoom: 3` to map options - drift is invisible at zoom 3+ but severe at zoom 1-2. Users searching for US HVAC training have no need for world-view zoom levels
- - **Also added:** CSS `max-width: none !important` on Google Maps tile images to prevent theme CSS interference
-
-2. **Event Cost HTML Entities** (`includes/find-training/class-hvac-training-map-data.php`)
- - **Symptom:** Event costs displayed as `$50` instead of `$50` in sidebar cards
- - **Root Cause:** `tribe_get_formatted_cost()` returns HTML-encoded entities, which JS doesn't decode
- - **Fix:** Added `html_entity_decode()` before passing cost to JavaScript
-
-3. **Version Bump for Cache Busting** (`includes/class-hvac-plugin.php`)
- - Bumped `HVAC_VERSION` and `HVAC_PLUGIN_VERSION` from `2.2.11` to `2.2.13`
- - Required because CDN/server-side caching served old JS even after deployment
- - Script enqueue uses `HVAC_VERSION` as query string parameter for cache invalidation
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `assets/js/find-training-map.js` | Added `minZoom: 3` to Google Maps options |
-| `assets/css/find-training-map.css` | Added `max-width: none !important` for Google Maps tile images |
-| `includes/find-training/class-hvac-training-map-data.php` | Added `html_entity_decode()` for event cost display |
-| `includes/class-hvac-plugin.php` | Version bump `2.2.11` โ `2.2.13` |
-
-### Verification
-
-- โ
Staging: `setZoom(1)` correctly clamped to zoom 3
-- โ
Production: `minZoom` option confirmed as 3, zoom clamping verified
-- โ
Production: Map loads at zoom 4 with all 42 trainers, 9 venues, 8 events correctly positioned
-- โ
Production: Zoom out button disables at zoom 3
+**Deploy:** `./scripts/deploy.sh staging` or `./scripts/deploy.sh production`
---
-## ๐ PREVIOUS SESSION - ZOHO CRM SYNC PRODUCTION FIX (Feb 6, 2026)
+## KNOWN ISSUES (Minor)
-### Status: โ
**COMPLETE - Deployed to Production (v2.2.11) - 64/64 Trainers Syncing**
-
-**Objective:** Fix Zoho CRM user sync that was silently failing on production - 0/65 users syncing despite "connection successful" status.
-
-### Issues Found & Fixed (iterative production debugging)
-
-1. **Version Constant Mismatch** (`includes/class-hvac-plugin.php`)
- - `HVAC_PLUGIN_VERSION` stuck at `'2.0.0'` while `HVAC_VERSION` was `'2.2.10'`
- - Admin JS used `HVAC_PLUGIN_VERSION` for cache busting, so browser served old JS without reset handler
- - Fix: Bumped both constants to `'2.2.11'`
-
-2. **GET Request Search Criteria Ignored** (`includes/zoho/class-zoho-sync.php`)
- - `sync_users()` passed search criteria as `$data` parameter to `make_api_request()`
- - But `make_api_request()` ignores `$data` for GET requests (line 345 only includes body for POST/PUT/PATCH)
- - Every Zoho contact search returned unfiltered results, causing all syncs to fail
- - Fix: Moved criteria into URL query string: `/Contacts/search?criteria=(Email:equals:...)`
-
-3. **Error Reporting Priority** (`includes/zoho/class-zoho-sync.php`)
- - `validate_api_response()` checked generic `error` key before Zoho-specific `data[0]` errors
- - Users saw "API error with status code 400" instead of actionable field-level errors
- - Fix: Reordered to check Zoho `data[0]` errors first, added field-level detail (api_name, expected_data_type, info)
-
-4. **Phone Field Validation** (`includes/zoho/class-zoho-sync.php`)
- - Zoho rejects invalid phone formats with HTTP 400
- - Fix: Strip non-digit chars, require 10+ digits, only include Phone field when valid
-
-5. **Last_Name Required Field** (`includes/zoho/class-zoho-sync.php`)
- - Zoho Contacts module requires Last_Name but some WP users had empty last names
- - Fix: Fallback chain: `last_name` meta โ `display_name` โ `user_login`
-
-6. **Spam Account Cleanup** (production WP-CLI)
- - User 14 (`rigobertohugo19`, `info103@noreply0.com`) was a spam/bot registration with no name
- - Demoted from `hvac_trainer` to `subscriber`
-
-### Production Sync Results (iterative)
-
-| Attempt | Synced | Failed | Issue |
-|---------|--------|--------|-------|
-| 1st (pre-fix) | 0 | 65 | Search criteria not sent to Zoho API |
-| 2nd (search fix) | 63 | 2 | Generic "status code 400" errors |
-| 3rd (error detail) | 0 | 2 | User 57: invalid Phone, User 14: missing Last_Name |
-| 4th (data validation) | 31 | 1 | User 57 phone still failing (7-digit threshold too low) |
-| 5th (10-digit threshold) | 26 | 0 | **All 65 trainers synced** |
-| Final (User 14 demoted) | **64/64** | **0** | All active trainers syncing |
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `includes/class-hvac-plugin.php` | Synced `HVAC_PLUGIN_VERSION` to `'2.2.11'` (was stuck at `'2.0.0'`) |
-| `includes/zoho/class-zoho-sync.php` | Search criteria in URL, error priority fix, phone sanitization, Last_Name fallback |
-
-### Git Commits
-- `03b9bce5` - fix(zoho): Fix silent sync failures with API response validation and hash reset
-- `4c22b9db` - fix(zoho): Fix user sync search criteria and improve data validation
+1. Playwright headless login requires headed mode with correct selectors
+2. Brief "jQuery is not defined" console error on page load (non-blocking)
+3. Minor responsive layout issue on dashboard (cosmetic)
---
-## ๐ PREVIOUS SESSION - ZOHO CRM SYNC ARCHITECTURE FIX (Feb 6, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Production**
-
-**Objective:** Fix Zoho CRM integration that appeared connected but was silently failing to sync data (events, attendees, ticket sales not appearing in Zoho CRM).
-
-### Root Cause Analysis (4-model consensus: GPT-5, Gemini 3, Zen Code Review, Zen Debug)
-
-The sync pipeline had a "silent failure" architecture:
-1. **Connection test only uses GET** - bypasses staging write block, giving false confidence
-2. **Staging mode returned fake `'status' => 'success'`** for blocked writes - appeared successful
-3. **Sync methods unconditionally updated `_zoho_sync_hash`** after any "sync" - poisoned hashes
-4. **Subsequent syncs compared hashes, found matches, skipped all records** - permanent data loss
-5. **No API response validation** - even real Zoho errors were silently ignored
-
-### Fixes Implemented
-
-1. **API Response Validation** (`includes/zoho/class-zoho-sync.php`)
- - Added `validate_api_response()` helper method
- - Checks for WP_Error, staging mode blocks, HTTP errors, Zoho error codes
- - Confirms success with ID extraction before treating a sync as successful
-
-2. **Hash-Only-On-Success** (`includes/zoho/class-zoho-sync.php`)
- - All 5 sync methods (events, users, attendees, rsvps, purchases) rewritten
- - `_zoho_sync_hash` only updates when Zoho API confirms the write succeeded
- - Failed syncs increment `$results['failed']` with error details
- - Changed `catch (Exception)` to `catch (\Throwable)` for comprehensive error handling
-
-3. **Staging Mode Detection Fix** (`includes/zoho/class-zoho-crm-auth.php`)
- - Replaced fragile `strpos()` substring matching with `wp_parse_url()` hostname comparison
- - Production (`upskillhvac.com` / `www.upskillhvac.com`) explicitly whitelisted
- - All other hostnames default to staging mode
- - `HVAC_ZOHO_PRODUCTION_MODE` / `HVAC_ZOHO_STAGING_MODE` constants can override
- - Staging fake responses now return `'skipped_staging'` instead of misleading `'success'`
-
-4. **Admin UI: Hash Reset & Staging Warning** (`includes/admin/class-zoho-admin.php`, `assets/js/zoho-admin.js`)
- - Added `reset_sync_hashes()` AJAX handler - clears all `_zoho_sync_hash` from postmeta and usermeta
- - Added "Force Full Re-sync (Reset Hashes)" button with confirmation dialog
- - Connection test now surfaces staging warning when staging mode is active
-
-5. **Staging Environment Fix** (staging `wp-config.php`)
- - Removed `HVAC_ZOHO_PRODUCTION_MODE` constant from staging wp-config.php
- - Staging now correctly blocks all Zoho write operations via hostname detection
- - GET requests (reads) still pass through for testing
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `includes/zoho/class-zoho-sync.php` | Added `validate_api_response()`, rewrote all 5 sync methods for validated hashing |
-| `includes/zoho/class-zoho-crm-auth.php` | Rewrote `is_staging_mode()` with hostname parsing, changed fake response status |
-| `includes/admin/class-zoho-admin.php` | Added `reset_sync_hashes()` handler, reset button HTML, staging warning in connection test |
-| `assets/js/zoho-admin.js` | Added reset hashes button handler, staging warning display in connection test |
-
----
-
-## ๐ PREVIOUS SESSION - NEAR ME BUTTON MOBILE FIX (Feb 6, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Staging**
-
-**Objective:** Fix mobile layout issue where the "Near Me" button caused the search bar to shrink when location was granted.
-
-### Issues Found & Fixed
-
-1. โ
**CSS/HTML Button Structure Bug** (`assets/js/find-training-filters.js`)
- - When the Near Me button state changed, the HTML was replaced without the `.hvac-btn-text` wrapper class
- - On mobile, CSS hides `.hvac-btn-text`, but unwrapped text was visible causing layout issues
- - Fixed in 5 locations: loading state, success state, error reset, clear filters, remove location filter
-
-2. โ
**No Feedback for Empty Results** (`assets/js/find-training-filters.js`)
- - When "Near Me" filter returned no results within 100km, user saw empty map with no explanation
- - Added notification: "No trainers, venues, or events found within 100km of your location. Try removing the 'Near Me' filter to see all results."
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `assets/js/find-training-filters.js` | Fixed button HTML to preserve `.hvac-btn-text` wrapper; added empty results notification |
-
-### Code Changes
-
-**Button HTML Fix (5 locations):**
-```javascript
-// Before (broken on mobile):
-$button.html(' Near Me');
-
-// After (correct):
-$button.html('Near Me');
-```
-
-**Empty Results Notification:**
-```javascript
-if (self.userLocation) {
- const totalResults = HVACTrainingMap.trainers.length +
- HVACTrainingMap.venues.length +
- HVACTrainingMap.events.length;
- if (totalResults === 0) {
- self.showLocationError('No trainers, venues, or events found within 100km...');
- }
-}
-```
-
-### Mobile Testing Performed
-- โ
375x812 (iPhone X) - Map and markers display correctly
-- โ
320x568 (iPhone SE) - Map and markers display correctly
-- โ
Cluster markers expand on click
-- โ
Individual trainer markers clickable
-- โ
Info windows display correctly
-- โ
Profile modal opens and displays correctly
-
----
-
-## ๐ PREVIOUS SESSION - CHAMPION DIFFERENTIATION ON FIND TRAINING (Feb 2, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Production**
-
-**Objective:** Differentiate measureQuick Certified Champions from Trainers on the Find Training map. Champions do not offer public training, so they should be displayed differently.
-
-### Changes Made
-
-1. โ
**Backend Data** (`includes/find-training/class-hvac-training-map-data.php`)
- - Added `is_champion` flag for trainers with "Certified measureQuick Champion" certification
- - Champions return empty `city` field (only state shown)
-
-2. โ
**Champion Marker Icon** (`assets/js/find-training-map.js`)
- - Added `getChampionIcon()` method with white outline (vs green for Trainers)
- - Champions use distinct visual appearance on map
-
-3. โ
**Sidebar Cards** (`assets/js/find-training-map.js`)
- - Champions show only state (e.g., "Ohio" not "Canton, Ohio")
- - Champions have non-clickable cards (no modal popup)
- - Added `hvac-champion-card` CSS class
-
-4. โ
**Info Windows** (`assets/js/find-training-map.js`)
- - Champions show only state in location
- - No "View Profile" button for Champions
- - Fixed location formatting to handle empty city gracefully
-
-5. โ
**Sorting** (`assets/js/find-training-map.js`)
- - Champions sorted to end of trainer list
- - Secondary sort by name for stable ordering
- - Applied to both `loadMapData` and `loadTrainerDirectory`
-
-6. โ
**CSS Styling** (`assets/css/find-training-map.css`)
- - Champion cards have non-clickable appearance
- - No hover effects (cursor: default, no transform/shadow)
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `includes/find-training/class-hvac-training-map-data.php` | Added `is_champion` flag, empty city for champions |
-| `assets/js/find-training-map.js` | Champion icon, card display, click prevention, sorting |
-| `assets/css/find-training-map.css` | Champion card non-clickable styling |
-
-### Verification (Staging)
-- โ
API returns `is_champion: true` for 18 champions
-- โ
Champions have empty city in API response
-- โ
Champions sorted to end of list
-- โ
Champion cards show only state
-- โ
Clicking champion card does NOT open modal
-- โ
Clicking trainer card DOES open modal (regression test)
-
-### Code Review Findings (Gemini 3)
-- **Fixed:** Location formatting bug - empty city could show ", California"
-- **Fixed:** Unstable sort order - added secondary sort by name
-
----
-
-## ๐ PREVIOUS SESSION - TABBED INTERFACE FOR FIND TRAINING (Feb 1, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Production**
-
-**Objective:** Refactor the Find Training page sidebar from a single trainer list to a tabbed interface with Trainers, Venues, and Events tabs.
-
-### Changes Made
-
-1. โ
**Tab Navigation System** (`templates/page-find-training.php`)
- - Replaced "42 trainers" header with three tabs: Trainers | Venues | Events
- - Each tab displays dynamic count in parentheses
- - ARIA accessibility attributes (role="tablist", role="tab", aria-selected)
- - Keyboard navigation (arrow keys, Home, End)
-
-2. โ
**Visibility Toggles Relocated**
- - Moved from map overlay to sidebar header
- - Colored dots (teal/orange/purple) match marker colors
- - Only control map marker visibility, not tab content
-
-3. โ
**Venue Cards** (`assets/js/find-training-map.js`)
- - Name with building icon
- - City, State location
- - "X upcoming events" count
-
-4. โ
**Event Cards** (`assets/js/find-training-map.js`)
- - Date badge showing month/day
- - Event title
- - Venue name
- - Cost display
- - "Past" badge for past events
-
-5. โ
**Info Modal** (`templates/page-find-training.php`)
- - "What is Upskill HVAC?" section
- - "How to Use" instructions
- - Map Legend (trainer/venue/event markers)
-
-6. โ
**Context-Aware Search** (`assets/js/find-training-filters.js`)
- - Placeholder changes based on active tab
- - Client-side filtering for instant results (150ms debounce)
- - Falls back to server-side when filters active
-
-7. โ
**CSS Styling** (`assets/css/find-training-map.css`)
- - Tab navigation container and button styles
- - Venue card and event card layouts
- - Info button and modal styling
- - Responsive adjustments for tablet/mobile
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `templates/page-find-training.php` | Tab navigation, panels, info modal |
-| `assets/js/find-training-map.js` | Tab switching, card creators, grid renderers |
-| `assets/js/find-training-filters.js` | Context-aware search, client-side filtering |
-| `assets/css/find-training-map.css` | ~300 lines new CSS for tabs, cards, modal |
-| `includes/class-hvac-plugin.php` | Version bump 2.2.5 โ 2.2.6 (CDN cache bust) |
-
-### Issue Resolved: CDN Cache
-
-**Problem:** After deployment, browser loaded old JavaScript without new `initTabs` method.
-
-**Root Cause:** CDN cached old assets. Deploy script clears WP/OPcache but not CDN edge cache.
-
-**Fix:** Bumped `HVAC_VERSION` from 2.2.5 to 2.2.6, changing script URL query string to force cache refresh.
-
-### Verified on Staging
-- โ
42 trainers tab count
-- โ
9 venues tab count
-- โ
8 events tab count
-- โ
Tab switching works with proper ARIA attributes
-- โ
Venue cards display correctly
-- โ
Event cards with date badges display correctly
-- โ
Info modal opens and displays content
-- โ
Visibility toggles control map markers
-
----
-
-## ๐ PREVIOUS SESSION - MEASUREQUICK APPROVED TRAINING LABS (Feb 1, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Staging, Venues Displaying Correctly**
-
-**Objective:** Transform /find-training to showcase only measureQuick Approved Training Labs with venue categories, equipment/amenities tags, and contact forms.
-
-1. โ
**Venue Taxonomies Created** (`includes/class-hvac-venue-categories.php` NEW)
- - `venue_type` - For lab classification (e.g., "measureQuick Approved Training Lab")
- - `venue_equipment` - Furnace, Heat Pump, AC, Mini-Split, Boiler, etc.
- - `venue_amenities` - Coffee, Water, Projector, WiFi, Parking, etc.
- - All taxonomies registered on `tribe_venue` post type
-
-2. โ
**9 Approved Training Labs Configured** (via WP-CLI script)
- - Fast Track Learning Lab (ID: 6631) - Joe Medosch
- - Progressive Training Lab (ID: 6284) - Samantha Brazie
- - NAVAC Technical Training Center (ID: 6476) - Andrew Greaves
- - Stevens Equipment Supply - Phoenix (ID: 6448) - Robert Cone
- - San Jacinto College South Campus (ID: 6521) - Terry McWilliams
- - Johnstone Supply - Live Fire Training Lab (ID: 4864) - Dave Petz
- - Stevens Equipment Supply - Johnstown (ID: 1648) - Phil Sweren
- - TruTech Tools Training Center (NEW) - Val Buckles
- - Auer Steel & Heating Supply (NEW) - Mike Breen
-
-3. โ
**Map Data Filtered by Taxonomy**
- - `get_venue_markers()` now includes `tax_query` for `mq-approved-lab` term
- - Only approved training labs appear as venue markers
- - Equipment, amenities, and POC data included in venue info
-
-4. โ
**Venue Modal Enhanced**
- - Equipment badges (teal outline chips)
- - Amenities badges (gray outline chips)
- - Contact form with name, email, phone, company, message
- - POC receives email notification on submission
-
-5. โ
**6 POC Trainer Accounts Created**
- - Samantha Brazie, Andrew Greaves, Terry McWilliams
- - Phil Sweren, Robert Cone, Dave Petz
- - All with `hvac_trainer` role and approved status
-
-### Files Created
-
-| File | Description |
-|------|-------------|
-| `includes/class-hvac-venue-categories.php` | Venue taxonomy registration (singleton) |
-| `scripts/setup-approved-labs.php` | WP-CLI script to configure all labs |
-| `scripts/check-venue-coordinates.php` | Diagnostic script to verify venue coordinates |
-| `scripts/geocode-approved-labs.php` | Geocode venues missing coordinates |
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `includes/class-hvac-plugin.php` | Load venue categories class |
-| `includes/find-training/class-hvac-training-map-data.php` | Add tax_query filter, include equipment/amenities |
-| `includes/class-hvac-ajax-handlers.php` | Add venue contact form AJAX handler |
-| `templates/page-find-training.php` | Add equipment/amenities badges, contact form |
-| `assets/js/find-training-map.js` | Render badges, bind contact form handler |
-| `assets/css/find-training-map.css` | Equipment/amenities badge styles |
-
-### Issue Resolved: Venues Now Displaying on Map โ
-
-**Root Cause:** `venue_type` taxonomy wasn't being registered when `get_venue_markers()` ran.
-
-`HVAC_Venue_Categories::instance()` was instantiated at 'init' priority 5, but then tried to add hooks to 'init' priority 5 for taxonomy registration. Since WordPress was already processing priority 5 handlers, the hook never fired.
-
-**Fix Applied:**
-1. **`includes/class-hvac-venue-categories.php`** - Added `did_action('init')` check in constructor
- - If 'init' has already fired, call `register_taxonomies()` and `create_default_terms()` directly
- - Otherwise, use the standard hook approach
-
-2. **`includes/find-training/class-hvac-training-map-data.php`** - Fixed HTML entity encoding
- - Venue names now use `html_entity_decode()` to properly display `&` and `โ` characters
- - Event titles also fixed
-
-**Result:**
-- โ
All 9 approved training labs now display as orange venue markers on the map
-- โ
Venue names display correctly (e.g., "Auer Steel & Heating Supply" not "Auer Steel &...")
-- โ
Marker clustering works with mixed trainer/venue markers
-
----
-
-## ๐ PREVIOUS SESSION - FIND TRAINING PAGE ENHANCEMENTS (Feb 1, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Production**
-
-**Objective:** Improve Find Training page UX with viewport sync and marker hover interactions.
-
-### Changes Made
-
-1. โ
**Viewport Sync** - Sidebar now shows only trainers visible in current map area
- - Added `visibleTrainers` array to track filtered trainers
- - Added `syncSidebarWithViewport()` method filtering by map bounds
- - Map `idle` event triggers sync on pan/zoom
- - Count shows "X of Y trainers" when zoomed in
-
-2. โ
**Marker Hover Interaction** - Info window appears on hover
- - Added `mouseover` event listener to trainer/venue markers
- - Set `optimized: false` on markers for reliable hover events
- - Hover shows info window preview with "View Profile" button
- - Click on "View Profile" opens full modal with contact form
-
-3. โ
**Legacy URL Redirects**
- - `/find-a-trainer/` โ `/find-training/` (301 redirect)
- - `/find-trainer/` โ `/find-training/` (301 redirect)
- - Removed old page from Page Manager
-
-### Files Modified
-
-| File | Change |
-|------|--------|
-| `assets/js/find-training-map.js` | Added viewport sync, hover events, optimized:false |
-| `assets/js/find-training-filters.js` | Updated filter handler for visibleTrainers |
-| `includes/class-hvac-route-manager.php` | Added legacy URL redirects |
-| `includes/class-hvac-page-manager.php` | Removed find-a-trainer page definition |
-| `includes/class-hvac-plugin.php` | Version bumped to 2.2.4 |
-
-### Verified Behavior
-- โ
Hover over marker โ Info window appears immediately
-- โ
Click "View Profile" โ Full modal with trainer details + contact form
-- โ
Pan/zoom map โ Sidebar updates to show visible trainers only
-- โ
Legacy URLs redirect to new page
-
----
-
-## ๐ PREVIOUS SESSION - FIND TRAINING PAGE IMPLEMENTATION (Jan 31 - Feb 1, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Production**
-
-**Objective:** Replace the buggy MapGeo-based `/find-a-trainer` page with a new `/find-training` page built from scratch using Google Maps JavaScript API.
-
-### Why This Change
-The existing IGM/amCharts implementation had a fundamental bug that corrupted marker coordinates (longitude gets overwritten with latitude). After multiple fix attempts, building fresh with Google Maps API provides:
-- Full control over marker data
-- No third-party plugin dependencies
-- Better long-term maintainability
-- Ability to show both trainers AND venues
-
-### Files Created (8 new files)
-
-| File | Description |
-|------|-------------|
-| `includes/find-training/class-hvac-find-training-page.php` | Main page handler (singleton), AJAX endpoints, asset enqueuing |
-| `includes/find-training/class-hvac-training-map-data.php` | Data provider for trainer/venue markers with caching |
-| `includes/find-training/class-hvac-venue-geocoding.php` | Auto-geocoding for TEC venues via Google API |
-| `templates/page-find-training.php` | Page template with map, filters, modals |
-| `assets/js/find-training-map.js` | Google Maps initialization, markers, clustering |
-| `assets/js/find-training-filters.js` | Filter handling, geolocation, AJAX |
-| `assets/css/find-training-map.css` | Complete responsive styling |
-| `assets/images/marker-trainer.svg` | Teal person icon for trainers |
-| `assets/images/marker-venue.svg` | Orange building icon for venues |
-
-### Files Modified (3 files)
-
-| File | Change |
-|------|--------|
-| `includes/class-hvac-page-manager.php` | Added find-training page definition |
-| `includes/class-hvac-plugin.php` | Load new find-training classes |
-| `includes/class-hvac-ajax-handlers.php` | Added contact form AJAX handler |
-
-### Multi-Model Code Review Findings & Fixes
-
-Ran comprehensive code review using GPT-5, Gemini 3, and Zen MCP tools. Found and fixed 6 issues:
-
-| # | Severity | Issue | Fix |
-|---|----------|-------|-----|
-| 1 | **CRITICAL** | Missing `hvac_submit_contact_form` AJAX handler | Added full handler with rate limiting, validation, email |
-| 2 | **HIGH** | XSS risk in InfoWindow onclick handlers | Replaced with DOM creation + addEventListener |
-| 3 | **MEDIUM** | Uncached filter dropdown SQL queries | Added wp_cache with 1-hour TTL |
-| 4 | **MEDIUM** | AJAX race condition on rapid filters | Added request abort handling |
-| 5 | **LOW** | Hardcoded `/trainer/registration/` URL | Changed to `site_url()` |
-| 6 | **LOW** | `alert()` for geolocation errors | Added inline dismissible notification |
-
-### Features Implemented
-
-- โ
Google Maps with custom trainer/venue markers
-- โ
MarkerClusterer for dense areas
-- โ
Filter by State, Certification, Training Format
-- โ
Search by name/location
-- โ
"Near Me" geolocation button
-- โ
Trainer/Venue toggle switches
-- โ
Trainer profile modal with contact form
-- โ
Venue info modal with upcoming events
-- โ
Trainer directory grid below map
-- โ
301 redirect from `/find-a-trainer` to `/find-training`
-- โ
Auto-geocoding for new venues
-- โ
Rate-limited batch geocoding for existing venues
-
-### Deployment Status
-- โ
Deployed to staging
-- โ
Map loads with markers and clustering
-- โ
Filters working (state, certification, format)
-- โ
Contact form functional
-- โ
Deployed to production
-
----
-
-## ๐ PREVIOUS SESSION - E2E TESTING & BUG FIXES (Feb 1, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Staging, Ready for Production**
-
-**Objective:** Deploy security fixes to staging, run E2E tests, fix discovered bugs, and validate all functionality.
-
-### Deployment & Testing Summary
-
-1. โ
**Deployed to Staging** - All 12 security fixes from previous session
-2. โ
**E2E Tests Passed** - Master trainer pages, security endpoints verified
-3. โ
**Discovered & Fixed 2 Critical Bugs** - Trainers table, event pages
-4. โ
**Created E2E Testing Skill** - `.claude/commands/e2e-visual-test.md`
-5. โ
**Added Staging Email Filter** - Prevents accidental user spam
-
-### Bugs Found & Fixed
-
-| Bug | Severity | Root Cause | Fix |
-|-----|----------|------------|-----|
-| **Trainers table empty** | HIGH | `ajax_filter_trainers()` used complex SQL that returned empty; `count_trainers_by_status()` only queried `hvac_trainer` role | Rewrote to use `get_trainers_table_data()` (same as working dashboard); fixed role query to include both roles |
-| **Event pages blank** | HIGH | Template path mismatch: code referenced `page-trainer-event-manage.php` but file is `page-manage-event.php` | Fixed path in `class-hvac-event-manager.php:138` |
-
-### Files Modified (4 files)
-
-1. **`includes/class-hvac-master-trainers-overview.php`**
- - Rewrote `ajax_filter_trainers()` to use reliable `get_trainers_table_data()`
- - Fixed `count_trainers_by_status()` to include `hvac_master_trainer` role
- - Now shows 53 trainers, 5 active (was showing 0)
-
-2. **`includes/class-hvac-event-manager.php`**
- - Fixed template path: `page-trainer-event-manage.php` โ `page-manage-event.php`
- - Event creation form now fully functional
-
-3. **`hvac-community-events.php`**
- - Added staging email filter (only `ben@tealmaker.com` receives emails)
- - Protects real users from test emails during development
-
-4. **`.claude/commands/e2e-visual-test.md`** (new)
- - Created E2E visual testing skill for Playwright MCP browser tools
- - Documents login procedure, test sequence, credentials
-
-### E2E Test Results
-
-| Feature | Status | Notes |
-|---------|--------|-------|
-| Master Trainer Login | โ
PASS | Custom `/training-login/` works |
-| Master Dashboard | โ
PASS | Stats, tables, AJAX functional |
-| Trainers Table | โ
PASS | 53 trainers displayed correctly |
-| Announcements | โ
PASS | Modal opens, form accessible |
-| Event Creation | โ
PASS | Full form with all TEC fields |
-| Certificate Reports | โ
PASS | Empty state (needs events) |
-| Security Endpoints | โ
PASS | 4/4 properly return 401/400 |
-
-### Staging Email Protection
-
-Emails on staging are now filtered:
-- **Allowed:** `ben@tealmaker.com`, `ben@measurequick.com`
-- **Blocked:** All other recipients (logged for debugging)
-- **Subject Prefix:** `[STAGING]` added to allowed emails
-
-### Next Steps
-1. โณ Deploy to production: `./scripts/deploy.sh production`
-2. โณ Verify production functionality
-3. โณ Monitor for any issues
-
----
-
-## ๐ PREVIOUS SESSION - MULTI-MODEL SECURITY CODE REVIEW (Jan 31, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Staging**
-
-**Objective:** Comprehensive security and business logic code review using 4 AI models (GPT-5, Gemini 3, Kimi K2.5, Zen MCP) across 11 critical files (~9,000 lines).
-
-### Critical Issues Found & Fixed (12 total)
-
-| ID | Severity | Issue | File |
-|----|----------|-------|------|
-| C1 | **CRITICAL** | Passwords stored in transients | `class-hvac-registration.php` |
-| U1 | **CRITICAL** | O(3600) token verification loop (DoS) | `class-hvac-ajax-security.php` |
-| U2 | **HIGH** | `remove_all_actions()` breaks WP isolation | `class-hvac-plugin.php` |
-| C2 | **HIGH** | Encryption key in same database as data | `class-hvac-secure-storage.php` |
-| M3 | **HIGH** | Revoked certificates still downloadable | `class-certificate-manager.php` |
-| U3 | **HIGH** | Security headers not applied to AJAX | `class-hvac-ajax-security.php` |
-| C3 | **MEDIUM** | IP spoofing undermines rate limiting | `class-hvac-security.php` |
-| M1 | **MEDIUM** | Weak CSP with `unsafe-eval` | `class-hvac-ajax-security.php` |
-| C5 | **MEDIUM** | Duplicate component initialization | `class-hvac-plugin.php` |
-| U9 | **MEDIUM** | File-scope side-effect initialization | `class-hvac-trainer-profile-manager.php` |
-| U11 | **LOW** | Timezone inconsistency in cert numbers | `class-certificate-manager.php` |
-| U4 | **HIGH** | zoho-config.php not in .gitignore | `.gitignore` |
-
-### Deliverables
-- โ
**Full Report:** `MULTI-MODEL-CODE-REVIEW-REPORT.md`
-- โ
**12 Security Fixes:** All implemented and deployed to staging
-
----
-
-## ๐ PREVIOUS SESSION - MASTER TRAINER PROFILE EDIT ENHANCEMENT (Jan 9, 2026)
-
-### Status: โ
**COMPLETE - Deployed to Production**
-
-**Objective:** Fix broken button styling and add all trainer profile fields to the master trainer profile edit page.
-
-**Issues Fixed:**
-1. **Button Styling Broken** - "Back to Dashboard" and "Cancel" buttons appeared faded/invisible due to CSS conflicts with theme
-2. **Missing Profile Fields** - Only showing basic name fields, needed all trainer profile fields
-3. **No Password Reset** - Master trainers couldn't trigger password resets for trainers they manage
-
-### Changes Made
-
-1. โ
**Fixed Button Styling** (`templates/page-master-trainer-profile-edit-simple.php`)
- - Added scoped CSS with new class names (`hvac-btn-primary`, `hvac-btn-secondary`, `hvac-btn-outline`)
- - Avoids theme CSS conflicts by using page-specific selectors
- - Proper colors, hover states, and responsive behavior
-
-2. โ
**Added All Profile Fields** (6 complete sections)
- - **Profile Settings:** Visibility (Public/Private)
- - **Certification Information:** Status, Type, Date Certified
- - **Personal Information:** Name, Email, LinkedIn URL, Bio
- - **Professional Information:** Accreditation, Training Audience/Formats/Locations/Resources (checkboxes)
- - **Business Information:** Business Type, Revenue Target, Application Details
- - **Location Information:** City, State, Country, Coordinates with re-geocode button
-
-3. โ
**Added Password Reset Button**
- - New "Send Password Reset Email" button in Personal Information section
- - Uses WordPress built-in `retrieve_password()` function
- - Shows status feedback (Sending... / Sent! / Error)
- - Requires master trainer or admin permissions
- - All actions logged for audit trail
-
-4. โ
**Added AJAX Handler** (`includes/class-hvac-ajax-handlers.php`)
- - New `hvac_send_password_reset` endpoint
- - Nonce verification, permission checks, input validation
- - Secure implementation using WordPress core functions
-
-### Files Modified
-- `templates/page-master-trainer-profile-edit-simple.php` - Complete rewrite with all fields
-- `includes/class-hvac-ajax-handlers.php` - Added password reset handler
-
-### URLs
-- **Production:** `https://upskillhvac.com/master-trainer/edit-trainer-profile/?user_id=75`
-- **Staging:** `https://upskill-staging.measurequick.com/master-trainer/edit-trainer-profile/?user_id=75`
-
----
-
-## ๐ PREVIOUS SESSION - TEC COMMUNITY EVENTS DEPENDENCY ANALYSIS (Jan 5, 2026)
-
-### Status: โ
**COMPLETE - Documented as Technical Debt**
-
-**Objective:** Analyze whether "The Events Calendar: Community" (TEC CE) plugin is still being used after recent refactoring.
-
-**Findings:**
-- The plugin **still actively relies on TEC CE** for event creation/editing
-- Core shortcode `[tribe_community_events]` is used in 7 template/class files
-- TEC CE hooks are used for field processing and form customization
-- `HVAC_Event_Manager` has custom CRUD capabilities but production paths use TEC CE
-
-**Removal Scope:**
-- **Estimated effort:** 9-14 days of development
-- **Key work:** Custom forms, date pickers, validation, template updates, testing
-- **Risk:** Recurring events complexity, Event Tickets integration
-
-**Decision:** Deferred as technical debt. Current implementation is functional and stable.
-
-### Deliverables
-1. โ
**Analysis Report:** `docs/reports/TEC-COMMUNITY-EVENTS-DEPENDENCY-ANALYSIS.md`
-2. โ
**CLAUDE.md Updated:** Added Technical Debt section
-3. โ
**Status.md Updated:** This entry
-
----
-
-## ๐ PREVIOUS SESSION - SCHEDULED SYNC PERSISTENCE FIX (Dec 20, 2025)
-
-### Status: โ
**COMPLETE - Deployed to Production**
-
-**Problem:** Scheduled sync showed "Not Scheduled" after page refresh, even though settings were saved correctly.
-
-**Root Cause:**
-- `HVAC_Zoho_Scheduled_Sync` was only loaded in admin context
-- On non-admin requests (including WP-Cron), custom cron schedules weren't registered
-- WordPress was clearing cron events because it didn't recognize the schedules
-
-### Fixes Applied
-1. โ
**Load Scheduled Sync on ALL Requests** (`class-hvac-plugin.php`)
- - Moved `HVAC_Zoho_Scheduled_Sync::instance()` initialization to main plugin loader
- - Now loads alongside other schedulers (like Communication Scheduler)
- - Ensures cron schedules and action hooks are always registered
-
-2. โ
**Add `add_option` Hook** (`class-zoho-scheduled-sync.php`)
- - Added `add_option_hvac_zoho_auto_sync` hook for first-time setting creation
- - WordPress fires `add_option_` (not `update_option_`) on first save
-
-3. โ
**Explicit Scheduling in Save** (`class-zoho-admin.php`)
- - `save_settings()` now explicitly calls `schedule_sync()` or `unschedule_sync()`
- - Ensures scheduling works even when option value hasn't changed
- - `update_option_` hook only fires when value actually changes
-
-### Files Modified
-- `includes/class-hvac-plugin.php` - Load scheduled sync globally
-- `includes/zoho/class-zoho-scheduled-sync.php` - Add first-time option hook
-- `includes/admin/class-zoho-admin.php` - Explicit scheduling call
-
----
-
-## ๐ PREVIOUS SESSION - PUBLIC MAP & DIRECTORY FIX (Dec 21, 2025)
-
-### Status: ๐ **IN PROGRESS - Deployed to Staging (Strategy H)**
-
-**Problem:** Map markers missing. Data analysis reveals markers have identical Latitude and Longitude values (corruption).
-
-**Root Cause:**
-- IGM Plugin's client-side processing corrupts `longitude` by overwriting it with `latitude` immediately before rendering.
-- Previous PHP Injection strategies (D-G) caused 500 errors due to `WP_Query` timing/context issues in the footer.
-
-**Solution (Strategy H):**
-1. โ
**Javascript Interceptor:** Injected a robust interceptor script in `class-hvac-mapgeo-integration.php`.
-2. โ
**Mechanism:** Uses `Object.defineProperty` on `window.iMapsData` to catch the data assignment *before* the map plugin sees it.
-3. โ
**Repair Logic:** Detects corrupted markers (Lat == Lng) and instantly restores correct values from safe `lat`/`lng` backup keys provided by PHP.
-4. โ
**Cleanup:** Removed dangerous PHP query injections that were causing server errors.
-
-**Current Status:**
-- Fix deployed to Staging.
-- Pending verification of visible markers and "Healed" console logs.
-
-**Next Steps:**
-1. Verify map renders correctly on Staging.
-2. Deploy to Production.
-
-
----
-
-## ๐ PREVIOUS SESSION - SCHEDULED ZOHO SYNC (Dec 19, 2025)
-
-### Status: โ
**COMPLETE - WP-Cron Scheduled Sync Implemented**
-
-**Summary:**
-- **Scheduled Sync:** WP-Cron job syncs new/modified records on configurable interval
-- **Incremental Sync:** Only syncs records modified since last sync run
-- **Admin UI:** Enable/disable toggle, interval selector (5min-daily), status display
-- **Manual Trigger:** "Run Sync Now" button for testing
-
-### Changes Made
-1. โ
**New File: `class-zoho-scheduled-sync.php`**
- - WP-Cron management with custom intervals
- - `run_scheduled_sync()` processes all data types
- - Tracks last sync time for incremental filtering
- - Stores results for status display
-
-2. โ
**Updated `class-zoho-sync.php`**
- - All 5 sync methods now accept `$since_timestamp` parameter
- - When provided, filters queries by `post_modified >= since_date`
-
-3. โ
**Updated `class-zoho-admin.php`**
- - Added `save_settings()` AJAX handler
- - Added `run_scheduled_sync_now()` AJAX handler
- - Enhanced admin UI with new intervals and status display
-
-4. โ
**Updated `zoho-admin.js`**
- - Settings form reloads page on save
- - "Run Sync Now" button with result display
-
-### Interval Options
-| Value | Frequency |
-|-------|-----------|
-| `every_5_minutes` | Every 5 minutes (default) |
-| `every_15_minutes` | Every 15 minutes |
-| `every_30_minutes` | Every 30 minutes |
-| `hourly` | Hourly |
-| `every_6_hours` | Every 6 hours |
-| `daily` | Daily |
-
-### Admin Page Location
-- `/wp-admin/admin.php?page=hvac-zoho-sync`
-- Look for "Scheduled Sync Settings" section
-
----
-
-## ๐ PREVIOUS SESSION - BATCH SYNC ENHANCEMENT (Dec 18, 2025)
-
-### Status: โ
**COMPLETE - All Sync Tasks Now Auto-Iterate with Progress Bar**
-
-**Summary:**
-- **All 5 Sync Types:** Now support batch pagination with auto-continue
-- **Progress Bar:** Visual feedback showing `X of Y processed (N%)`
-- **No Manual Repeating:** Frontend auto-loops until `has_more: false`
-- **Orphan Cleanup:** Deleted 14 test attendees referencing deleted events
-
-### Changes Made
-1. โ
**Backend Pagination:**
- - All sync methods (`sync_events`, `sync_users`, `sync_attendees`, `sync_rsvps`, `sync_purchases`) now accept `$offset` and `$limit` parameters
- - Each returns `has_more`, `next_offset`, and `total` for pagination
- - Admin endpoint updated to pass offset to sync methods
-2. โ
**Frontend Progress UI:**
- - New `syncWithProgress()` function replaces single AJAX calls
- - Auto-continues batches until complete
- - Progress bar shows percentage and count
- - Accumulated results across all batches
-
-### Files Modified
-- `includes/zoho/class-zoho-sync.php` - Pagination for all 5 sync methods
-- `includes/admin/class-zoho-admin.php` - Offset parameter handling
-- `assets/js/zoho-admin.js` - Progress bar + auto-continue logic
-
----
-
-## ๐ PREVIOUS SESSION - ZOHO CRM ATTENDEE SYNC (Dec 17-18, 2025)
-
-### Status: โ
**COMPLETE - All Attendees Syncing Successfully**
-
-**Summary:**
-- **Events Sync:** โ
WORKING. 39 events synced with enhanced field mapping.
-- **Attendees Sync:** โ
WORKING. 50/50 synced, 0 errors, all contacts updated with custom fields.
-
-### Issues Resolved
-1. โ
**Campaign Member Linking:**
- - Fixed API endpoint: `PUT /Contacts/{id}/Campaigns` (was `/Campaigns/{id}/Contacts/{id}`)
- - Fixed `log_debug()` visibility (private โ public)
-2. โ
**Attendee Field Mapping:**
- - measureQuick Email โ `Email` (primary, used for lookup)
- - Attendee Email โ `Secondary_Email`
- - Attendee Cell Phone โ `Mobile`
- - Company Role โ `Primary_Role`
- - Fixed meta key: `_tec_tickets_commerce_attendee_fields` with hyphenated field names
-3. โ
**Email Fallback Logic:**
- - If attendee email empty, use measureQuick email (and vice versa)
- - Only fails if BOTH emails are empty
-4. โ
**DUPLICATE_DATA Handling:**
- - When Zoho returns "duplicate exists", extract existing contact ID from error
- - Use that ID to update instead of failing
-5. โ
**Existing Contact Updates:**
- - Existing contacts now updated via PUT with new field data on each sync
-
----
-
-
-### Zoho CRM Integration - Staging Environment (Working)
-
-**Status:** โ
OAuth Working, Sync Methods Implemented, Dry-Run Tested
-
-**Completed:**
-
-1. โ
**OAuth Authentication Verified**
- - Refresh token exists and is valid
- - API connection successful (53 modules accessible)
- - Read operations working (Contacts, Campaigns, Users)
-
-2. โ
**Read-Only API Tests Passed**
- - Organization Info: Manifold Cloud Services (America/Detroit)
- - Contacts: 5+ records readable (Tanner Moore, Pete Knochelmann, etc.)
- - Campaigns: 5+ records readable (Nov 28, Oct 23, etc.)
- - CRM Users: Ben Reed (CEO), JR Lawhorne (Manager), etc.
-
-3. โ
**Sync Class Bug Fixes**
- - Fixed user roles: `trainer`/`trainee` โ `hvac_trainer`/`hvac_master_trainer`
- - Fixed event filter: Removed restrictive `_hvac_event_type` meta query
- - Fixed event display: Changed `eventDisplay` from `list` to `custom` to include past events
- - Fixed WooCommerce dependency: Added graceful error handling
-
-4. โ
**Event Tickets Integration (NEW)**
- - Replaced WooCommerce sync with Event Tickets (Tickets Commerce) support
- - Added `sync_attendees()` method โ Zoho Contacts + Campaign Members
- - Added `sync_rsvps()` method โ Zoho Leads + Campaign Members
- - Updated meta keys for Tickets Commerce (`_tec_tickets_commerce_*`)
- - Updated meta keys for RSVPs (`_tribe_rsvp_*`)
-
-5. โ
**Admin Interface Updated**
- - Added "Sync Attendees" button (Contacts + Campaign Members)
- - Added "Sync RSVPs" button (Leads + Campaign Members)
- - Renamed "Sync Purchases" to "Sync Orders" (Tickets Commerce)
-
-**Dry-Run Results (Staging - No Data Sent to Zoho):**
-| Sync Type | Records Found | Status |
-|-----------|---------------|--------|
-| Events โ Campaigns | 20 | โ
Ready |
-| Trainers โ Contacts | 53 | โ
Ready |
-| Attendees โ Contacts + Campaign Members | 79 | โ
Ready |
-| RSVPs โ Leads + Campaign Members | 4 | โ
Ready |
-| Orders โ Invoices | 52 | โ
Ready |
-
-**Zoho CRM Mapping Strategy:**
-- **Events** โ **Campaigns** (direct mapping)
-- **Trainers** (hvac_trainer, hvac_master_trainer) โ **Contacts** (with Contact_Type field)
-- **Ticket Attendees** โ **Contacts** + **Campaign Members** (links Contact โ Campaign)
-- **RSVPs** โ **Leads** + **Campaign Members** (links Lead โ Campaign)
-- **Ticket Orders** โ **Invoices** (financial records)
-
-**Staging Protection Active:**
-- All write operations (POST/PUT/DELETE) are blocked on staging
-- Only production (`upskillhvac.com`) can write to Zoho CRM
-- Dry-run shows what would sync without actually sending data
-
-**Admin Page Location:**
-- `/wp-admin/admin.php?page=hvac-zoho-sync`
-
-**Files Modified:**
-- `includes/zoho/class-zoho-sync.php` - Complete rewrite for Event Tickets
-- `includes/admin/class-zoho-admin.php` - Added new sync buttons
-
----
-
-## ๐
PREVIOUS SESSION - GEMINI TRANSITION & VALIDATION (Dec 16, 2025)
-
-### Gemini Development Environment Setup
-
-**Objective:** Transition from Claude Code-specific tooling to Gemini/Antigravity agent development workflow.
-
-**Completed:**
-1. โ
**Created `GEMINI.md`** - New development guidelines
- - Critical safety constraints for Cloudways Shared VPS
- - Workflows for testing (`/test`) and deployment
- - Coding standards (Singleton pattern, security, PHP 8+ modernization)
- - Agent personas (Tester, Security Auditor, Deployment Engineer)
-
-2. โ
**Environment Configuration**
- - Updated `.gitignore` to allow `.agent/`, `.mcp.json`, `GEMINI.md`
- - Created `/home/ben/dev/upskill-event-manager/.agent/workflows/test.md`
- - Fixed file access blocked by gitignore
-
-3. โ
**PHP 8+ Compatibility Verification**
- - **Issue:** `true|\WP_Error` syntax causing PHP fatal errors on staging (PHP 8.0)
- - **Fix:** Changed to `bool|\WP_Error` in `includes/class-hvac-security-helpers.php:231`
- - **Status:** Deployed to staging, verified working
-
-4. โ
**Comprehensive Test Suite**
- - **File:** `test-comprehensive-validation.js` (Playwright E2E tests)
- - **Fixed:** Login form selectors (`#user_login`, `#user_pass`, `#wp-submit`)
- - **Modes:** Headless (default) or headed (`DISPLAY=:1 HEADLESS=false`)
- - **Results:**
- - Master Trainer pages: โ
ALL PASSING (4/4)
- - Security endpoints: โ
ALL SECURE (4/4)
- - Trainer pages: โ ๏ธ Require authentication (expected)
-
-**Test Results Summary:**
-```
-โ
Master Dashboard - Functional with navigation
-โ
Announcements - Fully functional & responsive
-โ
Pending Approvals - Fully functional & responsive
-โ
Trainers - Fully functional & responsive
-
-๐ Security: All AJAX endpoints properly secured (401/400 responses)
- - hvac_get_trainer_stats
- - hvac_manage_announcement
- - hvac_approve_trainer
- - hvac_approve_trainer_v2
-```
-
-**Test Credentials Updated:**
-- `test_master` / `Test123!` (hvac_master_trainer)
-- `test_trainer` / `Test123!` (hvac_trainer)
-- `test_admin` / `Test123!` (administrator)
-
-5. โ
**Master Trainer Navigation Dropdown Fix** (Dec 16, 2025)
- - **Issue:** Green/teal colored boxes appearing in navigation toolbar instead of dropdown arrows
- - **Root Cause:** Empty `