# GAB-058 · StoryCliffhanger — « Cliffhanger pédagogique »

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

## Pack (structure officielle par-GAB)
```
GAB-058/
  renderer.html            ← moteur cliffhanger (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` · `cliffhanger_id` · `body` · `primary_cta{label,label_revealed,action}` · `reveal_text`

Optionnels : `icon` (emoji), `question` (phrase rhétorique).

## Ce qui vient du JSON vs HTML
- **JSON** : texte narratif (`body`), question rhétorique (`question`), émoji (`icon`), libellé du bouton (`primary_cta.label`), libellé post-révélation (`primary_cta.label_revealed`), texte révélé (`reveal_text`).
- **HTML** : carte cliffhanger, animation glow, shake emoji, bouton CTA, zone aria-live, layout, fallback BLOCKED.

## Garde-fous (child_safety)
- **Anti-invention** : aucun contenu pédagogique inventé. Toutes les données viennent de l'instance.
- **BLOCKED** si `body` vide · `reveal_text` vide · `primary_cta` absent/sans label.
- **progressive_reveal** : `reveal_text` n'est affiché qu'après le clic CTA — jamais pré-rendu.
- **Bouton désactivé** après clic pour éviter la double-révélation.

## QA à vérifier
1. Modifier `body` / `reveal_text` → rendu change sans toucher au HTML (critère d'or).
2. `body` absent → BLOCKED propre.
3. Clic CTA → `reveal_text` affiché, bouton disabled, `label_revealed` affiché.
4. `question` absent → zone cachée (hidden), pas d'espace vide.
5. Responsive 375/768/1024 — aucun débordement horizontal.
6. `prefers-reduced-motion` → animations neutralisées.

## use_when / do_not_use_when (extrait de la source)
- ✅ Fin temporaire avec suspense · donner envie de continuer · entre deux épisodes/étapes
- ⛔ Fin définitive d'épisode (→ GAB-059) · transition neutre (→ GAB-027) · suspense artificiel sans lien pédago

## external_refs / dependencies
- **GAB-059** (StoryEpisodeSummary) : cliffhanger débouche souvent sur GAB-059 pour la clôture narrative.
- **GAB-027** : transition neutre sans suspense — alternative quand pas de tension narrative.

## Source
`INDEX-300-storylearning-GAB-055-059-PLAYABLE.html` (stage `data-tpl="58"`, handler `cliffReveal()`).
