diff --git a/PROJECT-MEMORY.md b/PROJECT-MEMORY.md
index 25548f5..4ef31c6 100644
--- a/PROJECT-MEMORY.md
+++ b/PROJECT-MEMORY.md
@@ -60,14 +60,77 @@ const showLogos = ...
static/hyperscript/
├── toggles._hs # Toggle functions (CV length, icons, theme)
├── hover-sync._hs # Hover synchronization functions
-└── utils._hs # Utility functions (keyboard shortcuts, etc.)
+├── navigation._hs # Navigation functions (scroll-to-section) [2025-11-20]
+├── keyboard._hs # Keyboard handler reference (inline in body tag)
+└── utils._hs # Utility functions (print, scroll, etc.)
```
**Migration in progress:** Moving functions from `cv-functions.js` back to hyperscript
**Test that verifies no limit:** `tests/mjs/9-hyperscript-def-limit.test.mjs`
-**Reference:** `doc/HYPERSCRIPT-RULES.md`
+**Reference:** `doc/4-HYPERSCRIPT-RULES.md`
+
+---
+
+### 2.1. Hyperscript Event Handler Externalization (2025-11-20)
+
+**Rule: Complex event handlers that inspect event properties MUST stay inline**
+
+**✅ CAN Be Externalized:**
+- Simple navigation handlers (scrollToSection)
+- Toggle handlers (toggleCVLength, toggleIcons)
+- Hover sync handlers (syncPdfHover, syncPrintHover)
+
+**❌ MUST Stay Inline:**
+- Keyboard handlers that inspect `event.key`, `event.target`, modifier keys
+- Event handlers with complex conditional logic based on event properties
+
+**Why:** The `event` variable in `_=""` attributes is a hyperscript runtime variable. External `def` functions don't have direct access to this event context from HTML attributes.
+
+**Optimization for Inline:** Use `then` chains to make compact:
+```hyperscript
+-- Compact inline handler with then chains
+if event.key is '?' and not event.ctrlKey and not isInputField
+ halt the event then set modal to #shortcuts-modal then if modal then call modal.showModal() end
+end
+```
+
+**Example - Navigation (Externalized):**
+```html
+
+
+```
+
+```hyperscript
+-- External function in navigation._hs
+def scrollToSection(event, sectionId)
+ call event.preventDefault()
+ set element to document.getElementById(sectionId)
+ if element then call element.scrollIntoView({behavior: 'smooth'}) end
+end
+```
+
+**Example - Keyboard Handler (Inline):**
+```html
+
+
+```
+
+**Files:**
+- `static/hyperscript/navigation._hs` - External navigation function
+- `templates/partials/navigation/hamburger-menu.html` - 9 clean navigation links
+- `templates/index.html` - Optimized inline keyboard handler (body tag)
+
+**Test:** `tests/mjs/2-keyboard-shortcuts.test.mjs` (keyboard shortcuts)
+
+**Reference:** `doc/4-HYPERSCRIPT-RULES.md` Section "Rule 4: Event Handler Externalization Guidelines"
---
diff --git a/doc/4-HYPERSCRIPT-RULES.md b/doc/4-HYPERSCRIPT-RULES.md
index 2267989..ce1c97c 100644
--- a/doc/4-HYPERSCRIPT-RULES.md
+++ b/doc/4-HYPERSCRIPT-RULES.md
@@ -61,26 +61,96 @@ static/hyperscript/
end">
```
+### Rule 4: Event Handler Externalization Guidelines (2025-11-20)
+**Know what CAN and CANNOT be externalized**
+
+#### ✅ **CAN Be Externalized:**
+**Simple function calls without complex event inspection:**
+```html
+
+
+
+
+
+
+
+