---
name: interactive-content
description: "Build interactive HTML learning activities for Canvas pages."
---

# Interactive Content Creation Skill

> **HPI/ID standard** — this skill applies the HPI/ID practitioner standard automatically (CLAUDE.md §Operating Standard: HPI/ID Practitioner). Ground decisions in `standards/instructional-design.md` — design sections 1–12 and the HPI diagnostic layer in Section 13. Name the framework behind every judgment; every design recommendation carries gap → data → principle → mechanism.

> **Assurance by design (light touch)**: interactives are formative, not the graded anchor, so `standards/assessment-assurance-design.md` does not apply to the default iframe path. If an interactive is made gradable (SCORM), apply the standard to that graded instrument.

> **Gradable-vs-formative gate (mandatory, ask first)**: Before generating OR deploying any interactive, ASK the user which it is — do not assume:
> - **(a) Gradable assessment** → package as **SCORM** (`--scorm`, Path 4). Posts completion/score to the Canvas gradebook. Choose when the interactive is the graded instrument (decision sim graded on the path, scored knowledge check, tracked completion requirement).
> - **(b) Formative visualization** → default **iframe** (Path 1/2). No gradebook passback. Choose when the purpose is to explain/visualize a concept, retrieval practice, or any ungraded self-check.
>
> One plain question — e.g. *"Should this be a graded SCORM assessment (posts to the gradebook) or a formative iframe (visualization / ungraded practice)?"* — before you build or deploy. The two paths differ at generation time (the interactive must call `window.ASUCB.complete()` to report a grade), so the choice cannot be deferred to deploy. If the user is unsure, default to **formative iframe** and say so. Never ship a SCORM-graded interactive without an explicit gradable choice, and never silently drop a gradable interactive into a non-reporting iframe.


> **Write Safety**: Interactive content uploads files to Canvas Files and modifies Canvas pages. Per CLAUDE.md §Write Safety Guard, Claude must obtain explicit user approval after the preview step before invoking deploy_interactives.py. The staging-server preview is the user's review surface; do not skip it.

> **Iframe-only delivery (mandatory)**: Never place `<script>` in a Canvas page body — Canvas strips it. EVERY JS interactive deploys as an uploaded HTML file + `<iframe src=.../files/{id}/preview>`. This applies to hand-built/custom interactives too, not only generator output. For a single standalone HTML interactive, run `python scripts/deploy_interactives.py --html-file PATH --title TITLE [--module-id ID]` to upload it and create its iframe host page.

> **Browser verification (mandatory)**: After deploy, every interactive must be loaded and exercised in a real browser (Playwright or the Preview MCP) — render + interact (click/drag/submit) + screenshot — before claiming it works. HTTP 200 is NOT verification. Verify *every* interactive, not a sample.

> **Plugin**: ASU Canvas Course Builder
> **Scripts**: `scripts/generator.py` (generates HTML), `scripts/deploy_interactives.py` (uploads to Canvas)

## Purpose
Design interactive learning activities embedded throughout a course to:
- Provide **immediate formative feedback** during self-paced learning
- Support **retrieval practice** (more effective than re-reading)
- Make **abstract concepts** concrete through visual manipulation
- Offer **applied reasoning practice** via branching decision scenarios
- Reduce cognitive load by **segmenting** complex topics into interactive chunks

Interactive content is NOT for the sake of interactivity — every activity must serve a specific learning objective and be the right tool for that objective (not just the most impressive one).

## Deployment Paths

**First decide the gate above** (gradable SCORM vs formative iframe) — ask the user before generating. The choice selects the path: gradable → Path 4 (SCORM); formative → Path 1/2 (iframe).

### Path 1: Built-in HTML Generator → Canvas iframe (Primary)
- **Use for**: Dialog Cards, Sequencing, Fill-in-the-Blanks, Branching Scenarios, Review Quizzes
- **Output**: Self-contained HTML/CSS/JS files (no external dependencies)
- **Cost**: Free
- **Gradebook**: No passback (formative only — graded items use Canvas quizzes/assignments)
- **Workflow**:
  > **ASK FIRST**: Before generating ANY interactive activity, ASK the user: `Include "Download my results" button? (Y/N) — gives students a printable artifact of their session; non-graded by design.` Set `download_results: True` only on explicit Y.
  1. Generate — Claude runs `python scripts/generator.py <content_data.py> --course-id <id>`. HTML files write to `courses/{id}/staging/interactives/<module-key>/`.
  2. Preview — Start the staging server and review at `http://127.0.0.1:8111/courses/{id}/interactives/<module>/<activity>` (or the canonical v7.5.0 form `http://127.0.0.1:8111/courses/{id}/preview/interactives/<module>/<activity>` — both routes work permanently).
  3. Preflight — `deploy_interactives.py` runs the deterministic preflight subset automatically before any Canvas deploy.
  4. Approval gate — Wait for explicit user approval before deploy. The user must say "deploy", "approved", "looks good", or equivalent. Do not infer approval from silence or from "thanks".
  5. Deploy — Only after approval, run `python scripts/deploy_interactives.py <content_data.py> --from-staging`. This uploads files to Canvas Files and embeds iframes.
  6. Verify — Confirm Canvas pages updated; surface Canvas URL. **Browser-verify (mandatory): load each deployed interactive in a real browser (Playwright or the Preview MCP), exercise it (click/drag/submit), and screenshot before claiming it works. HTTP 200 is not verification. Verify every interactive, not a sample.**

### Path 2: Custom HTML Activity → Canvas iframe
- **Use for**: Any activity type not covered by the 5 built-in types — custom interactions designed by Claude based on your description
- **Output**: Self-contained HTML/CSS/JS file with ASU branding and WCAG compliance
- **Cost**: Free
- **Workflow**: Describe what you want → Claude generates the HTML into `courses/{id}/staging/interactives/` → Preview in the staging server → Preflight runs automatically → explicit user approval → deploy with `deploy_interactives.py --from-staging`
- **Preflight gate**: Custom-mode HTML is hard-blocked on deterministic accessibility failures from `scripts/check_interactive_a11y.py`. This is a subset of WCAG 2.1 AA, not a full conformance claim. Fix failures before deploy; warnings should be reviewed but do not block deploy.
- **See**: Custom Activity Mode section below

### Path 3: External Embeds (Simulations, Interactive Videos)
- **Use for**: PhET simulations, PlayPosit interactive videos, Lumi (H5P exports), discipline-specific tools
- **Cost**: Varies (PhET is free; Lumi is free; PlayPosit may require institutional license)
- **Workflow**: Create externally → Export as HTML or get embed URL → Upload/embed via iframe

### Path 4: SCORM Export (opt-in, gradebook passback)
- **Use for**: a self-contained interactive that must post **completion or a score to the Canvas gradebook** without being a native Canvas quiz (e.g., a branching decision sim graded on the decision path). This is the ONE delivery path with real gradebook passback — the iframe paths (1–3) are formative-only.
- **When NOT to use**: if the goal is just a formative activity, keep the iframe (Path 1/2). SCORM costs minimal-diff editing (re-zip + re-upload per change) and is opaque to the WCAG static checks that scan page bodies. Only reach for it when the tracked grade is the point.
- **How**: `python scripts/package_scorm.py --html-file PATH --title TITLE [--mode scored --mastery-score N]`, or `deploy_interactives.py --html-file PATH --title TITLE --scorm [--scorm-mode scored --scorm-mastery N]`. Produces a SCORM 1.2 `.zip`. The packager injects a `window.ASUCB` bridge (`findAPI` → `LMSInitialize` → set `cmi.core.lesson_status`/`score.raw` → `LMSCommit` → `LMSFinish`); the bridge no-ops cleanly when no LMS API is present, so the same HTML still works as a plain iframe.
- **Interactive must call the bridge**: generator output / hand-built HTML must call `window.ASUCB.complete(score, suspendData)` at its terminal screen (one line). Without that call the bridge stays dormant and nothing posts.
- **ASU import is a manual UI step (no API)**: ASU Canvas has no SCORM content-migration API and does NOT import via the Files UI. Upload through the **SCORM tool** (Course nav → "SCORM" → Upload), then "Choose import type" → "graded assignment" → Go. This creates an External-Tool assignment (100 pts default) + gradebook column. The packager prints these exact steps. **Verified end-to-end on canvas.asu.edu (2026-06-12): score posts to the gradebook.**
- **Scope**: SCORM 1.2 only. `completion` mode (default) or `scored` (0–100, optional mastery threshold → passed/failed).

### Canvas iframe Template
```html
<iframe src="/courses/[COURSE_ID]/files/[FILE_ID]/preview"
        width="100%" height="600"
        style="border: 1px solid #ccc; border-radius: 8px;"
        sandbox="allow-same-origin allow-scripts allow-forms"
        scrolling="no"
        title="[Activity Title]"
        loading="lazy">
</iframe>
```

## Built-in Activity Types (Python Generator)

The `scripts/generator.py` produces self-contained HTML files for 5 activity types:

### 1. Dialog Cards (Vocabulary Primer)
- Front: Term or concept name
- Back: Definition + one-sentence applied relevance
- 5-8 cards per module
- **Placement**: Prepare to Learn page
- **Estimated time**: 2-3 minutes
- **iframe height**: 550px

### 2. Sequencing (Process Ordering)
- Arrange steps/stages in correct order via drag-and-drop
- 4-8 items per activity
- **Placement**: Guided Practice page
- **Estimated time**: 3-5 minutes
- **iframe height**: 650px

### 3. Fill in the Blanks (Concept Completion)
- Cloze-style completion of key equations, definitions, or process descriptions
- Includes feedback explaining each blank
- **Placement**: Guided Practice page
- **Estimated time**: 3-5 minutes
- **iframe height**: 600px

### 4. Branching Scenario (Applied Reasoning)
- 2-3 decision points with consequence-based branching
- Each branch leads to an explained outcome
- End screens show score and explain the optimal path
- **Placement**: Guided Practice page
- **Estimated time**: 3-5 minutes
- **iframe height**: 700px

### 5. Review Quiz (Mixed-format Review)
- 3-5 questions (multiple choice, true/false)
- Different from the graded Knowledge Check — this is ungraded practice
- **Placement**: Guided Practice or Conclusion page
- **Estimated time**: 3-5 minutes
- **iframe height**: 650px

## Design Principles

### 1. Match Interaction to Learning Objective
Do NOT default to the most complex interaction type. Use the simplest interaction that achieves the objective:

| Learning Goal | Best Interaction | Why |
|---|---|---|
| Term recognition | Dialog Cards | Low motor load, high retrieval |
| Equation/process completion | Fill in the Blanks | Practices recall of components |
| Sequence ordering | Sequencing | Tests understanding of process steps |
| Applied reasoning | Branching Scenario | Decision-making with consequences |
| Concept review | Review Quiz | Mixed formats in one container |
| Spatial identification | Image Hotspots (custom HTML or Lumi) | Click-based (lower load than drag-and-drop) |
| Diagram labeling | Label a Diagram (custom HTML or Lumi) | Only when spatial reasoning IS the objective |

### 2. Cognitive Load Management
Research shows that high motor complexity (e.g., multi-zone drag-and-drop) can **impair** transfer learning by consuming working memory. Design rules:
- **Prefer click-based over drag-based** interactions for concept tasks
- **Limit to 2-4 activities per module** (more creates fatigue)
- **Keep branching scenarios to 2-3 decision nodes**
- **Remove decorative elements** — every element must serve the learning objective

### 3. Feedback Design
Immediate corrective feedback is the primary mechanism by which interactive content improves learning:
- **Correct answer feedback**: Explain WHY it's correct (reinforce the mechanism)
- **Incorrect answer feedback**: Address the specific misconception, not just "Try again"
- **Enable retry** for all formative activities
- **Show solution** after final attempt so students can self-correct

### 4. Mayer's Multimedia Principles Applied
| Principle | Application |
|---|---|
| Multimedia | Always pair diagrams with text for spatial concepts |
| Signaling | Use arrows, color coding, and markers to direct attention |
| Segmenting | Break content into small interactive chunks |
| Coherence | Remove decorative elements; everything serves learning |
| Contiguity | Place explanations adjacent to the element they describe |
| Pretraining | Dialog Cards with key terms BEFORE complex interactions |

### 5. Placement Within Module Structure
Each module has 7 items. Interactive content should be embedded WITHIN existing pages, not as separate module items:

| Module Page | Interactive Content |
|---|---|
| **Overview** | Optional: confidence self-rating |
| **Prepare to Learn** | Dialog Cards (5-8 key terms) |
| **Lesson** | Optional: interactive video or simulation embed |
| **Knowledge Check** | Already a Canvas quiz; no additional activities needed |
| **Guided Practice** | 1-2 activities (sequencing, fill-blanks, or branching) — the core opportunity |
| **Create an Artifact** | No activities — this is a graded student-produced artifact |
| **Conclusion** | Optional: quick review quiz |

**The Guided Practice page is the primary home for interactive content.**

## Activity Specification Format

When designing an interactive activity, produce this specification:

```
## Interactive Activity Specification

### Metadata
- **Activity Name**: [descriptive name]
- **Activity Type**: [Dialog Cards / Sequencing / Fill in Blanks / Branching / Quiz]
- **Module**: M[#] — [title]
- **Placement**: [which page it embeds in]
- **Learning Objective(s)**: [M#.# objectives assessed]
- **Estimated Time**: [1-5 minutes]

### Content

**For Dialog Cards:**
- Card 1 Front: [term] → Back: [definition + applied relevance]
- Card 2 Front: [...] → Back: [...]

**For Sequencing:**
- Items in correct order:
  1. [first step]
  2. [second step]
  3. ...
- Feedback for correct/incorrect completion

**For Fill in the Blanks:**
- Text with *blanks* marked: "The [process] is primarily determined by *[answer]*..."
- Acceptable answers for each blank
- Feedback per blank

**For Branching Scenario:**
- Starting scenario: [description]
- Decision 1: [question] → Option A: [consequence] → Option B: [consequence]
- Decision 2: [question] → ...
- End screens: [summary feedback for each path]

**For Review Quiz:**
- Q1: [question] | Type: [MC/TF] | Correct: [answer] | Distractors: [...] | Feedback: [...]

### Canvas Integration
- Upload to: Canvas Files → /[folder]/M[#]/[filename].html
- Embed in page: [page slug]
- iframe height: [recommended px]
```

## Content Data File Format

The Python generator expects a content data file with this structure:

```python
ALL_ACTIVITIES = {
    "m1": [
        {
            "type": "dialog_cards",
            "title": "Module 1 Key Terms",
            "filename": "m1-dialog-cards.html",
            "page_slug": "m1-prepare-to-learn",
            "page_type": "prepare",
            "instructions": "Review these foundational terms before diving into the lecture.",
            "instruction_text": "Review these foundational terms before diving into the lecture.",  # optional — defaults provided per type
            "download_results": False,  # optional — default False
            "cards": [
                {"front": "Term", "back": "Definition + relevance"},
                ...
            ]
        },
        {
            "type": "sequencing",
            "title": "Process Steps",
            "filename": "m1-sequencing.html",
            "page_slug": "m1-guided-practice",
            "page_type": "guided",
            "instructions": "Put the process steps in order, then check your answer.",
            "items": ["Step 1", "Step 2", "Step 3", ...],
            "feedback_correct": "Correct! ...",
            "feedback_incorrect": "Not quite. ..."
        },
        ...
    ],
    "m2": [...],
}
```

Required generator keys:
- All types: `type`, `title`, `filename`, `instructions`
- `dialog_cards`: `cards`
- `sequencing`: `items`, `feedback_correct`, `feedback_incorrect`
- `fill_blanks`: `passages`
- `branching`: `nodes`, `endpoints`
- `quiz`: `questions`

Optional generator keys:
- `download_results`: default `False`. Set `True` only after the user explicitly answers Y to the ASK FIRST prompt.

Unknown keys are reported as `SCHEMA WARNING:` log lines. `page_slug`, `page_type`, `instruction_text`, and `download_results` are accepted generator keys.

## Download Results (optional, ask first)

When `download_results: True` is set on an activity, the generator adds a maroon `Download my results` button and optional personal-notes textarea that appear only after the activity is complete. The artifact is formative and non-graded by design.

Always ask first before enabling it:

`Include "Download my results" button? (Y/N) — gives students a printable artifact of their session; non-graded by design.`

Client-side behavior:
- Creates a plain-text Blob/data URL in the browser and triggers an `<a download>` click.
- No `localStorage`, no persistence, no Canvas API, and no server call.
- Sandbox-compatible with `allow-scripts allow-forms`; the activity does not need `allow-same-origin`.

Sample summary format:

```text
ASU Self-Assessment Results
Activity: Module 1 Review
Date: 2026-05-17 14:30
-----
3 of 5 questions correct
-----
Personal notes:
I need to review the sequencing step.
```

## Custom Activity Mode

When the 5 built-in types don't fit the learning objective, Claude can generate a custom interactive HTML activity from scratch. This is an open-ended mode — describe what you want, and Claude will build it.

### When to Use Custom Mode
- The learning objective requires an interaction pattern not covered by dialog cards, sequencing, fill-blanks, branching, or quiz
- You want a unique experience (e.g., a drag-to-label diagram, a matching exercise, a timeline builder, a decision matrix)
- You have a specific pedagogical idea that doesn't fit the built-in templates

### How to Invoke
Ask Claude to create a custom interactive activity. Provide:
1. **Module and placement** — which module and page it goes on
2. **Learning objective(s)** — what the student should practice or demonstrate
3. **Interaction description** — what the student does (e.g., "drag labels onto a diagram," "sort items into categories," "build a timeline")
4. **Content** — the actual terms, scenarios, questions, or data to include

### What Claude Generates
A single self-contained HTML file that:
- **Works standalone** — all HTML, CSS, and JavaScript in one file (no external dependencies)
- **Embeds via iframe** — uses the standard Canvas iframe template (see above)
- **Follows ASU branding** — Maroon (#8C1D40) and Gold (#FFC627) color scheme
  - **Ready for manual WCAG review** — keyboard navigable, proper ARIA labels, sufficient contrast, screen-reader compatible
- **Provides feedback** — immediate corrective feedback with explanations
- **Is mobile-friendly** — responsive layout, touch-friendly targets (≥44px)
- **Includes a progress indicator** — shows completion state

### Canvas Integration Requirements
All custom activities must follow these Canvas iframe constraints:
- **Sandbox attribute**: `sandbox="allow-same-origin allow-scripts allow-forms"` — activities cannot access parent page DOM, open popups, or navigate the parent frame
- **No external requests**: All assets (fonts, images, icons) must be inline or data-URI encoded
- **Recommended iframe heights**: 550-700px depending on content density
- **File size**: Keep under 500KB (inline assets add up quickly)
- **Title attribute**: Every iframe needs a descriptive `title` for screen readers

### Example Custom Activities
| Idea | Description | Good For |
|---|---|---|
| Category Sort | Drag items into 2-3 labeled columns | Classification tasks |
| Label a Diagram | Click regions of an SVG to identify structures | Anatomy, systems diagrams |
| Timeline Builder | Arrange events chronologically on a visual timeline | Historical processes, pathways |
| Matching Exercise | Connect items from two columns | Term-definition, cause-effect |
| Decision Matrix | Fill in a matrix comparing options across criteria | Evaluation, comparison |
| Concept Checker | Multi-step guided walkthrough with embedded questions | Complex procedures |

### Quality Standards for Custom Activities
Custom activities follow the same design principles and quality checklist as built-in types — see below.

---

## Interactive Visualizations

For visuals that require **user interaction** — sliders, animations, hover effects, explorable elements, parameter controls. This extends the custom activity mode specifically for interactive scientific and educational visualizations.

> **Static visuals** (diagrams, infographics, charts with no interaction) belong in the `visual-builder` skill, not here. Route there if the user doesn't need interactivity.

### When to Use Interactive Visualizations
- The concept benefits from **exploration** — students click, drag, or hover to discover
- The visual has **dynamic parameters** — a slider changes a value and the diagram updates
- **Animation** illustrates a process that's hard to convey statically (e.g., wave propagation, mitosis phases)
- **Comparison** is user-driven — toggle between states, zoom into regions

### Examples
| Idea | Description | Interaction |
|------|-------------|-------------|
| Shadow floor plan | Top-down view of a building; slider rotates sun position to show shadow patterns | Slider controls time-of-day |
| Explorable cell | Clickable organelles reveal detail panels with structure and function | Click to focus |
| Physics simulation | Ball drop with adjustable gravity, mass, and air resistance | Sliders + play/pause |
| Parameter graph | Mathematical function with adjustable coefficients | Sliders update curve in real-time |
| Anatomical layers | Toggle visibility of skeletal, muscular, circulatory systems | Checkboxes or layer buttons |
| Process animation | Step-through animation of a chemical reaction or biological process | Play/pause + step controls |

### Technical Requirements
- **Self-contained HTML/CSS/JS** — single file, no external dependencies
- **Vanilla JavaScript only** — no React, D3, Angular, or other frameworks
- **All assets inline** — SVGs, icons, data all embedded in the file
- **Canvas iframe deployment** — uploaded to Canvas Files, embedded via `<iframe sandbox="allow-same-origin allow-scripts allow-forms">`
- **File size**: Under 500KB
- **Keyboard navigable** — all controls reachable via Tab/Enter/Arrow keys
- **`prefers-reduced-motion`** — wrap animations in a media query check
- **ARIA live regions** — announce dynamic value changes to screen readers

### Color Guidelines
- **Visual content**: Full color freedom — use whatever colors accurately represent the subject matter
- **UI controls** (buttons, sliders, toggles, labels): ASU palette — Maroon `#8C1D40` primary, Gold `#FFC627` accent, white text on maroon backgrounds
- **All text**: WCAG 4.5:1 contrast ratio minimum

### Quality Standards
Follow `standards/scientific-visuals.md` for SVG construction, accessibility, scientific accuracy, and Canvas embedding guidelines.

### Deployment
Same pipeline as custom HTML activities:
1. Claude generates the self-contained HTML file
2. Upload to Canvas Files (manually or via `deploy_interactives.py`)
3. Embed via iframe in the target Canvas page
4. Recommended iframe height: 600-800px depending on content

---

## No-Scroll Requirement

Activities must fit entirely within their iframe height without scrolling. They should feel like images embedded in the course page — not scrollable sub-windows.

### Rules
- `html, body { overflow: hidden; }` is enforced in all generated HTML
- Iframe embeds include `scrolling="no"` attribute
- Content that exceeds available space must use **pagination, stepping, or truncation** — never scrolling
- Dialog card backs should use concise text (under ~100 words); if too long, reduce font size or abbreviate
- All activities are designed to fit within their allocated iframe height (550-700px)

### Why
Double-scrolling (scrolling the activity within a scrolling course page) creates a choppy, disorienting UX. Activities should integrate seamlessly into the page flow.

---

## WCAG 2.1 AA Manual Review

All interactive activities must meet these accessibility requirements. `scripts/check_interactive_a11y.py` is a preflight subset only; it does not certify full WCAG 2.1 AA conformance.

### Focus Management
- All interactive elements have visible high-contrast focus indicators (gold outline + maroon shadow)
- Skip-to-content links at the top of every activity (`<a href="#main-content" class="skip-link">Skip to activity</a>`)
- Focus is managed programmatically after state changes (e.g., advancing to next question)

### ARIA
- `aria-describedby="instructions"` on primary interactive containers
- `role="alert"` on feedback messages requiring immediate announcement
- `role="status"` on non-urgent status updates (progress bars, counters)
- `aria-live="polite"` on dynamically updated content
- All form inputs have associated labels (`aria-label` or `<label>`)

### Color Independence
- Feedback states use icons (checkmark ✓ / X ✗) in addition to color
- Correct/incorrect slots use border style changes in addition to color
- Progress indicators use fill + text counter, not color alone

### Compliance Checklist
- [ ] All interactive elements reachable via keyboard (Tab/Enter/Space/Arrow)
- [ ] Visible focus indicators on every focusable element
- [ ] Skip-to-content link present
- [ ] `aria-describedby` on main activity container
- [ ] `role="alert"` or `role="status"` on all feedback regions
- [ ] No color-only state indicators
- [ ] 4.5:1 contrast ratio on all text
- [ ] 44px minimum touch targets
- [ ] `prefers-reduced-motion` respected
- [ ] Screen reader tested (VoiceOver or NVDA)

---

## CRC Handoff: Manual Review Surface

The CRC/manual review still owns the checks that the preflight script cannot prove reliably:
- Visible focus indicators across every interactive state
- Computed contrast after browser rendering
- Accessible names on role-elements, especially custom radio/listbox controls
- Dialog focus trap behavior when a custom activity uses dialogs
- `prefers-reduced-motion` behavior for animation-heavy activities
- Screen-reader pass with VoiceOver or NVDA

---

## Layout & Visual Quality Standards

All activities must meet these layout requirements to prevent text overflow, misalignment, and visual messiness.

### Text Containment
- All text containers use `word-wrap: break-word; overflow-wrap: break-word;`
- Minimum 12px padding from container edges
- Long text in fixed-width containers uses `text-overflow: ellipsis` when truncation is acceptable

### Container Sizing
- Use `min-height` instead of `height` where content length varies
- All flex/grid layouts have explicit `gap` values
- Fixed-height containers must account for content at all breakpoints

### Charts & Data Visualizations (Custom Activities)
- Labels must not overlap data elements or each other
- Axes must have adequate margin for label text
- All bars/segments have minimum 2px gap between them
- Legends positioned outside the chart area

### Responsive Behavior
- Test at 320px, 768px, and 1024px viewport widths
- Mobile breakpoint at 600px adjusts padding and font sizes
- Touch targets minimum 44px on mobile

### Quality Checklist (Visual Polish)
- [ ] No text overflows its container at any viewport width
- [ ] All containers have adequate internal padding (≥12px)
- [ ] Flex/grid gaps are explicit (not relying on margins alone)
- [ ] Long words break correctly (no horizontal scroll)
- [ ] Labels in visualizations don't overlap
- [ ] Mobile layout is usable without horizontal scrolling

---

## Instructional Context

Every interactive activity must include brief instructional framing when embedded in a Canvas page. The wrapper (generated by `deploy_interactives.py`) includes:

1. **Activity title** — what it's called
2. **Type label + estimated time** — e.g., "Flashcards | ~3 min | Formative (not graded)"
3. **Instruction text** — 1-2 sentences explaining what the student should do and why

### Default Instructions
If no custom `instruction_text` is provided in the activity data, defaults are used:
- **Dialog Cards**: "Review these key terms by clicking each card to reveal its definition. Use Shuffle to test yourself in a different order."
- **Sequencing**: "Arrange the items in the correct order by clicking an item, then clicking the numbered slot where it belongs."
- **Fill in the Blanks**: "Read each passage and fill in the missing terms. Check your answers when you're ready."
- **Branching**: "Read each scenario carefully and choose the best course of action. Your choices affect the outcome."
- **Quiz**: "Answer each question to test your understanding. You'll receive feedback after each submission."

### Custom Instructions
Use `instructions` for the generated activity's internal instruction paragraph. The deprecated singular `instruction` key is accepted temporarily and logs `SCHEMA WARNING: use instructions (plural)`.

Add `instruction_text` only when the Canvas wrapper text should differ from the generated activity's internal instruction:
```python
"instructions": "Before watching the lecture, test yourself on these foundational terms.",
"instruction_text": "Try this short activity before the lecture."
```

---

## Quality Checklist
Before finalizing any interactive activity:
- [ ] Does this activity assess or reinforce a specific learning objective?
- [ ] Is this the simplest interaction type that achieves the goal?
- [ ] Would removing this activity reduce learning outcomes? (If not, cut it)
- [ ] Is feedback explanatory (not just "correct/incorrect")?
- [ ] Does the activity take ≤5 minutes to complete?
- [ ] Is retry enabled for formative activities?
- [ ] Does the activity avoid excessive motor demands?
- [ ] Is the total interactive content for this module ≤4 activities?
- [ ] Does the activity fit within its iframe height without scrolling?
- [ ] Is all text contained within its containers (no overflow or bleeding)?
- [ ] Has preflight passed, and are full WCAG 2.1 AA manual-review checks complete?
- [ ] Does the embed wrapper include instructional context?

## Output
When invoked, the skill produces:
1. Complete activity specification following the format above
2. Content for the activity (terms, scenarios, questions, etc.)
3. Feedback text for all correct and incorrect responses
4. Canvas page integration instructions (where to embed, iframe code)
5. Alignment to specific module learning objectives
