Claude Skill

claude-docs-course

Generate an interactive, self-contained HTML course on any Claude documentation topic. Use this skill when the user wants to create an interactive course, tutorial, or deep-dive walkthrough about a Claude feature, API concept, SDK pattern, or prompt engineering technique. Trigger

LLM Mart · 0 points · 8 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download costiash-claude-code-docs-plugin_skills_claude-docs-course-e613f7b.zip · 30 KB
Part of costiash/claude-code-docs — 5 skills

Install

skills CLI npx skills add https://github.com/costiash/claude-code-docs/tree/main/plugin/skills/claude-docs-course
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install costiash-claude-code-docs@llmmart
Git git clone https://github.com/costiash/claude-code-docs.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole costiash/claude-code-docs collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Docs-to-Course

Transform any Claude documentation topic into a stunning, interactive single-page HTML course. The output is a single self-contained HTML file (no dependencies except Google Fonts) that teaches the topic through scroll-based modules, animated visualizations, embedded quizzes, and plain-English translations of real API examples and configuration snippets from the official docs.

First-Run Welcome

When the skill is first triggered and the user hasn't specified a topic yet, introduce yourself:

I can turn any Claude topic into an interactive course — visual explanations, animated diagrams, and hands-on quizzes, all in a single HTML file.

Tell me a topic:

  • A Claude Code feature — e.g., "create a course on hooks"
  • An API concept — e.g., "make a course about tool use"
  • An SDK pattern — e.g., "interactive tutorial for Agent SDK sessions"
  • A technique — e.g., "teach me about extended thinking interactively"

I'll read through the official documentation, design a learning arc, and generate a beautiful single-page HTML course with animated protocol diagrams, code explanations, and interactive quizzes. Opens right in your browser — no setup needed.

If the user just came from a /docs response, the topic is already known — skip the welcome and start building.

Who This Is For

The target learner is a developer building with Claude — someone who has general technical literacy but wants to deeply understand a specific Claude feature, API concept, or SDK pattern before using it in their project.

Assume general technical literacy. The learner knows what APIs, functions, JSON, and HTTP requests are. They don't need basic programming concepts explained. But they DO need Claude-specific concepts, patterns, and terminology explained thoroughly — tokens, context windows, tool_use blocks, stop sequences, system prompts, streaming events, hook matchers, MCP servers, etc.

Their goals are practical:

  • Master a Claude feature before using it in production — understand not just the API surface, but the mental model, edge cases, and best practices
  • Make confident architectural decisions — know which Claude feature to use for a given problem, understand tradeoffs
  • Debug effectively — when something doesn't work as expected, know where to look and what to check
  • Stay current — Claude's capabilities evolve fast; deep understanding beats surface-level familiarity
  • Communicate precisely — use the correct terminology when discussing Claude integrations with teammates

They are NOT beginners at programming. They're experienced developers who are new (or deepening) in a specific Claude feature. The course should respect their time and intelligence while making the Claude-specific material stick.

Why This Approach Works

Documentation is comprehensive but flat — it lists features, parameters, and examples without a learning arc. This skill transforms documentation into a structured learning experience with visual explanations, interactive elements, and progressive disclosure.

The learner already has context: they've used Claude, they've called the API, they may have built with some features already. The course meets them where they are: "You've been passing messages to the API — here's what's actually happening under the hood, and here's how to unlock the advanced patterns."

Every module answers "when and why would I use this?" before "how does it work?" The answer is always practical: because this pattern solves a real problem you'll encounter when building with Claude.

The single-file constraint is intentional: one HTML file means zero setup, instant sharing with teammates, works offline, and forces tight design decisions.


The Process (4 Phases)

Phase 1: Topic Discovery

Before writing course HTML, deeply understand the topic by reading all relevant documentation. Thoroughness here pays off — the more you understand, the better the course.

How to find documentation files:

Use the search scripts (they read the manifest + index, so they see every page whether or not it is cached):

  1. Content search — for questions or compound topics:

    bash ~/.claude-code-docs/plugin/skills/claude-docs/scripts/content-search.sh "<keyword1>" "<keyword2>"
    
  2. Fuzzy search — for approximate names:

    bash ~/.claude-code-docs/plugin/skills/claude-docs/scripts/fuzzy-search.sh "<query>"
    
  3. By category — list a whole product's pages:

    jq -r '.pages[] | select(.category=="claude_code") | .filename' ~/.claude-code-docs/paths_manifest.json
    

Reading a page: pages are cached at ~/.claude-code-docs/cache/<filename>. If a file isn't there yet, fetch it first, then read it:

~/.claude-code-docs/plugin/scripts/fetch-docs.sh get "<filename>"

(Fetching several? Run ~/.claude-code-docs/plugin/scripts/fetch-docs.sh sync once instead.)

What to read:

  • Read the top 5-8 matching docs for the topic (fetching any that aren't cached)
  • Read 1-2 adjacent/related docs for context (e.g., if the topic is "hooks", also skim the skills and settings docs)
  • Cap at 10 docs total to avoid context exhaustion

What to extract:

  • Concept definitions and mental models — how does this feature actually work?
  • API endpoints, parameters, and their purposes
  • Real code examples (Python, TypeScript, cURL, JSON configs) — these become your code translations
  • Configuration options and their defaults
  • Common patterns and recommended approaches
  • Edge cases, gotchas, and error scenarios
  • Connections to related features

Figure out the learning story yourself from the documentation. Don't ask the user to explain the topic — build the narrative from what the docs reveal. The course should open by explaining why this feature exists and what problem it solves, then progressively peel back layers.

Phase 2: Curriculum Design

Structure the course as 4-7 modules. Documentation topics are typically more focused than entire codebases, so fewer modules are usually appropriate. The arc starts from what the learner already knows (general Claude usage) and moves toward what they don't (deep feature knowledge).

Module Position Purpose Example for "hooks"
1 "What is this and why should you care?" What hooks are, what problems they solve, what you can automate
2 "The mental model" Hook lifecycle diagram, event types, when each fires
3 "See it in action" Real hook configs with code translations, walking through examples
4 "The details that matter" Matcher patterns, JSON schemas, timeout handling, async behavior
5 "Patterns and recipes" Common use cases — auto-formatting, CI/CD gates, security checks
6 "Connect the dots" How hooks relate to skills, MCP, permissions — the bigger picture

Not every topic needs all 6. A narrow feature (like "prompt caching") might only need 3-4 modules. A broad one (like "tool use") might need 6-7. Adapt the arc to the topic's depth.

The key principle: Every module should connect to a practical skill — building better, debugging faster, or making smarter architecture decisions. If a module doesn't help the learner DO something, cut it or reframe it until it does.

Each module should contain:

  • 3-6 screens (sub-sections that flow within the module)
  • At least one code-with-English translation (API calls, config snippets, CLI commands)
  • At least one interactive element (quiz, visualization, or animation)
  • One or two "aha!" callout boxes with practical insights
  • A metaphor that grounds the Claude concept in something tangible — but NEVER reuse the same metaphor across modules. Pick metaphors that organically fit each specific concept. Examples: hooks are "tripwires that trigger actions", streaming is a "live news ticker", tool use is a "Swiss army knife Claude carries", context windows are "working memory on a desk", prompt caching is "bookmarking your place in a conversation".

Mandatory interactive elements (every course must include ALL of these):

  • Protocol Conversation — at least one across the course. iMessage/chat-style conversations between system actors (Client App, Claude API, Claude Model, Tool Server) showing how they exchange messages. These bring protocol-level concepts to life.
  • Data Flow Animation — at least one across the course. Step-by-step visualization of data moving through the system — API request lifecycles, streaming event flows, hook execution chains.
  • Code ↔ English Translation Blocks — at least one per module. Real code from the documentation (API calls, JSON configs, CLI commands) with plain-English translation on the right.
  • Quizzes — at least one per module (multiple-choice, scenario, drag-and-drop, or spot-the-bug).
  • Glossary Tooltips — on every Claude-specific term, first use per module.

These five element types are the backbone of every course. Other interactive elements (architecture diagrams, layer toggles, pattern cards, etc.) are optional and should be added when they fit. But the five above must ALWAYS be present — no exceptions.

Do NOT present the curriculum for approval — just build it. The user wants a course, not a planning document. Design the curriculum internally, then go straight to generating the HTML. If they want changes, they'll tell you after seeing the result.

Phase 3: Build the Course

Generate a single HTML file with embedded CSS and JavaScript. Read references/design-system.md for the complete CSS design tokens, typography, and color system. Read references/interactive-elements.md for implementation patterns of every interactive element type.

Build order (task by task):

  1. Foundation first — HTML shell with all module sections (empty), complete CSS design system, navigation bar with progress tracking, scroll-snap behavior, keyboard navigation, and scroll-triggered animations. After this step, you should have a working skeleton you can scroll through.

  2. One module at a time — Fill in each module's content, code translations, and interactive elements. Don't try to write all modules in one pass — the quality drops. Build Module 1, verify it works, then Module 2, etc.

  3. Polish pass — After all modules are built, do a final pass for transitions, mobile responsiveness, and visual consistency.

Critical implementation rules:

  • The file must be completely self-contained (only external dependency: Google Fonts CDN)
  • Use CSS scroll-snap-type: y proximity (NOT mandatory — mandatory traps users in long modules)
  • Use min-height: 100dvh with 100vh fallback for sections
  • Only animate transform and opacity for GPU performance
  • Wrap all JS in an IIFE, use passive: true on scroll listeners, throttle with requestAnimationFrame
  • Include touch support for drag-and-drop, keyboard navigation (arrow keys), and ARIA attributes

Phase 4: Save, Review, and Open

Save the course to the dedicated courses directory:

mkdir -p ~/.claude-code-docs/courses

Name the file based on the topic: ~/.claude-code-docs/courses/<topic-slug>.html

  • Use kebab-case: "prompt caching" → prompt-caching.html, "tool use" → tool-use.html
  • If a file with that name already exists, append a number: hooks-2.html

After saving, open the file in the browser for the user to review. Walk them through what was built — the module arc, the key interactive elements, and the learning progression. Tell them where the file is saved so they can share it or revisit it later. Ask for feedback on content, design, and interactivity.


Content Philosophy

These principles are what separate a great course from a generic tutorial. They should guide every content decision:

Show, Don't Tell — Aggressively Visual

Developers' eyes glaze over text blocks too. The course should feel closer to an interactive reference than a wall of documentation. Follow these hard rules:

Text limits:

  • Max 2-3 sentences per text block. If you're writing a fourth sentence, stop and convert it into a visual instead.
  • No text block should ever be wider than the content width AND taller than ~4 lines. If it is, break it up with a visual element.
  • Every screen must be at least 50% visual (diagrams, code blocks, cards, animations, badges — anything that isn't a paragraph).

Convert text to visuals:

  • A list of 3+ items → cards with icons (pattern cards, feature cards)
  • A sequence of steps → flow diagram with arrows or numbered step cards
  • "Client sends request to API" → animated data flow or protocol conversation
  • "This parameter does X, that parameter does Y" → side-by-side comparison columns or config badges
  • Explaining what code does → code↔English translation block (not a paragraph about the code)
  • Comparing two approaches → side-by-side columns with visual contrast

Visual breathing room:

  • Use generous spacing between elements (--space-8 to --space-12 between sections)
  • Alternate between full-width visuals and narrow text blocks to create rhythm
  • Every module should have at least one "hero visual" — a diagram, animation, or interactive element that dominates the screen and teaches the core concept at a glance

Code ↔ English Translations

Every code example gets a side-by-side plain English translation. Left panel: real code from the documentation (API calls, JSON configs, CLI commands) with syntax highlighting. Right panel: line-by-line plain English explaining what each part does and why.

Critical: No horizontal scrollbars on code. All code must use white-space: pre-wrap so it wraps instead of scrolling. Readability beats preserving indentation structure.

Critical: Use documentation examples exactly as-is. Never modify, simplify, or trim code examples from the docs. The learner should be able to find the exact same example in the official documentation — that builds trust and makes the course a companion to the docs, not a replacement. Instead of editing code to make it shorter, choose naturally short, punchy examples (5-15 lines) from the docs that illustrate the concept well.

One Concept Per Screen

No walls of text. Each screen within a module teaches exactly one idea. If you need more space, add another screen — don't cram.

Metaphors First, Then Reality

Introduce every new Claude concept with a metaphor from everyday life. Then immediately ground it: "In Claude's API, this looks like..." The metaphor builds intuition; the code grounds it in reality.

Critical: No recycled metaphors. Each concept deserves its own metaphor that feels natural to that specific idea. Context windows as "desk space", tokens as "word fragments in a shredder", system prompts as "stage directions for an actor", tool use as "a Swiss army knife", streaming as "a live ticker". Pick the metaphor that makes the concept click, not the one that's easiest to reach for.

Learn by Tracing

Follow what actually happens when the developer makes a familiar API call — trace the request end-to-end. "You've been sending messages to Claude — here's the full lifecycle of that request, from your code to Claude's response, step by step." This works because the learner has already used the feature — now they're seeing the machinery behind it.

Make It Memorable

Use "aha!" callout boxes for practical insights. Use humor where natural (not forced). Give system actors personality in protocol conversations — Claude, the API gateway, the tool server are "characters" in the story, not abstract boxes.

Glossary Tooltips — Claude-Specific Terms

Every Claude-specific term gets a dashed-underline tooltip on first use in each module. Hover on desktop or tap on mobile to see a 1-2 sentence definition grounded in practical usage.

Tooltip scope for developer audience: Don't tooltip basic programming terms (function, variable, JSON, API). DO tooltip:

  • Claude-specific concepts: tokens, context window, stop sequences, tool_use blocks, content blocks, thinking blocks
  • Anthropic-specific terms: Messages API, Admin API, prompt caching, extended thinking, adaptive thinking
  • Claude Code terms: hooks, matchers, skills, MCP servers, CLAUDE.md, sub-agents
  • Agent SDK terms: sessions, agent loop, tool search, slash commands
  • Protocol terms: SSE (Server-Sent Events), streaming deltas, stop_reason values
  • Acronyms on first use — even common ones in a Claude context (MCP, SSE, IIFE, ARIA)

The vocabulary IS the learning. Each tooltip should teach the term in a way that helps the learner USE it correctly — e.g., "stop_reason — tells you why Claude stopped generating. end_turn means Claude finished naturally. tool_use means Claude wants to call a tool. Check this to decide your next action."

Cursor: Use cursor: pointer on terms (not cursor: help). The question-mark cursor feels clinical — a pointer feels clickable and inviting.

Tooltip overflow fix: Translation blocks and other containers with overflow: hidden will clip tooltips. To fix this, the tooltip JS must use position: fixed and calculate coordinates from getBoundingClientRect() instead of relying on CSS position: absolute within the container. Append tooltips to document.body rather than inside the term element.

Quizzes That Test Application, Not Memory

Quizzes should test whether the learner can use their knowledge to solve a real problem, not whether they can regurgitate parameter names.

What to quiz (in order of value):

  1. "What would you use?" scenarios — "You want to let Claude browse the web during a conversation. Which feature would you configure?" Tests whether they understood the feature landscape.
  2. Debugging scenarios — "Your streaming response cuts off mid-sentence with stop_reason: max_tokens. What's happening and what should you change?" Tests practical understanding.
  3. Architecture decisions — "You're building an agent that needs to remember context across sessions. Which approach would you use: prompt caching, the Files API, or external storage?" Tests tradeoff reasoning.
  4. Configuration challenges — "Write the hook matcher JSON that would block all file deletions during CI runs." Tests whether they can apply the syntax.

What NOT to quiz:

  • Definitions ("What is a token?") — that's what the glossary tooltips are for
  • Parameter recall ("What's the default max_tokens?") — that's what docs are for
  • Exact syntax ("Write the correct API call") — this isn't a coding exam
  • Anything that can be answered by scrolling up — that tests scrolling, not understanding

Quiz tone:

  • Wrong answers get encouraging, helpful explanations ("Not quite — here's why...")
  • Correct answers get brief reinforcement of the underlying principle ("Exactly! This works because...")
  • Never punitive, never score-focused. No "You got 3/5!" — the quiz is a thinking exercise, not an exam

How many quizzes: One per module, placed at the end. 3-5 questions per quiz. Each question should make the learner pause and think.


Topic Scope Control

Documentation topics vary wildly in breadth. A clear scoping strategy prevents courses from becoming unfocused.

Narrow topics (hooks, prompt caching, streaming) — 3-5 modules, read all relevant docs. These make the best courses.

Medium topics (tool use, Agent SDK, MCP) — 5-7 modules. May need to prioritize which aspects to cover deeply vs. mention in passing.

Broad topics (Claude API, "everything about Claude Code") — Too broad for a single course. Narrow to a specific sub-topic and suggest related courses:

"The Claude API is too broad for one course. I'll focus on the Messages API and tool use — the core of building with Claude. For streaming, batch processing, and admin APIs, you can generate separate courses."

Rule of thumb: If you'd need to read more than 10 doc files to cover the topic, it's too broad. Narrow it.


Design Identity — Obsidian & Amber

The visual design should feel like discovering knowledge in a luxury developer observatory — deep, atmospheric, and unmistakable. Read references/design-system.md for the full token system, but here are the non-negotiable principles:

  • Dark obsidian palette: Deep navy-black backgrounds (#0D0D16) with warm undertones — never pure black, never cold gray. The darkness creates focus; the warmth creates comfort.
  • Amber accent: Warm amber-gold (#F0A050) as the signature color. Used sparingly — for interactive highlights, active states, and glow effects. Amber evokes lamplight, discovery, and illumination.
  • Editorial typography: Instrument Serif for display headings — sharp, elegant serifs that create immediate visual identity. The contrast between serif headings and clean sans body text (Outfit) is the signature of this theme. NEVER use Inter, Roboto, Arial, Space Grotesk, or any generic sans-serif for headings.
  • Generous whitespace: Modules breathe against the dark background. Max 3-4 short paragraphs per screen.
  • Alternating depths: Even/odd modules alternate between two dark tones for subtle visual rhythm
  • Inky code blocks: Near-black (#08080F) with amber-tinted syntax highlighting that echoes the theme accent
  • Grain texture: Subtle analog noise overlay across all surfaces — adds warmth and prevents the "dead screen" flatness of digital dark themes
  • Amber glow: Interactive elements emit a soft amber glow on hover and focus, drawing the eye like lamplight
  • Glass-morphism: Elevated surfaces use backdrop-filter blur with faint border highlights for depth

Gotchas — Common Failure Points

Check every one of these before considering a course complete.

Tooltip Clipping

Translation blocks use overflow: hidden for code wrapping. If tooltips use position: absolute inside the term element, they get clipped by the container. Fix: Tooltips must use position: fixed and be appended to document.body. Calculate position from getBoundingClientRect(). This is the #1 bug in every build.

Under-Tooltipping Claude Terms

The most common failure is under-tooltipping. Claude-specific terms like MCP, SSE, content blocks, stop_reason, tool_use, matchers, CLAUDE.md, sub-agents — all need tooltips on first use per module. Rule: if a term is specific to Claude/Anthropic and wouldn't be known to a developer who hasn't used Claude before, tooltip it.

Walls of Text

The course looks like reformatted documentation instead of a visual learning experience. This happens when you write more than 2-3 sentences in a row without a visual break. Every screen must be at least 50% visual.

Recycled Metaphors

Using the same metaphor for different concepts. Every module needs its own metaphor that feels inevitable for that specific concept.

Documentation Example Modifications

Trimming, simplifying, or "cleaning up" code examples from the docs. The learner should be able to find the exact same code in the official documentation. Choose naturally short examples rather than editing longer ones.

Topic Scope Creep

Trying to cover everything related to a topic instead of staying focused. If the topic is "hooks," don't also try to teach MCP, skills, and permissions in depth. Mention them in the "Connect the dots" module and suggest separate courses.

Quiz Questions That Test Memory

Asking "What's the default max_tokens?" or "Name the hook event types" — those test recall, not understanding. Every quiz question should present a scenario the learner hasn't seen and ask them to apply what they learned.

Scroll-Snap Mandatory

Using scroll-snap-type: y mandatory traps users inside long modules. Always use proximity.

Module Quality Degradation

Trying to write all modules in one pass causes later modules to be thin and rushed. Build one module at a time and verify each before moving on.

Missing Interactive Elements

A module with only text and code blocks, no interactivity. Every module needs at least one of: quiz, data flow animation, protocol conversation, architecture diagram, drag-and-drop.


Reference Files

The references/ directory contains detailed implementation specs. Read them when you reach the relevant phase:

  • references/design-system.md — Complete CSS custom properties, color palette, typography scale, spacing system, shadows, animations, scrollbar styling. Read this before writing any CSS.
  • references/interactive-elements.md — Implementation patterns for every interactive element: drag-and-drop quizzes, multiple-choice quizzes, code↔English translations, protocol conversations, message flow visualizations, architecture diagrams, pattern cards, callout boxes. Read this before building any interactive elements.
Files (claude-code-docs)
  • examples
    • course-from-docs.md 3 KB
      # Example: Interactive Course from Documentation
      
      ## User Query
      > /docs --course hooks
      
      ## Skill Reasoning
      - User requests an interactive course on "hooks"
      - Strategy: Topic Discovery → find all hooks-related documentation pages via the search scripts
      
      ## Actions
      
      ### Phase 1: Topic Discovery
      1. **Search:** `bash ~/.claude-code-docs/plugin/skills/claude-docs/scripts/fuzzy-search.sh "hooks"`
         - Results: `claude-code__hooks.md`, `claude-code__hooks-guide.md`, `claude-code__agent-sdk__hooks.md`
      2. **Fetch + read all 3 pages** — each lives at `~/.claude-code-docs/cache/<filename>`;
         on a cache miss, fetch first:
         ```bash
         ~/.claude-code-docs/plugin/scripts/fetch-docs.sh get "claude-code__hooks.md"
         ```
         Extract concept definitions, JSON config examples, matcher patterns, event types, lifecycle details
      3. **Adjacent docs for context:** Skim `claude-code__skills.md`, `claude-code__settings.md` for related features
         (same get-then-read pattern)
      4. **Extracted material:**
         - Hook event types: PreToolUse, PostToolUse, SessionStart, etc.
         - JSON configuration format with matcher patterns
         - Shell script examples for hook commands
         - Agent SDK hook variants (Python/TypeScript)
      
      ### Phase 2: Curriculum Design
      Design 6-module curriculum:
      
      | # | Title | Key Visual |
      |---|-------|-----------|
      | 1 | What Are Hooks & Why They Matter | Feature cards showing automation scenarios |
      | 2 | The Hook Lifecycle | Data flow animation: User action → event → matcher → hook → result |
      | 3 | See It In Action | Code translations of hook JSON configs |
      | 4 | Matchers & Advanced Patterns | Scenario quiz on matcher patterns |
      | 5 | Common Recipes | Pattern cards: auto-format, CI gates, security checks |
      | 6 | Hooks in the Ecosystem | Protocol conversation: Claude ↔ Hook Handler ↔ Tool |
      
      ### Phase 3: Build
      1. Foundation: HTML shell, CSS design system, nav, scroll-snap
      2. Module 1: Intro + feature cards
      3. Module 2: Lifecycle animation + event type badges
      4. Module 3: Hook JSON → English translations
      5. Module 4: Matcher quiz + advanced config translations
      6. Module 5: Recipe pattern cards + drag-and-drop matching
      7. Module 6: Protocol conversation + architecture diagram
      8. Polish pass
      
      ### Phase 4: Review
      - Open HTML in browser
      - Walk user through: "Here's what we built — 6 modules covering hooks from concept to advanced patterns"
      - Ask for feedback
      
      ## Output Format
      A single self-contained HTML file (~80-120KB) with:
      - 6 scroll-snap modules with progress nav
      - Protocol conversation showing hook execution flow
      - Code ↔ English translations of hook JSON configs
      - Data flow animation of the hook lifecycle
      - Multiple-choice quizzes testing practical hook configuration
      - Glossary tooltips on terms: matchers, IIFE, ARIA, stdin, SSE, MCP
      - Source links from the manifest, e.g. [Hooks reference](https://code.claude.com/docs/en/hooks),
        [Automate actions with hooks](https://code.claude.com/docs/en/hooks-guide),
        [Agent SDK hooks](https://code.claude.com/docs/en/agent-sdk/hooks)
      - Obsidian & Amber design aesthetic (Instrument Serif + Outfit + JetBrains Mono)
      
  • references
    • design-system.md 19 KB
      # Design System Reference — Obsidian & Amber
      
      Complete CSS design tokens for the course. Copy this entire `:root` block into the course HTML. The theme is a refined dark aesthetic — deep obsidian backgrounds with warm amber accents that create an atmosphere of focused discovery. Serif display headings give editorial elegance; clean sans-serif body text ensures readability. Grain textures and subtle glow effects add depth without distraction.
      
      ## Table of Contents
      1. [Color Palette](#color-palette)
      2. [Typography](#typography)
      3. [Spacing & Layout](#spacing--layout)
      4. [Shadows & Depth](#shadows--depth)
      5. [Animations & Transitions](#animations--transitions)
      6. [Navigation & Progress](#navigation--progress)
      7. [Module Structure](#module-structure)
      8. [Responsive Breakpoints](#responsive-breakpoints)
      9. [Scrollbar & Background](#scrollbar--background)
      10. [Grain & Atmosphere](#grain--atmosphere)
      
      ---
      
      ## Color Palette
      
      ```css
      :root {
        /* --- BACKGROUNDS ---
           Deep obsidian with a subtle warm-navy undertone. Never pure black.
           The slight blue-purple tint gives depth and avoids a "dead screen" feel. */
        --color-bg:             #0D0D16;       /* primary — deep obsidian */
        --color-bg-warm:        #12121E;       /* alternating modules — slightly lifted */
        --color-bg-code:        #08080F;       /* code blocks — near-black, inky */
        --color-text:           #E8E0D4;       /* warm cream — primary text */
        --color-text-secondary: #9A9088;       /* warm muted — body text */
        --color-text-muted:     #5C5852;       /* dark muted — labels, timestamps */
        --color-border:         #2A2840;       /* subtle dark border */
        --color-border-light:   #1E1C32;       /* even subtler border */
        --color-surface:        #161624;       /* card surfaces — elevated from bg */
        --color-surface-warm:   #1C1A28;       /* warm card surface — for translations */
      
        /* --- ACCENT: Amber ---
           Warm amber-gold evokes lamplight, discovery, illumination.
           This is the signature color — used sparingly for maximum impact. */
        --color-accent:         #F0A050;       /* amber gold */
        --color-accent-hover:   #E88A30;       /* deeper amber on hover */
        --color-accent-light:   rgba(240, 160, 80, 0.08);  /* subtle amber wash */
        --color-accent-muted:   #C09060;       /* desaturated amber for less emphasis */
        --color-accent-glow:    rgba(240, 160, 80, 0.25);  /* glow effect around interactives */
      
        /* --- SEMANTIC --- */
        --color-success:        #50C8A0;       /* bright mint-teal */
        --color-success-light:  rgba(80, 200, 160, 0.08);
        --color-error:          #F06060;       /* warm red */
        --color-error-light:    rgba(240, 96, 96, 0.08);
        --color-info:           #60A0E0;       /* soft blue */
        --color-info-light:     rgba(96, 160, 224, 0.08);
      
        /* --- ACTOR COLORS (assign to protocol conversation actors) ---
           Chosen for contrast against dark backgrounds and against each other.
           Each actor should be instantly recognizable by color alone. */
        --color-actor-1:        #F0A050;       /* amber — Client App */
        --color-actor-2:        #50C8A0;       /* teal — API Gateway */
        --color-actor-3:        #C080E0;       /* soft violet — Claude Model */
        --color-actor-4:        #E0C060;       /* warm gold — Cache / Tool */
        --color-actor-5:        #60B0E0;       /* sky blue — User */
      }
      ```
      
      **Rules:**
      - Even-numbered modules use `--color-bg`, odd-numbered use `--color-bg-warm` (alternating creates depth rhythm)
      - Actor colors must be distinct from each other and pass a contrast test against `--color-surface`
      - Code blocks always use `--color-bg-code` — darker than everything else to visually recede
      - The amber accent should be used for CTAs, active states, and highlights — never for large background areas
      - Interactive elements get a subtle `box-shadow: 0 0 20px var(--color-accent-glow)` on hover/focus
      
      ---
      
      ## Typography
      
      ```css
      :root {
        /* --- FONTS ---
           Display: Instrument Serif — sharp, elegant serifs with editorial character.
           Creates immediate visual identity on dark backgrounds. The contrast between
           serif headings and sans body text is the signature of this theme.
           Body: Outfit — modern, clean, slightly rounded terminals. Excellent legibility
           at all sizes on dark backgrounds.
           Mono: JetBrains Mono — developer standard, clear character distinction. */
        --font-display:  'Instrument Serif', Georgia, 'Times New Roman', serif;
        --font-body:     'Outfit', -apple-system, sans-serif;
        --font-mono:     'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
      
        /* --- TYPE SCALE (1.25 ratio) --- */
        --text-xs:   0.75rem;    /* 12px — labels, badges */
        --text-sm:   0.875rem;   /* 14px — secondary text, code */
        --text-base: 1rem;       /* 16px — body text */
        --text-lg:   1.125rem;   /* 18px — lead paragraphs */
        --text-xl:   1.25rem;    /* 20px — screen headings */
        --text-2xl:  1.5rem;     /* 24px — sub-module titles */
        --text-3xl:  1.875rem;   /* 30px — module subtitles */
        --text-4xl:  2.25rem;    /* 36px — module titles */
        --text-5xl:  3rem;       /* 48px — hero text */
        --text-6xl:  3.75rem;    /* 60px — module numbers */
      
        /* --- LINE HEIGHTS --- */
        --leading-tight:  1.15;  /* headings */
        --leading-snug:   1.3;   /* subheadings */
        --leading-normal: 1.6;   /* body text */
        --leading-loose:  1.8;   /* relaxed reading */
      }
      ```
      
      **Google Fonts link (put in `<head>`):**
      ```html
      <link rel="preconnect" href="https://fonts.googleapis.com">
      <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
      <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Outfit:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
      ```
      
      **Rules:**
      - Module numbers: `--text-6xl`, font-display, italic, `--color-accent` with 20% opacity
      - Module titles: `--text-4xl` or `--text-5xl`, font-display, normal weight (serifs carry their own weight — no bold needed)
      - Screen headings: `--text-xl` or `--text-2xl`, font-display
      - Body text: `--text-base` or `--text-lg`, font-body, weight 400, `--leading-normal`
      - Code: `--text-sm`, font-mono
      - Labels/badges: `--text-xs`, font-body, weight 600, uppercase, letter-spacing 0.08em
      - The serif display font should NEVER be used below `--text-xl` — below that, use font-body
      
      ---
      
      ## Spacing & Layout
      
      ```css
      :root {
        --space-1:  0.25rem;   /* 4px */
        --space-2:  0.5rem;    /* 8px */
        --space-3:  0.75rem;   /* 12px */
        --space-4:  1rem;      /* 16px */
        --space-5:  1.25rem;   /* 20px */
        --space-6:  1.5rem;    /* 24px */
        --space-8:  2rem;      /* 32px */
        --space-10: 2.5rem;    /* 40px */
        --space-12: 3rem;      /* 48px */
        --space-16: 4rem;      /* 64px */
        --space-20: 5rem;      /* 80px */
        --space-24: 6rem;      /* 96px */
      
        --content-width:     800px;   /* standard reading width */
        --content-width-wide: 1000px; /* for side-by-side layouts */
        --nav-height:        52px;
        --radius-sm:  6px;
        --radius-md:  10px;
        --radius-lg:  14px;
        --radius-xl:  20px;
        --radius-full: 9999px;
      }
      ```
      
      **Module layout:**
      ```css
      .module {
        min-height: 100dvh;       /* fallback: 100vh */
        scroll-snap-align: start;
        padding: var(--space-16) var(--space-6);
        padding-top: calc(var(--nav-height) + var(--space-12));
        position: relative;        /* for grain overlay pseudo-element */
      }
      .module-content {
        max-width: var(--content-width);
        margin: 0 auto;
      }
      ```
      
      ---
      
      ## Shadows & Depth
      
      ```css
      :root {
        /* On dark backgrounds, shadows use near-black with slight blue tint
           to maintain the obsidian atmosphere. Glow effects use the accent color. */
        --shadow-sm:  0 1px 3px rgba(0, 0, 8, 0.3);
        --shadow-md:  0 4px 16px rgba(0, 0, 8, 0.4);
        --shadow-lg:  0 8px 32px rgba(0, 0, 8, 0.5);
        --shadow-xl:  0 16px 48px rgba(0, 0, 8, 0.6);
        --shadow-glow: 0 0 24px var(--color-accent-glow);    /* amber glow for interactives */
        --shadow-inner: inset 0 1px 0 rgba(255, 255, 255, 0.04);  /* subtle top-edge highlight */
      }
      ```
      
      **Card depth pattern:**
      ```css
      .card {
        background: var(--color-surface);
        border: 1px solid var(--color-border);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-md), var(--shadow-inner);
        transition: box-shadow var(--duration-normal) var(--ease-out),
                    border-color var(--duration-normal) var(--ease-out);
      }
      .card:hover {
        border-color: var(--color-accent-muted);
        box-shadow: var(--shadow-lg), var(--shadow-glow);
      }
      ```
      
      Never use pure black `rgba(0,0,0,...)` for shadows — always use the blue-tinted `rgba(0,0,8,...)` to maintain the obsidian atmosphere.
      
      ---
      
      ## Animations & Transitions
      
      ```css
      :root {
        --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
        --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
        --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);   /* subtle overshoot */
        --duration-fast:   150ms;
        --duration-normal: 300ms;
        --duration-slow:   500ms;
        --duration-reveal: 700ms;
        --stagger-delay:   100ms;
      }
      ```
      
      **Scroll-triggered reveal pattern:**
      ```css
      .animate-in {
        opacity: 0;
        transform: translateY(24px);
        transition: opacity var(--duration-reveal) var(--ease-out),
                    transform var(--duration-reveal) var(--ease-out);
      }
      .animate-in.visible {
        opacity: 1;
        transform: translateY(0);
      }
      
      /* Stagger children */
      .stagger-children > .animate-in {
        transition-delay: calc(var(--stagger-index, 0) * var(--stagger-delay));
      }
      ```
      
      **Amber glow pulse (for interactive elements awaiting interaction):**
      ```css
      @keyframes glowPulse {
        0%, 100% { box-shadow: 0 0 16px rgba(240, 160, 80, 0.1); }
        50%      { box-shadow: 0 0 28px rgba(240, 160, 80, 0.2); }
      }
      .interactive-hint {
        animation: glowPulse 3s var(--ease-in-out) infinite;
      }
      ```
      
      **JS setup for stagger:**
      ```javascript
      document.querySelectorAll('.stagger-children').forEach(parent => {
        Array.from(parent.children).forEach((child, i) => {
          child.style.setProperty('--stagger-index', i);
        });
      });
      ```
      
      **Intersection Observer (trigger reveals):**
      ```javascript
      const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            entry.target.classList.add('visible');
            observer.unobserve(entry.target); // animate only once
          }
        });
      }, { rootMargin: '0px 0px -10% 0px', threshold: 0.1 });
      
      document.querySelectorAll('.animate-in').forEach(el => observer.observe(el));
      ```
      
      ---
      
      ## Navigation & Progress
      
      **HTML structure:**
      ```html
      <nav class="nav">
        <div class="progress-bar" role="progressbar" aria-valuenow="0"></div>
        <div class="nav-inner">
          <span class="nav-title">Course Title</span>
          <div class="nav-dots">
            <button class="nav-dot" data-target="module-1" data-tooltip="Module 1 Name"
                    role="tab" aria-label="Module 1"></button>
            <!-- one per module -->
          </div>
        </div>
      </nav>
      ```
      
      **Nav styling:**
      ```css
      .nav {
        position: fixed;
        top: 0; left: 0; right: 0;
        z-index: 100;
        background: rgba(13, 13, 22, 0.85);
        backdrop-filter: blur(16px) saturate(1.2);
        -webkit-backdrop-filter: blur(16px) saturate(1.2);
        border-bottom: 1px solid var(--color-border-light);
        height: var(--nav-height);
      }
      .nav-inner {
        max-width: var(--content-width-wide);
        margin: 0 auto;
        padding: 0 var(--space-6);
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: space-between;
      }
      .nav-title {
        font-family: var(--font-display);
        font-size: var(--text-base);
        color: var(--color-text);
        letter-spacing: -0.01em;
      }
      .progress-bar {
        position: absolute;
        bottom: 0; left: 0;
        height: 2px;
        background: linear-gradient(90deg, var(--color-accent), var(--color-accent-hover));
        transition: width 100ms linear;
        box-shadow: 0 0 8px var(--color-accent-glow);
      }
      ```
      
      **Nav dot states:**
      ```css
      .nav-dot {
        width: 10px; height: 10px;
        border-radius: 50%;
        border: 1.5px solid var(--color-text-muted);
        background: transparent;
        cursor: pointer;
        transition: all var(--duration-normal) var(--ease-out);
        padding: 0;
      }
      .nav-dot.active {
        border-color: var(--color-accent);
        background: var(--color-accent);
        box-shadow: 0 0 10px var(--color-accent-glow);
        transform: scale(1.15);
      }
      .nav-dot.visited {
        border-color: var(--color-accent-muted);
        background: var(--color-accent-muted);
      }
      ```
      
      **Progress bar (JS):**
      ```javascript
      function updateProgressBar() {
        const scrollTop = window.scrollY;
        const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
        const progress = (scrollTop / scrollHeight) * 100;
        progressBar.style.width = progress + '%';
      }
      window.addEventListener('scroll', () => {
        requestAnimationFrame(updateProgressBar);
      }, { passive: true });
      ```
      
      **Keyboard navigation:**
      ```javascript
      document.addEventListener('keydown', (e) => {
        if (['INPUT', 'TEXTAREA'].includes(e.target.tagName)) return;
        if (e.key === 'ArrowDown' || e.key === 'ArrowRight') { nextModule(); e.preventDefault(); }
        if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') { prevModule(); e.preventDefault(); }
      });
      ```
      
      ---
      
      ## Module Structure
      
      **HTML template for each module:**
      ```html
      <section class="module" id="module-N">
        <div class="module-content">
          <header class="module-header animate-in">
            <span class="module-number">0N</span>
            <h1 class="module-title">Module Title</h1>
            <p class="module-subtitle">One-line description of what this module teaches</p>
          </header>
      
          <div class="module-body">
            <section class="screen animate-in">
              <h2 class="screen-heading">Screen Title</h2>
              <p>Content...</p>
              <!-- Interactive elements, code translations, etc. -->
            </section>
      
            <section class="screen animate-in">
              <!-- Next screen -->
            </section>
          </div>
        </div>
      </section>
      ```
      
      **Module number styling:**
      ```css
      .module-number {
        font-family: var(--font-display);
        font-style: italic;
        font-size: var(--text-6xl);
        color: var(--color-accent);
        opacity: 0.15;
        line-height: 1;
        display: block;
        margin-bottom: var(--space-2);
      }
      .module-title {
        font-family: var(--font-display);
        font-size: var(--text-5xl);
        color: var(--color-text);
        line-height: var(--leading-tight);
        margin-bottom: var(--space-3);
        letter-spacing: -0.02em;
      }
      .module-subtitle {
        font-family: var(--font-body);
        font-size: var(--text-lg);
        color: var(--color-text-secondary);
        line-height: var(--leading-snug);
        max-width: 540px;
      }
      .screen-heading {
        font-family: var(--font-display);
        font-size: var(--text-2xl);
        color: var(--color-text);
        margin-bottom: var(--space-4);
      }
      ```
      
      **Alternating module backgrounds:**
      ```css
      .module:nth-child(odd)  { background: var(--color-bg); }
      .module:nth-child(even) { background: var(--color-bg-warm); }
      ```
      
      ---
      
      ## Responsive Breakpoints
      
      ```css
      /* Tablet */
      @media (max-width: 768px) {
        :root {
          --text-4xl: 1.875rem;
          --text-5xl: 2.25rem;
          --text-6xl: 3rem;
        }
        .translation-block { grid-template-columns: 1fr; } /* stack code/english */
        .pattern-cards { grid-template-columns: 1fr 1fr; }
      }
      
      /* Mobile */
      @media (max-width: 480px) {
        :root {
          --text-4xl: 1.5rem;
          --text-5xl: 1.875rem;
          --text-6xl: 2.25rem;
        }
        .module { padding: var(--space-8) var(--space-4); }
        .pattern-cards { grid-template-columns: 1fr; }
        .flow-steps { flex-direction: column; }
        .flow-arrow { transform: rotate(90deg); }
      }
      ```
      
      ---
      
      ## Scrollbar & Background
      
      ```css
      /* Custom scrollbar — thin, ambient */
      ::-webkit-scrollbar { width: 5px; }
      ::-webkit-scrollbar-track { background: transparent; }
      ::-webkit-scrollbar-thumb {
        background: var(--color-border);
        border-radius: var(--radius-full);
      }
      ::-webkit-scrollbar-thumb:hover {
        background: var(--color-accent-muted);
      }
      
      /* Atmospheric background — subtle amber radial at top, fading out */
      body {
        background: var(--color-bg);
        background-image:
          radial-gradient(ellipse at 30% 0%, rgba(240, 160, 80, 0.04) 0%, transparent 50%),
          radial-gradient(ellipse at 80% 100%, rgba(192, 128, 224, 0.02) 0%, transparent 40%);
      }
      
      /* Page scroll setup */
      html {
        scroll-snap-type: y proximity;
        scroll-behavior: smooth;
      }
      ```
      
      ---
      
      ## Grain & Atmosphere
      
      The grain overlay is the signature texture of this theme. It adds analog warmth to the digital dark surface — like looking through a vintage lens or at a printed page under lamplight.
      
      **CSS grain overlay (apply to body or individual modules):**
      ```css
      body::after {
        content: '';
        position: fixed;
        top: 0; left: 0;
        width: 100%; height: 100%;
        pointer-events: none;
        z-index: 9999;
        opacity: 0.035;
        background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
        background-repeat: repeat;
        background-size: 256px 256px;
      }
      ```
      
      **Module separator — geometric line accent:**
      ```css
      .module + .module::before {
        content: '';
        display: block;
        position: absolute;
        top: 0;
        left: 50%;
        transform: translateX(-50%);
        width: 60px;
        height: 1px;
        background: linear-gradient(90deg, transparent, var(--color-accent-muted), transparent);
      }
      ```
      
      **Glass-morphism pattern for elevated surfaces:**
      ```css
      .glass {
        background: rgba(22, 22, 36, 0.6);
        backdrop-filter: blur(12px) saturate(1.1);
        -webkit-backdrop-filter: blur(12px) saturate(1.1);
        border: 1px solid rgba(255, 255, 255, 0.04);
        box-shadow: var(--shadow-md), var(--shadow-inner);
      }
      ```
      
      ---
      
      ## Code Block Globals
      
      All code blocks in the course — whether inside translation blocks, standalone snippets, or quiz challenges — must wrap text and never show a horizontal scrollbar. This is a teaching tool, not an IDE.
      
      ```css
      pre, code {
        white-space: pre-wrap;       /* wrap long lines */
        word-break: break-word;      /* break mid-word if absolutely needed */
        overflow-x: hidden;          /* no horizontal scrollbar — ever */
      }
      /* Hide scrollbars on code containers */
      .translation-code::-webkit-scrollbar,
      pre::-webkit-scrollbar {
        display: none;
      }
      ```
      
      Code snippets must be **exact copies** from the official documentation — never modified, trimmed, or simplified. Choose naturally short (5-15 line) examples that illustrate the concept well.
      
      ---
      
      ## Syntax Highlighting (Amber Night)
      
      Custom syntax theme designed for the `--color-bg-code` (#08080F) background. Warm tones dominate, with cool accents for contrast. Every color must be instantly readable against the near-black code background.
      
      ```css
      .code-keyword  { color: #F0A050; }  /* amber — keywords carry the theme color */
      .code-string   { color: #A6E3A1; }  /* soft green — strings stay calm */
      .code-function { color: #60B0E0; }  /* sky blue — function names pop */
      .code-comment  { color: #4A4A58; }  /* muted slate — comments recede */
      .code-number   { color: #F0C080; }  /* warm peach — numbers glow gently */
      .code-property { color: #E8E0D4; }  /* cream — object keys match body text */
      .code-operator { color: #50C8A0; }  /* teal — operators are structural */
      .code-tag      { color: #E08080; }  /* muted rose — HTML tags */
      .code-attr     { color: #C080E0; }  /* soft violet — HTML attributes */
      .code-value    { color: #A6E3A1; }  /* soft green — attribute values */
      ```
      
      The amber keyword color (`#F0A050`) ties code to the overall theme accent, creating visual cohesion between the UI and the code examples.
      
    • interactive-elements.md 40.4 KB
      # Interactive Elements Reference
      
      Implementation patterns for every interactive element type used in courses. Pick the elements that best serve each module's teaching goal.
      
      ## Table of Contents
      1. [Code ↔ English Translation Blocks](#code--english-translation-blocks)
      2. [Multiple-Choice Quizzes](#multiple-choice-quizzes)
      3. [Drag-and-Drop Matching](#drag-and-drop-matching)
      4. [Group Chat Animation](#group-chat-animation)
      5. [Message Flow / Data Flow Animation](#message-flow--data-flow-animation)
      6. [Interactive Architecture Diagram](#interactive-architecture-diagram)
      7. [Layer Toggle Demo](#layer-toggle-demo)
      8. ["Spot the Bug" Challenge](#spot-the-bug-challenge)
      9. [Scenario Quiz](#scenario-quiz)
      10. [Callout Boxes](#callout-boxes)
      11. [Pattern/Feature Cards](#patternfeature-cards)
      12. [Flow Diagrams](#flow-diagrams)
      13. [Permission/Config Badges](#permissionconfig-badges)
      14. [Glossary Tooltips](#glossary-tooltips)
      15. [Visual File Tree](#visual-file-tree)
      16. [Icon-Label Rows](#icon-label-rows)
      17. [Numbered Step Cards](#numbered-step-cards)
      18. [Protocol Conversation](#protocol-conversation)
      
      ---
      
      ## Code ↔ English Translation Blocks
      
      The most important teaching element. Shows real code from the project on the left and a plain English translation on the right, line by line.
      
      **HTML:**
      ```html
      <div class="translation-block animate-in">
        <div class="translation-code">
          <span class="translation-label">CODE</span>
          <pre><code>
      <span class="code-line"><span class="code-keyword">const</span> response = <span class="code-keyword">await</span> <span class="code-function">fetch</span>(url, {</span>
      <span class="code-line">  <span class="code-property">method</span>: <span class="code-string">'POST'</span>,</span>
      <span class="code-line">  <span class="code-property">headers</span>: { <span class="code-string">'Authorization'</span>: apiKey }</span>
      <span class="code-line">});</span>
          </code></pre>
        </div>
        <div class="translation-english">
          <span class="translation-label">PLAIN ENGLISH</span>
          <div class="translation-lines">
            <p class="tl">Send a request to the URL and wait for a response...</p>
            <p class="tl">We're sending data (POST), not just asking for it (GET)...</p>
            <p class="tl">Include our API key so the server knows who we are...</p>
            <p class="tl">End of the request setup.</p>
          </div>
        </div>
      </div>
      ```
      
      **CSS:**
      ```css
      .translation-block {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 0;
        border-radius: var(--radius-md);
        overflow: hidden;
        box-shadow: var(--shadow-md);
        margin: var(--space-8) 0;
      }
      .translation-code {
        background: var(--color-bg-code);
        color: #CDD6F4;
        padding: var(--space-6);
        font-family: var(--font-mono);
        font-size: var(--text-sm);
        line-height: 1.7;
        position: relative;
        overflow-x: hidden;  /* NO horizontal scrollbar — ever */
      }
      .translation-code pre,
      .translation-code code {
        white-space: pre-wrap;       /* wrap long lines instead of scrolling */
        word-break: break-word;      /* break mid-word if needed */
        overflow-x: hidden;
      }
      .translation-english {
        background: var(--color-surface-warm);
        padding: var(--space-6);
        font-size: var(--text-sm);
        line-height: 1.7;
        border-left: 3px solid var(--color-accent);
      }
      .translation-label {
        position: absolute;
        top: var(--space-2);
        right: var(--space-3);
        font-size: var(--text-xs);
        text-transform: uppercase;
        letter-spacing: 0.1em;
        opacity: 0.5;
      }
      .translation-english .translation-label {
        color: var(--color-text-muted);
      }
      /* Responsive: stack vertically on mobile */
      @media (max-width: 768px) {
        .translation-block { grid-template-columns: 1fr; }
        .translation-english { border-left: none; border-top: 3px solid var(--color-accent); }
      }
      ```
      
      **Rules:**
      - Each English line should correspond to 1-2 code lines
      - Use conversational language, not technical jargon
      - Highlight the "why" not just the "what" — e.g., "Include our API key so the server knows who we are" not "Set the Authorization header"
      
      ---
      
      ## Multiple-Choice Quizzes
      
      For testing understanding with instant feedback. Each question has options, one correct answer, and per-question explanations.
      
      **HTML:**
      ```html
      <div class="quiz-container">
        <div class="quiz-question-block" data-question="q1" data-correct="option-b">
          <h3 class="quiz-question">Question text here?</h3>
          <div class="quiz-options">
            <button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
              <div class="quiz-option-radio"></div>
              <span>Answer A</span>
            </button>
            <button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
              <div class="quiz-option-radio"></div>
              <span>Answer B (correct)</span>
            </button>
            <button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
              <div class="quiz-option-radio"></div>
              <span>Answer C</span>
            </button>
          </div>
          <div class="quiz-feedback" id="q1-feedback"></div>
        </div>
      
        <button class="quiz-check-btn" onclick="checkQuiz('section-id')">Check Answers</button>
        <button class="quiz-reset-btn" onclick="resetQuiz('section-id')">Try Again</button>
        <div class="quiz-overall-feedback" id="section-overall"></div>
      </div>
      ```
      
      **JS pattern:**
      ```javascript
      window.selectOption = function(btn) {
        // Deselect siblings
        const block = btn.closest('.quiz-question-block');
        block.querySelectorAll('.quiz-option').forEach(o => o.classList.remove('selected'));
        btn.classList.add('selected');
      };
      
      window.checkQuiz = function(sectionId) {
        const container = document.querySelector(`#${sectionId} .quiz-container`);
        const questions = container.querySelectorAll('.quiz-question-block');
        let correct = 0;
      
        questions.forEach(q => {
          const selected = q.querySelector('.quiz-option.selected');
          const feedback = q.querySelector('.quiz-feedback');
          const correctValue = q.dataset.correct;
      
          if (!selected) {
            feedback.textContent = 'Pick an answer first!';
            feedback.className = 'quiz-feedback show warning';
            return;
          }
      
          if (selected.dataset.value === correctValue) {
            correct++;
            selected.classList.add('correct');
            feedback.innerHTML = '<strong>Exactly!</strong> ' + getExplanation(q, true);
            feedback.className = 'quiz-feedback show success';
          } else {
            selected.classList.add('incorrect');
            // Highlight the correct one
            q.querySelector(`[data-value="${correctValue}"]`).classList.add('correct');
            feedback.innerHTML = '<strong>Not quite.</strong> ' + getExplanation(q, false);
            feedback.className = 'quiz-feedback show error';
          }
      
          // Disable further interaction
          q.querySelectorAll('.quiz-option').forEach(o => o.disabled = true);
        });
      };
      ```
      
      **CSS for quiz states:**
      ```css
      .quiz-option {
        display: flex; align-items: center; gap: var(--space-3);
        padding: var(--space-3) var(--space-4);
        border: 2px solid var(--color-border);
        border-radius: var(--radius-sm);
        background: var(--color-surface);
        cursor: pointer; width: 100%;
        transition: border-color var(--duration-fast), background var(--duration-fast);
      }
      .quiz-option:hover { border-color: var(--color-accent-muted); }
      .quiz-option.selected { border-color: var(--color-accent); background: var(--color-accent-light); }
      .quiz-option.correct { border-color: var(--color-success); background: var(--color-success-light); }
      .quiz-option.incorrect { border-color: var(--color-error); background: var(--color-error-light); }
      .quiz-option-radio {
        width: 18px; height: 18px; border-radius: 50%;
        border: 2px solid var(--color-border);
        transition: all var(--duration-fast);
      }
      .quiz-option.selected .quiz-option-radio {
        border-color: var(--color-accent);
        background: var(--color-accent);
        box-shadow: inset 0 0 0 3px white;
      }
      .quiz-feedback {
        max-height: 0; overflow: hidden; opacity: 0;
        transition: max-height var(--duration-normal), opacity var(--duration-normal);
      }
      .quiz-feedback.show { max-height: 200px; opacity: 1; padding: var(--space-3); margin-top: var(--space-2); border-radius: var(--radius-sm); }
      .quiz-feedback.success { background: var(--color-success-light); color: var(--color-success); }
      .quiz-feedback.error { background: var(--color-error-light); color: var(--color-error); }
      ```
      
      ---
      
      ## Drag-and-Drop Matching
      
      For matching concepts to descriptions. Supports both mouse (HTML5 Drag API) and touch.
      
      **HTML:**
      ```html
      <div class="dnd-container">
        <div class="dnd-chips">
          <div class="dnd-chip" draggable="true" data-answer="actor-a">Actor A</div>
          <div class="dnd-chip" draggable="true" data-answer="actor-b">Actor B</div>
          <div class="dnd-chip" draggable="true" data-answer="actor-c">Actor C</div>
        </div>
        <div class="dnd-zones">
          <div class="dnd-zone" data-correct="actor-a">
            <p class="dnd-zone-label">Description for Actor A</p>
            <div class="dnd-zone-target">Drop here</div>
          </div>
          <!-- more zones -->
        </div>
        <button onclick="checkDnD()">Check Matches</button>
        <button onclick="resetDnD()">Reset</button>
      </div>
      ```
      
      **JS (mouse + touch):**
      ```javascript
      // MOUSE: HTML5 Drag API
      chips.forEach(chip => {
        chip.addEventListener('dragstart', (e) => {
          e.dataTransfer.setData('text/plain', chip.dataset.answer);
          chip.classList.add('dragging');
        });
        chip.addEventListener('dragend', () => chip.classList.remove('dragging'));
      });
      
      zones.forEach(zone => {
        const target = zone.querySelector('.dnd-zone-target');
        target.addEventListener('dragover', (e) => { e.preventDefault(); target.classList.add('drag-over'); });
        target.addEventListener('dragleave', () => target.classList.remove('drag-over'));
        target.addEventListener('drop', (e) => {
          e.preventDefault();
          target.classList.remove('drag-over');
          const answer = e.dataTransfer.getData('text/plain');
          const chip = document.querySelector(`[data-answer="${answer}"]`);
          target.textContent = chip.textContent;
          target.dataset.placed = answer;
          chip.classList.add('placed');
        });
      });
      
      // TOUCH: Custom implementation (HTML5 drag doesn't work on mobile)
      chips.forEach(chip => {
        chip.addEventListener('touchstart', (e) => {
          e.preventDefault();
          const touch = e.touches[0];
          const clone = chip.cloneNode(true);
          clone.classList.add('touch-ghost');
          clone.style.cssText = `position:fixed; z-index:1000; pointer-events:none;
            left:${touch.clientX - 40}px; top:${touch.clientY - 20}px;`;
          document.body.appendChild(clone);
          chip._ghost = clone;
          chip._answer = chip.dataset.answer;
        }, { passive: false });
      
        chip.addEventListener('touchmove', (e) => {
          e.preventDefault();
          const touch = e.touches[0];
          if (chip._ghost) {
            chip._ghost.style.left = (touch.clientX - 40) + 'px';
            chip._ghost.style.top = (touch.clientY - 20) + 'px';
          }
          // Highlight zone under finger
          const el = document.elementFromPoint(touch.clientX, touch.clientY);
          zones.forEach(z => z.querySelector('.dnd-zone-target').classList.remove('drag-over'));
          if (el && el.closest('.dnd-zone-target')) {
            el.closest('.dnd-zone-target').classList.add('drag-over');
          }
        }, { passive: false });
      
        chip.addEventListener('touchend', (e) => {
          if (chip._ghost) { chip._ghost.remove(); chip._ghost = null; }
          const touch = e.changedTouches[0];
          const el = document.elementFromPoint(touch.clientX, touch.clientY);
          if (el && el.closest('.dnd-zone-target')) {
            const target = el.closest('.dnd-zone-target');
            target.textContent = chip.textContent;
            target.dataset.placed = chip._answer;
            chip.classList.add('placed');
          }
        });
      });
      ```
      
      ---
      
      ## Group Chat Animation
      
      iMessage/WeChat-style chat showing components "talking" to each other. Messages appear one by one with typing indicators.
      
      **HTML:**
      ```html
      <div class="chat-window">
        <div class="chat-messages" id="chat-messages">
          <div class="chat-message" data-msg="0" data-sender="actor-a" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-1)">A</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-1)">Actor A</span>
              <p>Hey Background, I need the data for this item.</p>
            </div>
          </div>
          <!-- more messages... -->
        </div>
      
        <div class="chat-typing" id="chat-typing" style="display:none">
          <div class="chat-avatar" id="typing-avatar">?</div>
          <div class="chat-typing-dots">
            <span class="typing-dot"></span>
            <span class="typing-dot"></span>
            <span class="typing-dot"></span>
          </div>
        </div>
      
        <div class="chat-controls">
          <button onclick="playChatNext()">Next Message</button>
          <button onclick="playChatAll()">Play All</button>
          <button onclick="resetChat()">Replay</button>
          <span class="chat-progress">0 / N messages</span>
        </div>
      </div>
      ```
      
      **JS:**
      ```javascript
      let chatIndex = 0;
      const chatMessages = document.querySelectorAll('#chat-messages .chat-message');
      
      // Actor color/avatar mapping
      const actors = {
        'actor-a': { initials: 'A', color: 'var(--color-actor-1)' },
        'actor-b': { initials: 'B', color: 'var(--color-actor-2)' },
        'actor-c': { initials: 'C', color: 'var(--color-actor-3)' },
      };
      
      window.playChatNext = function() {
        if (chatIndex >= chatMessages.length) return;
        const msg = chatMessages[chatIndex];
        const sender = msg.dataset.sender;
      
        // Show typing indicator with correct avatar
        const typing = document.getElementById('chat-typing');
        const avatar = document.getElementById('typing-avatar');
        avatar.textContent = actors[sender].initials;
        avatar.style.background = actors[sender].color;
        typing.style.display = 'flex';
      
        setTimeout(() => {
          typing.style.display = 'none';
          msg.style.display = 'flex';
          msg.style.animation = 'fadeSlideUp 0.3s var(--ease-out)';
          chatIndex++;
          updateChatProgress();
        }, 800);
      };
      
      window.playChatAll = function() {
        const interval = setInterval(() => {
          if (chatIndex >= chatMessages.length) { clearInterval(interval); return; }
          playChatNext();
        }, 1200);
      };
      ```
      
      **CSS for typing dots:**
      ```css
      .typing-dot {
        width: 8px; height: 8px; border-radius: 50%;
        background: var(--color-text-muted);
        animation: typingBounce 1.4s infinite;
      }
      .typing-dot:nth-child(2) { animation-delay: 0.2s; }
      .typing-dot:nth-child(3) { animation-delay: 0.4s; }
      @keyframes typingBounce {
        0%, 60%, 100% { transform: translateY(0); }
        30% { transform: translateY(-6px); }
      }
      ```
      
      ---
      
      ## Message Flow / Data Flow Animation
      
      Step-by-step visualization of data moving between components. User clicks "Next Step" to advance.
      
      **HTML:**
      ```html
      <div class="flow-animation">
        <div class="flow-actors">
          <div class="flow-actor" id="flow-actor-1">
            <div class="flow-actor-icon">A</div>
            <span>Actor 1</span>
          </div>
          <div class="flow-actor" id="flow-actor-2">
            <div class="flow-actor-icon">B</div>
            <span>Actor 2</span>
          </div>
          <div class="flow-actor" id="flow-actor-3">
            <div class="flow-actor-icon">C</div>
            <span>Actor 3</span>
          </div>
        </div>
      
        <div class="flow-packet" id="flow-packet"></div>
      
        <div class="flow-step-label" id="flow-label">Click "Next Step" to begin</div>
      
        <div class="flow-controls">
          <button onclick="flowNext()">Next Step</button>
          <button onclick="flowReset()">Restart</button>
          <span class="flow-progress">Step 0 / N</span>
        </div>
      </div>
      ```
      
      **JS pattern:**
      ```javascript
      const flowSteps = [
        { from: 'actor-1', to: 'actor-2', label: 'User clicks button → Actor 1 detects click event', highlight: 'actor-1' },
        { from: 'actor-1', to: 'actor-2', label: 'Actor 1 sends message to Actor 2', highlight: 'actor-2', packet: true },
        { from: 'actor-2', to: 'external', label: 'Actor 2 calls external API', highlight: 'actor-2', cloud: true },
        // etc.
      ];
      
      let flowStep = 0;
      window.flowNext = function() {
        if (flowStep >= flowSteps.length) return;
        const step = flowSteps[flowStep];
      
        // Remove previous highlights
        document.querySelectorAll('.flow-actor').forEach(a => a.classList.remove('active'));
      
        // Highlight current actor
        document.getElementById(`flow-${step.highlight}`).classList.add('active');
      
        // Animate packet if needed
        if (step.packet) {
          animatePacket(step.from, step.to);
        }
      
        // Update label
        document.getElementById('flow-label').textContent = step.label;
        flowStep++;
      };
      ```
      
      **CSS for active actor glow:**
      ```css
      .flow-actor.active {
        box-shadow: 0 0 0 3px var(--color-accent), 0 0 20px var(--color-accent-glow);
        transform: scale(1.05);
        transition: all var(--duration-normal) var(--ease-out);
      }
      ```
      
      ---
      
      ## Interactive Architecture Diagram
      
      Full-system diagram where hovering/clicking a component shows a description tooltip.
      
      **HTML:**
      ```html
      <div class="arch-diagram">
        <div class="arch-zone arch-zone-browser">
          <h4 class="arch-zone-label">Browser</h4>
          <div class="arch-component" data-desc="Injects UI into the web page, reads DOM, captures user actions"
               onclick="showArchDesc(this)">
            <div class="arch-icon">📄</div>
            <span>Component A</span>
          </div>
          <!-- more components -->
        </div>
        <div class="arch-zone arch-zone-external">
          <h4 class="arch-zone-label">External Services</h4>
          <!-- API cards -->
        </div>
        <div class="arch-description" id="arch-desc">Click any component to learn what it does</div>
      </div>
      ```
      
      ---
      
      ## Layer Toggle Demo
      
      Shows how different layers (e.g., HTML/CSS/JS, or data/logic/UI) build on each other. Three tabs switch between views.
      
      **HTML:**
      ```html
      <div class="layer-demo">
        <div class="layer-tabs">
          <button class="layer-tab active" onclick="showLayer('html')">HTML</button>
          <button class="layer-tab" onclick="showLayer('css')">+ CSS</button>
          <button class="layer-tab" onclick="showLayer('js')">+ JS</button>
        </div>
        <div class="layer-viewport">
          <div class="layer" id="layer-html" style="display:block">
            <!-- Raw unstyled version -->
          </div>
          <div class="layer" id="layer-css" style="display:none">
            <!-- Styled version -->
          </div>
          <div class="layer" id="layer-js" style="display:none">
            <!-- Interactive version -->
          </div>
        </div>
        <p class="layer-description" id="layer-desc">This is the raw HTML...</p>
      </div>
      ```
      
      ---
      
      ## "Spot the Bug" Challenge
      
      Show code with a deliberate bug. User clicks the buggy line. Reveal explains the issue.
      
      **HTML:**
      ```html
      <div class="bug-challenge">
        <h3>Find the bug in this code:</h3>
        <div class="bug-code">
          <div class="bug-line" data-line="1" onclick="checkBugLine(this, false)">
            <span class="line-num">1</span>
            <code>chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {</code>
          </div>
          <div class="bug-line" data-line="2" onclick="checkBugLine(this, false)">
            <span class="line-num">2</span>
            <code>  if (msg.action === 'fetchData') {</code>
          </div>
          <div class="bug-line bug-target" data-line="3" onclick="checkBugLine(this, true)">
            <span class="line-num">3</span>
            <code>    fetch(url).then(r => r.json()).then(data => sendResponse(data));</code>
          </div>
          <div class="bug-line" data-line="4" onclick="checkBugLine(this, false)">
            <span class="line-num">4</span>
            <code>  }</code>
          </div>
          <div class="bug-line" data-line="5" onclick="checkBugLine(this, false)">
            <span class="line-num">5</span>
            <code>});</code>
          </div>
        </div>
        <div class="bug-feedback" id="bug-feedback"></div>
      </div>
      ```
      
      **JS:**
      ```javascript
      window.checkBugLine = function(el, isCorrect) {
        const feedback = el.closest('.bug-challenge').querySelector('.bug-feedback');
        if (isCorrect) {
          el.classList.add('correct');
          feedback.innerHTML = '<strong>Found it!</strong> The listener uses an async operation (fetch) but doesn\'t return true. Chrome closes the message channel before the response can be sent. Fix: add <code>return true;</code> at the end.';
          feedback.className = 'bug-feedback show success';
        } else {
          el.classList.add('incorrect');
          feedback.innerHTML = 'Not this line — look for where the async timing might cause problems...';
          feedback.className = 'bug-feedback show error';
          setTimeout(() => { el.classList.remove('incorrect'); feedback.className = 'bug-feedback'; }, 2000);
        }
      };
      ```
      
      ---
      
      ## Scenario Quiz
      
      "What would a senior engineer do?" — situational questions with explanations.
      
      Same HTML/CSS/JS pattern as Multiple-Choice Quizzes, but with longer scenario descriptions and more detailed explanations. Wrap each question in a scenario context block:
      
      ```html
      <div class="scenario-block">
        <div class="scenario-context">
          <span class="scenario-label">Scenario</span>
          <p>Your app processes a 3-hour podcast transcript. The API has a 16,000 token limit. What do you do?</p>
        </div>
        <!-- quiz-options here -->
      </div>
      ```
      
      ---
      
      ## Callout Boxes
      
      "Aha!" moments — universal CS insights. Max 2 per module.
      
      ```html
      <div class="callout callout-accent">
        <div class="callout-icon">💡</div>
        <div class="callout-content">
          <strong class="callout-title">Key Insight</strong>
          <p>This pattern — splitting responsibilities into focused roles — is one of the most important ideas in software engineering. Engineers call it "separation of concerns."</p>
        </div>
      </div>
      ```
      
      **Variants:**
      - `callout-accent`: amber left border, light accent background (for CS insights)
      - `callout-info`: teal left border, light info background (for "good to know")
      - `callout-warning`: red left border, light error background (for common mistakes)
      
      ---
      
      ## Pattern/Feature Cards
      
      Grid of cards highlighting engineering patterns, tech stack components, or key concepts.
      
      ```html
      <div class="pattern-cards">
        <div class="pattern-card" style="border-top: 3px solid var(--color-actor-1)">
          <div class="pattern-icon" style="background: var(--color-actor-1)">🔄</div>
          <h4 class="pattern-title">Caching</h4>
          <p class="pattern-desc">Store results to avoid redundant work — like keeping leftovers instead of cooking a new meal every time.</p>
        </div>
        <!-- more cards -->
      </div>
      ```
      
      ```css
      .pattern-cards {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
        gap: var(--space-4);
      }
      .pattern-card {
        background: var(--color-surface);
        border-radius: var(--radius-md);
        padding: var(--space-6);
        box-shadow: var(--shadow-sm);
        transition: transform var(--duration-normal) var(--ease-out), box-shadow var(--duration-normal);
      }
      .pattern-card:hover {
        transform: translateY(-4px);
        box-shadow: var(--shadow-md);
      }
      ```
      
      ---
      
      ## Flow Diagrams
      
      **Horizontal flow (desktop):**
      ```html
      <div class="flow-steps">
        <div class="flow-step">
          <div class="flow-step-num">1</div>
          <p>User clicks button</p>
        </div>
        <div class="flow-arrow">→</div>
        <div class="flow-step">
          <div class="flow-step-num">2</div>
          <p>Component A detects click</p>
        </div>
        <div class="flow-arrow">→</div>
        <!-- more steps -->
      </div>
      ```
      
      Arrows rotate to `↓` on mobile via CSS transform.
      
      ---
      
      ## Permission/Config Badges
      
      For annotating config files, permissions, or settings:
      
      ```html
      <div class="badge-list">
        <div class="badge-item">
          <code class="badge-code">storage</code>
          <span class="badge-desc">Save data between sessions (like browser bookmarks)</span>
        </div>
        <div class="badge-item">
          <code class="badge-code">activeTab</code>
          <span class="badge-desc">Access the currently open tab (only when the user clicks)</span>
        </div>
      </div>
      ```
      
      ```css
      .badge-item {
        display: flex; align-items: center; gap: var(--space-4);
        padding: var(--space-3) var(--space-4);
        border: 1px solid var(--color-border-light);
        border-radius: var(--radius-sm);
        transition: border-color var(--duration-fast);
      }
      .badge-item:hover { border-color: var(--color-accent-muted); }
      .badge-code {
        font-family: var(--font-mono);
        font-size: var(--text-sm);
        background: var(--color-bg-code);
        color: #CBA6F7;
        padding: var(--space-1) var(--space-3);
        border-radius: var(--radius-sm);
        white-space: nowrap;
      }
      ```
      
      ---
      
      ## Glossary Tooltips
      
      The most important accessibility feature for non-technical learners. Any technical term in the course text should be wrapped in a tooltip that shows a plain-English definition on hover (desktop) or tap (mobile). The learner never has to leave the page or Google anything.
      
      **HTML — mark up terms inline:**
      ```html
      <p>The extension uses a
        <span class="term" data-definition="A service worker is a background script that runs independently of the web page — like a behind-the-scenes assistant that's always on, even when you're not looking at the page.">service worker</span>
        to handle API calls.
      </p>
      ```
      
      **CSS:**
      ```css
      .term {
        border-bottom: 1.5px dashed var(--color-accent-muted);
        cursor: pointer;    /* NOT cursor: help — pointer feels clickable and inviting */
        position: relative;
      }
      .term:hover, .term.active {
        border-bottom-color: var(--color-accent);
        color: var(--color-accent);
      }
      
      /* The tooltip bubble — uses position: fixed and is appended to document.body
         via JS so it is NEVER clipped by ancestor overflow: hidden containers
         (like translation blocks). See JS section below for positioning logic. */
      .term-tooltip {
        position: fixed;        /* CRITICAL: fixed, not absolute — prevents clipping */
        background: var(--color-bg-code);
        color: #CDD6F4;
        padding: var(--space-3) var(--space-4);
        border-radius: var(--radius-sm);
        font-size: var(--text-sm);
        font-family: var(--font-body);
        line-height: var(--leading-normal);
        width: max(200px, min(320px, 80vw));
        box-shadow: var(--shadow-lg);
        pointer-events: none;
        opacity: 0;
        transition: opacity var(--duration-fast);
        z-index: 10000;        /* Above everything, including nav */
      }
      /* Arrow pointing down */
      .term-tooltip::after {
        content: '';
        position: absolute;
        top: 100%;
        left: 50%;
        transform: translateX(-50%);
        border: 6px solid transparent;
        border-top-color: var(--color-bg-code);
      }
      .term-tooltip.visible {
        opacity: 1;
      }
      
      /* If tooltip goes off-screen top, flip to below */
      .term-tooltip.flip {
        bottom: auto;
        top: calc(100% + 8px);
      }
      .term-tooltip.flip::after {
        top: auto;
        bottom: 100%;
        border-top-color: transparent;
        border-bottom-color: var(--color-bg-code);
      }
      ```
      
      **JS — position: fixed tooltips appended to body (never clipped by overflow):**
      ```javascript
      // Tooltip container — appended to body so it's never clipped
      let activeTooltip = null;
      
      function positionTooltip(term, tip) {
        const rect = term.getBoundingClientRect();
        const tipWidth = 300; // approximate
        let left = rect.left + rect.width / 2 - tipWidth / 2;
        // Clamp to viewport
        left = Math.max(8, Math.min(left, window.innerWidth - tipWidth - 8));
      
        // Try above first
        let top = rect.top - 8;
        tip.style.left = left + 'px';
      
        // Position above by default, flip below if no room
        document.body.appendChild(tip);
        const tipHeight = tip.offsetHeight;
        if (rect.top - tipHeight - 8 < 0) {
          // Flip below
          tip.style.top = (rect.bottom + 8) + 'px';
          tip.classList.add('flip');
        } else {
          tip.style.top = (rect.top - tipHeight - 8) + 'px';
          tip.classList.remove('flip');
        }
      }
      
      document.querySelectorAll('.term').forEach(term => {
        const tip = document.createElement('span');
        tip.className = 'term-tooltip';
        tip.textContent = term.dataset.definition;
      
        // Hover for desktop
        term.addEventListener('mouseenter', () => {
          if (activeTooltip && activeTooltip !== tip) {
            activeTooltip.classList.remove('visible');
            activeTooltip.remove();
          }
          positionTooltip(term, tip);
          requestAnimationFrame(() => tip.classList.add('visible'));
          activeTooltip = tip;
        });
      
        term.addEventListener('mouseleave', () => {
          tip.classList.remove('visible');
          setTimeout(() => { if (!tip.classList.contains('visible')) tip.remove(); }, 150);
          activeTooltip = null;
        });
      
        // Tap for mobile
        term.addEventListener('click', (e) => {
          e.stopPropagation();
          if (activeTooltip && activeTooltip !== tip) {
            activeTooltip.classList.remove('visible');
            activeTooltip.remove();
          }
          if (tip.classList.contains('visible')) {
            tip.classList.remove('visible');
            tip.remove();
            activeTooltip = null;
          } else {
            positionTooltip(term, tip);
            requestAnimationFrame(() => tip.classList.add('visible'));
            activeTooltip = tip;
          }
        });
      });
      
      // Close tooltips when clicking elsewhere
      document.addEventListener('click', () => {
        if (activeTooltip) {
          activeTooltip.classList.remove('visible');
          activeTooltip.remove();
          activeTooltip = null;
        }
      });
      ```
      
      **Rules:**
      - Mark up EVERY technical term on first use in each module (API, DOM, callback, async, endpoint, middleware, etc.)
      - Keep definitions to 1-2 sentences max, in everyday language
      - Use a metaphor in the definition when it helps — e.g., "A **callback** is like leaving your phone number at a restaurant so they can call you when your table is ready"
      - Don't mark the same term twice within the same screen — only on first appearance per module
      - The dashed underline should be subtle enough not to distract but visible enough that curious learners discover it
      
      ---
      
      ## Visual File Tree
      
      Use instead of paragraphs listing "this folder does X, that folder does Y." Much easier to scan.
      
      ```html
      <div class="file-tree">
        <div class="ft-folder open">
          <span class="ft-name">app/</span>
          <span class="ft-desc">Pages and API routes</span>
          <div class="ft-children">
            <div class="ft-folder">
              <span class="ft-name">api/</span>
              <span class="ft-desc">Backend endpoints the frontend calls</span>
            </div>
            <div class="ft-file">
              <span class="ft-name">layout.tsx</span>
              <span class="ft-desc">The shell that wraps every page</span>
            </div>
          </div>
        </div>
        <div class="ft-folder">
          <span class="ft-name">components/</span>
          <span class="ft-desc">Reusable UI building blocks</span>
        </div>
        <div class="ft-folder">
          <span class="ft-name">lib/</span>
          <span class="ft-desc">Shared logic and utilities</span>
        </div>
      </div>
      ```
      
      ```css
      .file-tree { font-family: var(--font-mono); font-size: var(--text-sm); }
      .ft-folder, .ft-file {
        padding: var(--space-2) var(--space-3);
        border-left: 2px solid var(--color-border-light);
        margin-left: var(--space-4);
      }
      .ft-folder > .ft-name { color: var(--color-accent); font-weight: 600; }
      .ft-folder > .ft-name::before { content: '📁 '; }
      .ft-file > .ft-name::before { content: '📄 '; }
      .ft-desc {
        color: var(--color-text-secondary);
        font-family: var(--font-body);
        margin-left: var(--space-2);
        font-size: var(--text-xs);
      }
      .ft-children { margin-left: var(--space-4); }
      ```
      
      ---
      
      ## Icon-Label Rows
      
      For listing components, features, or concepts visually. Replaces bullet-point paragraphs.
      
      ```html
      <div class="icon-rows">
        <div class="icon-row">
          <div class="icon-circle" style="background: var(--color-actor-1)">🖥️</div>
          <div>
            <strong>Frontend (Next.js)</strong>
            <p>What the user sees and interacts with</p>
          </div>
        </div>
        <div class="icon-row">
          <div class="icon-circle" style="background: var(--color-actor-2)">⚡</div>
          <div>
            <strong>API Routes</strong>
            <p>Backend logic that runs on the server</p>
          </div>
        </div>
        <div class="icon-row">
          <div class="icon-circle" style="background: var(--color-actor-3)">🗄️</div>
          <div>
            <strong>Database (Supabase)</strong>
            <p>Where all the data is stored permanently</p>
          </div>
        </div>
      </div>
      ```
      
      ```css
      .icon-rows { display: flex; flex-direction: column; gap: var(--space-4); }
      .icon-row {
        display: flex; align-items: center; gap: var(--space-4);
        padding: var(--space-4);
        background: var(--color-surface);
        border-radius: var(--radius-md);
        box-shadow: var(--shadow-sm);
      }
      .icon-row p { margin: 0; color: var(--color-text-secondary); font-size: var(--text-sm); }
      .icon-circle {
        width: 48px; height: 48px; border-radius: 50%;
        display: flex; align-items: center; justify-content: center;
        font-size: 1.25rem; flex-shrink: 0;
      }
      ```
      
      ---
      
      ## Numbered Step Cards
      
      For sequences that would otherwise be a numbered paragraph list. Visual, scannable, and each step stands alone.
      
      ```html
      <div class="step-cards">
        <div class="step-card">
          <div class="step-num">1</div>
          <div class="step-body">
            <strong>User pastes a YouTube URL</strong>
            <p>The frontend captures the URL and extracts the video ID</p>
          </div>
        </div>
        <div class="step-card">
          <div class="step-num">2</div>
          <div class="step-body">
            <strong>API fetches the transcript</strong>
            <p>A server-side route calls an external service to get the video's text</p>
          </div>
        </div>
        <div class="step-card">
          <div class="step-num">3</div>
          <div class="step-body">
            <strong>AI analyzes the content</strong>
            <p>The transcript is sent to an AI model that extracts key moments</p>
          </div>
        </div>
      </div>
      ```
      
      ```css
      .step-cards { display: flex; flex-direction: column; gap: var(--space-3); }
      .step-card {
        display: flex; align-items: flex-start; gap: var(--space-4);
        padding: var(--space-4) var(--space-5);
        background: var(--color-surface);
        border-radius: var(--radius-md);
        border-left: 3px solid var(--color-accent);
        box-shadow: var(--shadow-sm);
      }
      .step-num {
        width: 32px; height: 32px; border-radius: 50%;
        background: var(--color-accent);
        color: white; font-weight: 700;
        display: flex; align-items: center; justify-content: center;
        font-family: var(--font-display);
        flex-shrink: 0;
      }
      .step-body p { margin: var(--space-1) 0 0; color: var(--color-text-secondary); font-size: var(--text-sm); }
      ```
      
      ---
      
      ## Protocol Conversation
      
      A variant of the Group Chat Animation specifically designed for API and system interactions. Instead of code components, the actors are protocol-level entities: Client App, Claude API, Claude Model, Tool Server, and User. Use this to illustrate request/response flows, streaming events, tool use cycles, and hook execution chains.
      
      **When to use:** Any time you need to show how system components communicate — API request lifecycles, streaming event sequences, tool use round-trips, or multi-step agent loops. This is the docs-to-course equivalent of the Group Chat Animation.
      
      **HTML:**
      ```html
      <div class="chat-window protocol-chat">
        <div class="chat-header">
          <span class="chat-header-title">Tool Use Round-Trip</span>
          <div class="chat-header-actors">
            <span class="actor-badge" style="--badge-color: var(--color-actor-1)">Client</span>
            <span class="actor-badge" style="--badge-color: var(--color-actor-2)">API</span>
            <span class="actor-badge" style="--badge-color: var(--color-actor-3)">Claude</span>
            <span class="actor-badge" style="--badge-color: var(--color-actor-4)">Tool</span>
          </div>
        </div>
      
        <div class="chat-messages" id="protocol-chat-messages">
          <div class="chat-message" data-msg="0" data-sender="client" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-1)">C</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-1)">Client App</span>
              <p>POST /v1/messages<br><code>{"model": "claude-opus-4-6", "tools": [...]}</code></p>
            </div>
          </div>
      
          <div class="chat-message" data-msg="1" data-sender="api" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-2)">A</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-2)">Claude API</span>
              <p>Authenticated. Forwarding to model with tool definitions...</p>
            </div>
          </div>
      
          <div class="chat-message" data-msg="2" data-sender="claude" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-3)">M</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-3)">Claude</span>
              <p>I need to look up that data. Responding with <code>stop_reason: "tool_use"</code> and a tool call block.</p>
            </div>
          </div>
      
          <div class="chat-message" data-msg="3" data-sender="client" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-1)">C</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-1)">Client App</span>
              <p>Got it — executing the tool call locally...</p>
            </div>
          </div>
      
          <div class="chat-message" data-msg="4" data-sender="tool" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-4)">T</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-4)">Tool Server</span>
              <p>Here's the result: <code>{"temperature": 22, "conditions": "sunny"}</code></p>
            </div>
          </div>
      
          <div class="chat-message" data-msg="5" data-sender="client" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-1)">C</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-1)">Client App</span>
              <p>Sending tool result back to Claude as a <code>tool_result</code> content block...</p>
            </div>
          </div>
      
          <div class="chat-message" data-msg="6" data-sender="claude" style="display:none">
            <div class="chat-avatar" style="background: var(--color-actor-3)">M</div>
            <div class="chat-bubble">
              <span class="chat-sender" style="color: var(--color-actor-3)">Claude</span>
              <p>Thanks! The weather is 22°C and sunny. <code>stop_reason: "end_turn"</code></p>
            </div>
          </div>
        </div>
      
        <div class="chat-typing" id="protocol-typing" style="display:none">
          <div class="chat-avatar" id="protocol-typing-avatar">?</div>
          <div class="chat-typing-dots">
            <span class="typing-dot"></span>
            <span class="typing-dot"></span>
            <span class="typing-dot"></span>
          </div>
        </div>
      
        <div class="chat-controls">
          <button onclick="playProtocolNext()">Next Message</button>
          <button onclick="playProtocolAll()">Play All</button>
          <button onclick="resetProtocol()">Replay</button>
          <span class="chat-progress" id="protocol-progress">0 / 7 messages</span>
        </div>
      </div>
      ```
      
      **Suggested actor mapping for Claude documentation courses:**
      
      | Role | Avatar | Color Variable | Use For |
      |------|--------|---------------|---------|
      | Client App | C | `--color-actor-1` (amber) | Your application code making API calls |
      | Claude API | A | `--color-actor-2` (teal) | The API gateway — auth, routing, rate limits |
      | Claude (Model) | M | `--color-actor-3` (plum) | Claude's reasoning and responses |
      | Tool Server | T | `--color-actor-4` (golden) | External tools, MCP servers, databases |
      | User | U | `--color-actor-5` (sky blue) | The end user interacting with the app |
      
      **Additional CSS for protocol variant:**
      ```css
      .protocol-chat .chat-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: var(--space-3) var(--space-4);
        background: var(--color-bg-code);
        border-radius: var(--radius-md) var(--radius-md) 0 0;
      }
      .chat-header-title {
        color: #CDD6F4;
        font-family: var(--font-mono);
        font-size: var(--text-sm);
      }
      .chat-header-actors {
        display: flex;
        gap: var(--space-2);
      }
      .actor-badge {
        font-size: var(--text-xs);
        padding: 2px 8px;
        border-radius: var(--radius-full);
        background: color-mix(in srgb, var(--badge-color) 15%, transparent);
        color: var(--badge-color);
        font-weight: 600;
      }
      /* Code snippets inside chat bubbles */
      .protocol-chat .chat-bubble code {
        background: var(--color-bg-code);
        color: #CDD6F4;
        padding: 1px 6px;
        border-radius: var(--radius-sm);
        font-family: var(--font-mono);
        font-size: 0.85em;
      }
      ```
      
      **JS:** Uses the same pattern as the Group Chat Animation (see above). Replace actor names and IDs:
      
      ```javascript
      const protocolActors = {
        'client': { initials: 'C', color: 'var(--color-actor-1)', name: 'Client App' },
        'api':    { initials: 'A', color: 'var(--color-actor-2)', name: 'Claude API' },
        'claude': { initials: 'M', color: 'var(--color-actor-3)', name: 'Claude' },
        'tool':   { initials: 'T', color: 'var(--color-actor-4)', name: 'Tool Server' },
        'user':   { initials: 'U', color: 'var(--color-actor-5)', name: 'User' },
      };
      
      // Same playChatNext/playChatAll/resetChat logic as Group Chat Animation,
      // but targeting #protocol-chat-messages and #protocol-typing elements.
      ```
      
      **Scenario ideas for documentation courses:**
      - **Messages API lifecycle** — Client → API → Claude → response
      - **Tool use round-trip** — Client → Claude → "I need a tool" → Client executes → sends result → Claude responds
      - **Streaming flow** — API sends message_start → content_block_start → content_block_delta (repeated) → message_stop
      - **Hook execution chain** — User action → Claude proposes tool → PreToolUse hook fires → hook allows/blocks → tool executes
      - **MCP server connection** — Claude Code → discovers MCP server → lists tools → calls tool → gets result
      - **Agent loop** — User prompt → Claude thinks → uses tool → observes result → thinks again → responds
      
  • SKILL.md 25.2 KB
    ---
    name: claude-docs-course
    description: >
      Generate an interactive, self-contained HTML course on any Claude documentation
      topic. Use this skill when the user wants to create an interactive course,
      tutorial, or deep-dive walkthrough about a Claude feature, API concept, SDK
      pattern, or prompt engineering technique. Triggers on: "create a course about",
      "interactive tutorial for", "teach me about X interactively", "make a course on",
      "I'd like a course", "/docs --course", "/docs course", or when the user accepts
      the post-docs course prompt. Produces a stunning single-page HTML file with
      scroll-based navigation, animated visualizations, quizzes, and code translations
      drawn from official Claude documentation.
    ---
    
    # Docs-to-Course
    
    Transform any Claude documentation topic into a stunning, interactive single-page HTML course. The output is a single self-contained HTML file (no dependencies except Google Fonts) that teaches the topic through scroll-based modules, animated visualizations, embedded quizzes, and plain-English translations of real API examples and configuration snippets from the official docs.
    
    ## First-Run Welcome
    
    When the skill is first triggered and the user hasn't specified a topic yet, introduce yourself:
    
    > **I can turn any Claude topic into an interactive course — visual explanations, animated diagrams, and hands-on quizzes, all in a single HTML file.**
    >
    > Tell me a topic:
    > - **A Claude Code feature** — e.g., "create a course on hooks"
    > - **An API concept** — e.g., "make a course about tool use"
    > - **An SDK pattern** — e.g., "interactive tutorial for Agent SDK sessions"
    > - **A technique** — e.g., "teach me about extended thinking interactively"
    >
    > I'll read through the official documentation, design a learning arc, and generate a beautiful single-page HTML course with animated protocol diagrams, code explanations, and interactive quizzes. Opens right in your browser — no setup needed.
    
    If the user just came from a `/docs` response, the topic is already known — skip the welcome and start building.
    
    ## Who This Is For
    
    The target learner is a **developer building with Claude** — someone who has general technical literacy but wants to deeply understand a specific Claude feature, API concept, or SDK pattern before using it in their project.
    
    **Assume general technical literacy.** The learner knows what APIs, functions, JSON, and HTTP requests are. They don't need basic programming concepts explained. But they DO need Claude-specific concepts, patterns, and terminology explained thoroughly — tokens, context windows, tool_use blocks, stop sequences, system prompts, streaming events, hook matchers, MCP servers, etc.
    
    **Their goals are practical:**
    - **Master a Claude feature** before using it in production — understand not just the API surface, but the mental model, edge cases, and best practices
    - **Make confident architectural decisions** — know which Claude feature to use for a given problem, understand tradeoffs
    - **Debug effectively** — when something doesn't work as expected, know where to look and what to check
    - **Stay current** — Claude's capabilities evolve fast; deep understanding beats surface-level familiarity
    - **Communicate precisely** — use the correct terminology when discussing Claude integrations with teammates
    
    **They are NOT beginners at programming.** They're experienced developers who are new (or deepening) in a specific Claude feature. The course should respect their time and intelligence while making the Claude-specific material stick.
    
    ## Why This Approach Works
    
    Documentation is comprehensive but flat — it lists features, parameters, and examples without a learning arc. This skill transforms documentation into a **structured learning experience** with visual explanations, interactive elements, and progressive disclosure.
    
    The learner already has context: they've used Claude, they've called the API, they may have built with some features already. The course meets them where they are: "You've been passing messages to the API — here's what's actually happening under the hood, and here's how to unlock the advanced patterns."
    
    Every module answers **"when and why would I use this?"** before "how does it work?" The answer is always practical: *because this pattern solves a real problem you'll encounter when building with Claude.*
    
    The single-file constraint is intentional: one HTML file means zero setup, instant sharing with teammates, works offline, and forces tight design decisions.
    
    ---
    
    ## The Process (4 Phases)
    
    ### Phase 1: Topic Discovery
    
    Before writing course HTML, deeply understand the topic by reading all relevant documentation. Thoroughness here pays off — the more you understand, the better the course.
    
    **How to find documentation files:**
    
    Use the search scripts (they read the manifest + index, so they see every page whether or not it is cached):
    
    1. **Content search** — for questions or compound topics:
       ```bash
       bash ~/.claude-code-docs/plugin/skills/claude-docs/scripts/content-search.sh "<keyword1>" "<keyword2>"
       ```
    
    2. **Fuzzy search** — for approximate names:
       ```bash
       bash ~/.claude-code-docs/plugin/skills/claude-docs/scripts/fuzzy-search.sh "<query>"
       ```
    
    3. **By category** — list a whole product's pages:
       ```bash
       jq -r '.pages[] | select(.category=="claude_code") | .filename' ~/.claude-code-docs/paths_manifest.json
       ```
    
    **Reading a page:** pages are cached at `~/.claude-code-docs/cache/<filename>`. If a file
    isn't there yet, fetch it first, then read it:
    ```bash
    ~/.claude-code-docs/plugin/scripts/fetch-docs.sh get "<filename>"
    ```
    (Fetching several? Run `~/.claude-code-docs/plugin/scripts/fetch-docs.sh sync` once instead.)
    
    **What to read:**
    - Read the top 5-8 matching docs for the topic (fetching any that aren't cached)
    - Read 1-2 adjacent/related docs for context (e.g., if the topic is "hooks", also skim the skills and settings docs)
    - Cap at 10 docs total to avoid context exhaustion
    
    **What to extract:**
    - Concept definitions and mental models — how does this feature actually work?
    - API endpoints, parameters, and their purposes
    - Real code examples (Python, TypeScript, cURL, JSON configs) — these become your code translations
    - Configuration options and their defaults
    - Common patterns and recommended approaches
    - Edge cases, gotchas, and error scenarios
    - Connections to related features
    
    **Figure out the learning story yourself** from the documentation. Don't ask the user to explain the topic — build the narrative from what the docs reveal. The course should open by explaining why this feature exists and what problem it solves, then progressively peel back layers.
    
    ### Phase 2: Curriculum Design
    
    Structure the course as 4-7 modules. Documentation topics are typically more focused than entire codebases, so fewer modules are usually appropriate. The arc starts from what the learner already knows (general Claude usage) and moves toward what they don't (deep feature knowledge).
    
    | Module Position | Purpose | Example for "hooks" |
    |---|---|---|
    | 1 | "What is this and why should you care?" | What hooks are, what problems they solve, what you can automate |
    | 2 | "The mental model" | Hook lifecycle diagram, event types, when each fires |
    | 3 | "See it in action" | Real hook configs with code translations, walking through examples |
    | 4 | "The details that matter" | Matcher patterns, JSON schemas, timeout handling, async behavior |
    | 5 | "Patterns and recipes" | Common use cases — auto-formatting, CI/CD gates, security checks |
    | 6 | "Connect the dots" | How hooks relate to skills, MCP, permissions — the bigger picture |
    
    Not every topic needs all 6. A narrow feature (like "prompt caching") might only need 3-4 modules. A broad one (like "tool use") might need 6-7. Adapt the arc to the topic's depth.
    
    **The key principle:** Every module should connect to a practical skill — building better, debugging faster, or making smarter architecture decisions. If a module doesn't help the learner DO something, cut it or reframe it until it does.
    
    **Each module should contain:**
    - 3-6 screens (sub-sections that flow within the module)
    - At least one code-with-English translation (API calls, config snippets, CLI commands)
    - At least one interactive element (quiz, visualization, or animation)
    - One or two "aha!" callout boxes with practical insights
    - A metaphor that grounds the Claude concept in something tangible — but NEVER reuse the same metaphor across modules. Pick metaphors that organically fit each specific concept. Examples: hooks are "tripwires that trigger actions", streaming is a "live news ticker", tool use is a "Swiss army knife Claude carries", context windows are "working memory on a desk", prompt caching is "bookmarking your place in a conversation".
    
    **Mandatory interactive elements (every course must include ALL of these):**
    - **Protocol Conversation** — at least one across the course. iMessage/chat-style conversations between system actors (Client App, Claude API, Claude Model, Tool Server) showing how they exchange messages. These bring protocol-level concepts to life.
    - **Data Flow Animation** — at least one across the course. Step-by-step visualization of data moving through the system — API request lifecycles, streaming event flows, hook execution chains.
    - **Code ↔ English Translation Blocks** — at least one per module. Real code from the documentation (API calls, JSON configs, CLI commands) with plain-English translation on the right.
    - **Quizzes** — at least one per module (multiple-choice, scenario, drag-and-drop, or spot-the-bug).
    - **Glossary Tooltips** — on every Claude-specific term, first use per module.
    
    These five element types are the backbone of every course. Other interactive elements (architecture diagrams, layer toggles, pattern cards, etc.) are optional and should be added when they fit. But the five above must ALWAYS be present — no exceptions.
    
    **Do NOT present the curriculum for approval — just build it.** The user wants a course, not a planning document. Design the curriculum internally, then go straight to generating the HTML. If they want changes, they'll tell you after seeing the result.
    
    ### Phase 3: Build the Course
    
    Generate a single HTML file with embedded CSS and JavaScript. Read `references/design-system.md` for the complete CSS design tokens, typography, and color system. Read `references/interactive-elements.md` for implementation patterns of every interactive element type.
    
    **Build order (task by task):**
    
    1. **Foundation first** — HTML shell with all module sections (empty), complete CSS design system, navigation bar with progress tracking, scroll-snap behavior, keyboard navigation, and scroll-triggered animations. After this step, you should have a working skeleton you can scroll through.
    
    2. **One module at a time** — Fill in each module's content, code translations, and interactive elements. Don't try to write all modules in one pass — the quality drops. Build Module 1, verify it works, then Module 2, etc.
    
    3. **Polish pass** — After all modules are built, do a final pass for transitions, mobile responsiveness, and visual consistency.
    
    **Critical implementation rules:**
    - The file must be completely self-contained (only external dependency: Google Fonts CDN)
    - Use CSS `scroll-snap-type: y proximity` (NOT `mandatory` — mandatory traps users in long modules)
    - Use `min-height: 100dvh` with `100vh` fallback for sections
    - Only animate `transform` and `opacity` for GPU performance
    - Wrap all JS in an IIFE, use `passive: true` on scroll listeners, throttle with `requestAnimationFrame`
    - Include touch support for drag-and-drop, keyboard navigation (arrow keys), and ARIA attributes
    
    ### Phase 4: Save, Review, and Open
    
    **Save the course** to the dedicated courses directory:
    
    ```bash
    mkdir -p ~/.claude-code-docs/courses
    ```
    
    Name the file based on the topic: `~/.claude-code-docs/courses/<topic-slug>.html`
    - Use kebab-case: "prompt caching" → `prompt-caching.html`, "tool use" → `tool-use.html`
    - If a file with that name already exists, append a number: `hooks-2.html`
    
    After saving, open the file in the browser for the user to review. Walk them through what was built — the module arc, the key interactive elements, and the learning progression. Tell them where the file is saved so they can share it or revisit it later. Ask for feedback on content, design, and interactivity.
    
    ---
    
    ## Content Philosophy
    
    These principles are what separate a great course from a generic tutorial. They should guide every content decision:
    
    ### Show, Don't Tell — Aggressively Visual
    Developers' eyes glaze over text blocks too. The course should feel closer to an interactive reference than a wall of documentation. Follow these hard rules:
    
    **Text limits:**
    - Max **2-3 sentences** per text block. If you're writing a fourth sentence, stop and convert it into a visual instead.
    - No text block should ever be wider than the content width AND taller than ~4 lines. If it is, break it up with a visual element.
    - Every screen must be **at least 50% visual** (diagrams, code blocks, cards, animations, badges — anything that isn't a paragraph).
    
    **Convert text to visuals:**
    - A list of 3+ items → **cards with icons** (pattern cards, feature cards)
    - A sequence of steps → **flow diagram with arrows** or **numbered step cards**
    - "Client sends request to API" → **animated data flow** or **protocol conversation**
    - "This parameter does X, that parameter does Y" → **side-by-side comparison columns** or **config badges**
    - Explaining what code does → **code↔English translation block** (not a paragraph *about* the code)
    - Comparing two approaches → **side-by-side columns** with visual contrast
    
    **Visual breathing room:**
    - Use generous spacing between elements (`--space-8` to `--space-12` between sections)
    - Alternate between full-width visuals and narrow text blocks to create rhythm
    - Every module should have at least one "hero visual" — a diagram, animation, or interactive element that dominates the screen and teaches the core concept at a glance
    
    ### Code ↔ English Translations
    Every code example gets a side-by-side plain English translation. Left panel: real code from the documentation (API calls, JSON configs, CLI commands) with syntax highlighting. Right panel: line-by-line plain English explaining what each part does and *why*.
    
    **Critical: No horizontal scrollbars on code.** All code must use `white-space: pre-wrap` so it wraps instead of scrolling. Readability beats preserving indentation structure.
    
    **Critical: Use documentation examples exactly as-is.** Never modify, simplify, or trim code examples from the docs. The learner should be able to find the exact same example in the official documentation — that builds trust and makes the course a companion to the docs, not a replacement. Instead of editing code to make it shorter, *choose* naturally short, punchy examples (5-15 lines) from the docs that illustrate the concept well.
    
    ### One Concept Per Screen
    No walls of text. Each screen within a module teaches exactly one idea. If you need more space, add another screen — don't cram.
    
    ### Metaphors First, Then Reality
    Introduce every new Claude concept with a metaphor from everyday life. Then immediately ground it: "In Claude's API, this looks like..." The metaphor builds intuition; the code grounds it in reality.
    
    **Critical: No recycled metaphors.** Each concept deserves its own metaphor that feels natural to *that specific idea*. Context windows as "desk space", tokens as "word fragments in a shredder", system prompts as "stage directions for an actor", tool use as "a Swiss army knife", streaming as "a live ticker". Pick the metaphor that makes the concept click, not the one that's easiest to reach for.
    
    ### Learn by Tracing
    Follow what actually happens when the developer makes a familiar API call — trace the request end-to-end. "You've been sending messages to Claude — here's the full lifecycle of that request, from your code to Claude's response, step by step." This works because the learner has *already used the feature* — now they're seeing the machinery behind it.
    
    ### Make It Memorable
    Use "aha!" callout boxes for practical insights. Use humor where natural (not forced). Give system actors personality in protocol conversations — Claude, the API gateway, the tool server are "characters" in the story, not abstract boxes.
    
    ### Glossary Tooltips — Claude-Specific Terms
    Every Claude-specific term gets a dashed-underline tooltip on first use in each module. Hover on desktop or tap on mobile to see a 1-2 sentence definition grounded in practical usage.
    
    **Tooltip scope for developer audience:** Don't tooltip basic programming terms (function, variable, JSON, API). DO tooltip:
    - Claude-specific concepts: tokens, context window, stop sequences, tool_use blocks, content blocks, thinking blocks
    - Anthropic-specific terms: Messages API, Admin API, prompt caching, extended thinking, adaptive thinking
    - Claude Code terms: hooks, matchers, skills, MCP servers, CLAUDE.md, sub-agents
    - Agent SDK terms: sessions, agent loop, tool search, slash commands
    - Protocol terms: SSE (Server-Sent Events), streaming deltas, stop_reason values
    - Acronyms on first use — even common ones in a Claude context (MCP, SSE, IIFE, ARIA)
    
    **The vocabulary IS the learning.** Each tooltip should teach the term in a way that helps the learner USE it correctly — e.g., "**stop_reason** — tells you *why* Claude stopped generating. `end_turn` means Claude finished naturally. `tool_use` means Claude wants to call a tool. Check this to decide your next action."
    
    **Cursor:** Use `cursor: pointer` on terms (not `cursor: help`). The question-mark cursor feels clinical — a pointer feels clickable and inviting.
    
    **Tooltip overflow fix:** Translation blocks and other containers with `overflow: hidden` will clip tooltips. To fix this, the tooltip JS must use `position: fixed` and calculate coordinates from `getBoundingClientRect()` instead of relying on CSS `position: absolute` within the container. Append tooltips to `document.body` rather than inside the term element.
    
    ### Quizzes That Test Application, Not Memory
    
    Quizzes should test whether the learner can use their knowledge to solve a real problem, not whether they can regurgitate parameter names.
    
    **What to quiz (in order of value):**
    1. **"What would you use?" scenarios** — "You want to let Claude browse the web during a conversation. Which feature would you configure?" Tests whether they understood the feature landscape.
    2. **Debugging scenarios** — "Your streaming response cuts off mid-sentence with stop_reason: max_tokens. What's happening and what should you change?" Tests practical understanding.
    3. **Architecture decisions** — "You're building an agent that needs to remember context across sessions. Which approach would you use: prompt caching, the Files API, or external storage?" Tests tradeoff reasoning.
    4. **Configuration challenges** — "Write the hook matcher JSON that would block all file deletions during CI runs." Tests whether they can apply the syntax.
    
    **What NOT to quiz:**
    - Definitions ("What is a token?") — that's what the glossary tooltips are for
    - Parameter recall ("What's the default max_tokens?") — that's what docs are for
    - Exact syntax ("Write the correct API call") — this isn't a coding exam
    - Anything that can be answered by scrolling up — that tests scrolling, not understanding
    
    **Quiz tone:**
    - Wrong answers get encouraging, helpful explanations ("Not quite — here's why...")
    - Correct answers get brief reinforcement of the underlying principle ("Exactly! This works because...")
    - Never punitive, never score-focused. No "You got 3/5!" — the quiz is a thinking exercise, not an exam
    
    **How many quizzes:** One per module, placed at the end. 3-5 questions per quiz. Each question should make the learner pause and *think*.
    
    ---
    
    ## Topic Scope Control
    
    Documentation topics vary wildly in breadth. A clear scoping strategy prevents courses from becoming unfocused.
    
    **Narrow topics** (hooks, prompt caching, streaming) — 3-5 modules, read all relevant docs. These make the best courses.
    
    **Medium topics** (tool use, Agent SDK, MCP) — 5-7 modules. May need to prioritize which aspects to cover deeply vs. mention in passing.
    
    **Broad topics** (Claude API, "everything about Claude Code") — Too broad for a single course. Narrow to a specific sub-topic and suggest related courses:
    > "The Claude API is too broad for one course. I'll focus on **the Messages API and tool use** — the core of building with Claude. For streaming, batch processing, and admin APIs, you can generate separate courses."
    
    **Rule of thumb:** If you'd need to read more than 10 doc files to cover the topic, it's too broad. Narrow it.
    
    ---
    
    ## Design Identity — Obsidian & Amber
    
    The visual design should feel like discovering knowledge in a **luxury developer observatory** — deep, atmospheric, and unmistakable. Read `references/design-system.md` for the full token system, but here are the non-negotiable principles:
    
    - **Dark obsidian palette**: Deep navy-black backgrounds (#0D0D16) with warm undertones — never pure black, never cold gray. The darkness creates focus; the warmth creates comfort.
    - **Amber accent**: Warm amber-gold (#F0A050) as the signature color. Used sparingly — for interactive highlights, active states, and glow effects. Amber evokes lamplight, discovery, and illumination.
    - **Editorial typography**: Instrument Serif for display headings — sharp, elegant serifs that create immediate visual identity. The contrast between serif headings and clean sans body text (Outfit) is the signature of this theme. NEVER use Inter, Roboto, Arial, Space Grotesk, or any generic sans-serif for headings.
    - **Generous whitespace**: Modules breathe against the dark background. Max 3-4 short paragraphs per screen.
    - **Alternating depths**: Even/odd modules alternate between two dark tones for subtle visual rhythm
    - **Inky code blocks**: Near-black (#08080F) with amber-tinted syntax highlighting that echoes the theme accent
    - **Grain texture**: Subtle analog noise overlay across all surfaces — adds warmth and prevents the "dead screen" flatness of digital dark themes
    - **Amber glow**: Interactive elements emit a soft amber glow on hover and focus, drawing the eye like lamplight
    - **Glass-morphism**: Elevated surfaces use backdrop-filter blur with faint border highlights for depth
    
    ---
    
    ## Gotchas — Common Failure Points
    
    Check every one of these before considering a course complete.
    
    ### Tooltip Clipping
    Translation blocks use `overflow: hidden` for code wrapping. If tooltips use `position: absolute` inside the term element, they get clipped by the container. **Fix:** Tooltips must use `position: fixed` and be appended to `document.body`. Calculate position from `getBoundingClientRect()`. This is the #1 bug in every build.
    
    ### Under-Tooltipping Claude Terms
    The most common failure is under-tooltipping. Claude-specific terms like MCP, SSE, content blocks, stop_reason, tool_use, matchers, CLAUDE.md, sub-agents — all need tooltips on first use per module. **Rule:** if a term is specific to Claude/Anthropic and wouldn't be known to a developer who hasn't used Claude before, tooltip it.
    
    ### Walls of Text
    The course looks like reformatted documentation instead of a visual learning experience. This happens when you write more than 2-3 sentences in a row without a visual break. Every screen must be at least 50% visual.
    
    ### Recycled Metaphors
    Using the same metaphor for different concepts. Every module needs its own metaphor that feels inevitable for that specific concept.
    
    ### Documentation Example Modifications
    Trimming, simplifying, or "cleaning up" code examples from the docs. The learner should be able to find the exact same code in the official documentation. Choose naturally short examples rather than editing longer ones.
    
    ### Topic Scope Creep
    Trying to cover everything related to a topic instead of staying focused. If the topic is "hooks," don't also try to teach MCP, skills, and permissions in depth. Mention them in the "Connect the dots" module and suggest separate courses.
    
    ### Quiz Questions That Test Memory
    Asking "What's the default max_tokens?" or "Name the hook event types" — those test recall, not understanding. Every quiz question should present a scenario the learner hasn't seen and ask them to *apply* what they learned.
    
    ### Scroll-Snap Mandatory
    Using `scroll-snap-type: y mandatory` traps users inside long modules. Always use `proximity`.
    
    ### Module Quality Degradation
    Trying to write all modules in one pass causes later modules to be thin and rushed. Build one module at a time and verify each before moving on.
    
    ### Missing Interactive Elements
    A module with only text and code blocks, no interactivity. Every module needs at least one of: quiz, data flow animation, protocol conversation, architecture diagram, drag-and-drop.
    
    ---
    
    ## Reference Files
    
    The `references/` directory contains detailed implementation specs. Read them when you reach the relevant phase:
    
    - **`references/design-system.md`** — Complete CSS custom properties, color palette, typography scale, spacing system, shadows, animations, scrollbar styling. Read this before writing any CSS.
    - **`references/interactive-elements.md`** — Implementation patterns for every interactive element: drag-and-drop quizzes, multiple-choice quizzes, code↔English translations, protocol conversations, message flow visualizations, architecture diagrams, pattern cards, callout boxes. Read this before building any interactive elements.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related