# GAB-063 · StoryEpisodeUnlock — « Déblocage d'épisode »

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

## Pack (structure officielle par-GAB)
```
GAB-063/
  renderer.html            ← moteur déblocage (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` · `episode_unlock_id` · `title` · `body` · `primary_cta{label,action}`
Optionnels : `kicker`, `icon`

## Ce qui vient du JSON vs HTML
- **JSON** : kicker (texte au-dessus du titre), titre de l'épisode, message de félicitation, libellé du bouton CTA, icône (emoji).
- **HTML** : layout dark card, animation étincelles (particules), shake de l'icône, structure bouton, fallback icon `🔓`, règles responsive.

## Garde-fous (child_safety)
- **BLOCKED** si `title` absent, `body` absent, ou `primary_cta` absent.
- `kicker` optionnel : si absent, le bloc kicker est masqué (`display:none`) — pas de crash.
- `icon` optionnel : si absent, fallback `🔓` affiché automatiquement.
- Aucune métadonnée pédagogique n'est inventée — le moteur n'affiche que ce que l'instance fournit.

## QA à vérifier
1. Modifier `title`/`body`/`primary_cta.label` → rendu change sans toucher au HTML (critère d'or).
2. Supprimer `title` ou `body` ou `primary_cta` → BLOCKED propre listé.
3. `icon` absent → fallback `🔓` affiché, animation préservée.
4. `kicker` absent → bloc kicker invisible, reste du rendu normal.
5. Instance externe injectée via `ENGINE.init(ext)` → rendu mis à jour.
6. Responsive 375/768/1024 — aucun débordement.
7. `prefers-reduced-motion` → animation réduite, fonctionnalité préservée.

## Source
`INDEX-300-storylearning-GAB-060-064-PLAYABLE.html` — section `<!-- GAB-063 -->`, stage `data-tpl="63"`, handler `epunReplay()`.
Contenu extrait : kicker "Épisode débloqué", titre "La prise de la Bastille", body "Tu as compris les causes — l'épisode 2 t'attend !", CTA "Rejouer le déblocage".
