# GAB-073 · StoryGlossaryPopup — « Glossaire popup »

**Archétype / renderer_key :** `text_cta` (cartographie) · **module :** EdTechStoryLearning
**Critère validé :** changer le JSON change le texte et les termes sans modifier le HTML. ✅ check.py 12/12.

## Pack (structure officielle par-GAB)
```
GAB-073/
  renderer.html            ← moteur glossaire popup (ne pas modifier par instance)
  instance.example.json    ← SOURCE DE VÉRITÉ (contenu réel, à plat)
  schema.contract.json     ← contrat de validation
  README-contract.md       ← ce fichier
```

## Champs requis (instance, à plat)
`gab_id` · `glossary_id` · `body` · `terms[]{term, definition}`

Optionnels : `title`, `popup_note`, `primary_cta{label, action}`.

## Ce qui vient du JSON vs HTML
- **JSON** : texte narratif (`body`), liste des termes avec leurs définitions (`terms`), note pédagogique (`popup_note`), libellé du bouton (`primary_cta.label`).
- **HTML** : injection des termes annotés dans le texte, rendu popup, interactions clavier/souris, layout, fallback BLOCKED.

## Garde-fous (child_safety)
- **Anti-invention** : aucune définition ni terme n'est codé en dur dans le HTML.
- **BLOCKED** si `terms` vide ou absent, si `body` absent, si `glossary_id` absent.
- **Non-intrusif** : la popup n'est visible qu'à la demande (clic/tap/Enter sur le terme).
- **Fermeture automatique** : clic en dehors ferme toutes les popups ouvertes.
- **Surcharge cognitive** : recommandé 1 à 5 termes (contrainte dans le schema).

## QA à vérifier
1. Modifier `body` ou un item `terms` → rendu change sans toucher au HTML.
2. `terms:[]` → BLOCKED propre.
3. Clic sur un terme souligné → popup affiche le terme (gold) + définition.
4. Clic en dehors → popup se ferme.
5. Navigation clavier (Tab → Enter/Space) → popup accessible.
6. Responsive 375/768/1024 — popup réduite à 180px sur mobile.

## Source
`INDEX-300-storylearning-GAB-070-073-PLAYABLE.html` (stage `data-tpl="73"`, handler `gloToggle`).
