@thanh01.pmt/presentation-kit 0.2.15 → 0.2.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/layout/serializer.ts","../src/core/layout/presets.ts","../src/html-engine/themes.ts","../src/html-engine/presets.ts","../src/html-engine/shell.ts","../src/html-engine/compiler.ts"],"names":["yaml"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,IAAA,EA01BnD,KAAA,CAAM,aAAa,EAAE;AAAA;AAAA,EAAA,EAEvB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAA,EAMV,UAAU;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,kCAAA,EAiKkB,OAAO,UAAU,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,2BAAA,EAyB1C,UAAU,CAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;A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","file":"chunk-SUGKWGJJ.cjs","sourcesContent":["import yaml from 'js-yaml';\nimport type { LayoutBoxConfig, SlideLayoutData } from '../../types.js';\n\n/**\n * Serialize a SlideLayoutData object into a Markdown HTML comment\n */\nexport function serializeLayoutToComment(layout: SlideLayoutData): string {\n if (!layout.boxes || layout.boxes.length === 0) return '';\n\n const cleanData = {\n boxes: layout.boxes.map(box => {\n const b: Record<string, unknown> = {\n id: box.id,\n target: box.target || `h1`,\n pos: [\n Math.round(box.pos[0]),\n Math.round(box.pos[1]),\n Math.round(box.pos[2]),\n Math.round(box.pos[3]),\n ],\n };\n if (box.fontSize) b.fontSize = box.fontSize;\n if (box.color) b.color = box.color;\n if (box.textAlign) b.textAlign = box.textAlign;\n if (box.style) b.style = box.style;\n return b;\n }),\n };\n\n const yamlStr = yaml.dump(cleanData, {\n indent: 2,\n lineWidth: -1,\n noRefs: true,\n }).trim();\n\n return `<!-- layout:\\n ${yamlStr.split('\\n').join('\\n ')}\\n-->`;\n}\n\n/**\n * Split a Markdown presentation into individual slide strings,\n * properly handling frontmatter and code blocks.\n */\nexport function splitMarkdownSlides(markdown: string): {\n frontmatter: string | null;\n slides: string[];\n} {\n const lines = markdown.split('\\n');\n let frontmatter: string | null = null;\n const slideBuffers: string[][] = [];\n let currentBuffer: string[] = [];\n\n let inCodeFence = false;\n let inFrontmatter = false;\n let lineIdx = 0;\n\n // Check for leading frontmatter\n if (lines.length > 0 && lines[0].trim() === '---') {\n inFrontmatter = true;\n const fmBuffer: string[] = [lines[0]];\n lineIdx = 1;\n\n while (lineIdx < lines.length) {\n const line = lines[lineIdx];\n fmBuffer.push(line);\n if (line.trim() === '---') {\n frontmatter = fmBuffer.join('\\n');\n lineIdx++;\n break;\n }\n lineIdx++;\n }\n }\n\n // Iterate remaining lines to collect slides\n for (let i = lineIdx; i < lines.length; i++) {\n const line = lines[i];\n\n if (/^```/.test(line.trim())) {\n inCodeFence = !inCodeFence;\n currentBuffer.push(line);\n continue;\n }\n\n if (!inCodeFence && line.trim() === '---') {\n slideBuffers.push(currentBuffer);\n currentBuffer = [];\n continue;\n }\n\n currentBuffer.push(line);\n }\n\n slideBuffers.push(currentBuffer);\n\n const slides = slideBuffers.map(b => b.join('\\n'));\n return { frontmatter, slides };\n}\n\n/**\n * Update or insert a layout comment inside a specific slide's markdown\n */\nexport function updateSlideLayoutInMarkdown(\n markdown: string,\n slideIndex: number,\n layout: SlideLayoutData | null\n): string {\n const { frontmatter, slides } = splitMarkdownSlides(markdown);\n\n if (slideIndex < 0 || slideIndex >= slides.length) {\n return markdown;\n }\n\n let slideContent = slides[slideIndex];\n\n // Regex to detect existing layout comment\n const layoutCommentRegex = /<!--\\s*layout:\\s*[\\s\\S]*?-->/i;\n\n const newComment = layout && layout.boxes && layout.boxes.length > 0\n ? serializeLayoutToComment(layout)\n : '';\n\n if (layoutCommentRegex.test(slideContent)) {\n if (newComment) {\n slideContent = slideContent.replace(layoutCommentRegex, newComment);\n } else {\n slideContent = slideContent.replace(layoutCommentRegex, '').trim();\n }\n } else if (newComment) {\n // Prepend layout comment to the slide\n const trimmed = slideContent.trimStart();\n slideContent = `${newComment}\\n\\n${trimmed}`;\n }\n\n slides[slideIndex] = slideContent;\n\n // Reassemble deck\n const joinedSlides = slides.join('\\n---\\n');\n if (frontmatter) {\n return `${frontmatter}\\n\\n${joinedSlides}`;\n }\n return joinedSlides;\n}\n\n/**\n * Update text content inside a specific slide's markdown.\n * Replaces oldText with newText within the given slideIndex.\n */\nexport function updateSlideTextInMarkdown(\n markdown: string,\n slideIndex: number,\n oldText: string,\n newText: string\n): string {\n const { frontmatter, slides } = splitMarkdownSlides(markdown);\n\n if (slideIndex < 0 || slideIndex >= slides.length) {\n return markdown;\n }\n\n const cleanOld = oldText.trim();\n const cleanNew = newText.trim();\n if (!cleanOld || cleanOld === cleanNew) return markdown;\n\n let slideContent = slides[slideIndex];\n\n // Try exact match first\n if (slideContent.includes(cleanOld)) {\n slideContent = slideContent.replace(cleanOld, cleanNew);\n } else {\n // Check line-by-line stripping markdown decorators (#, -, *, >, `)\n const lines = slideContent.split('\\n');\n let replaced = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const stripped = line.replace(/^[#\\s\\-\\*\\>]+/, '').replace(/[*_`]/g, '').trim();\n if (stripped === cleanOld) {\n const prefixMatch = line.match(/^([#\\s\\-\\*\\>]+)/);\n const prefix = prefixMatch ? prefixMatch[1] : '';\n lines[i] = `${prefix}${cleanNew}`;\n replaced = true;\n break;\n }\n }\n\n if (replaced) {\n slideContent = lines.join('\\n');\n } else {\n // Escape regex characters and try matching regex\n const escaped = cleanOld.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = new RegExp(escaped, 'i');\n if (regex.test(slideContent)) {\n slideContent = slideContent.replace(regex, cleanNew);\n } else {\n // Fuzzy word match\n const words = cleanOld.split(/\\s+/).filter(w => w.length > 2);\n if (words.length > 0) {\n const pattern = words.map(w => w.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('[\\\\s\\\\S]*?');\n const fuzzyRegex = new RegExp(pattern, 'i');\n if (fuzzyRegex.test(slideContent)) {\n slideContent = slideContent.replace(fuzzyRegex, cleanNew);\n }\n }\n }\n }\n }\n\n slides[slideIndex] = slideContent;\n\n const joinedSlides = slides.join('\\n---\\n');\n if (frontmatter) {\n return `${frontmatter}\\n\\n${joinedSlides}`;\n }\n return joinedSlides;\n}\n\n/**\n * Remove an element (line) and its layout box from a specific slide's markdown.\n */\nexport function removeSlideElementFromMarkdown(\n markdown: string,\n slideIndex: number,\n options: {\n content?: string;\n boxId?: string;\n target?: string;\n }\n): string {\n const { frontmatter, slides } = splitMarkdownSlides(markdown);\n\n if (slideIndex < 0 || slideIndex >= slides.length) {\n return markdown;\n }\n\n let slideContent = slides[slideIndex];\n const cleanContent = options.content?.trim();\n\n // 1. Remove text line from slide content if content provided\n if (cleanContent) {\n const lines = slideContent.split('\\n');\n let removed = false;\n\n // Filter out the line matching the content\n const updatedLines = lines.filter(line => {\n if (removed) return true;\n const stripped = line.replace(/^[#\\s\\-\\*\\>]+/, '').replace(/[*_`]/g, '').trim();\n if (stripped === cleanContent || line.includes(cleanContent)) {\n removed = true;\n return false;\n }\n return true;\n });\n\n if (removed) {\n slideContent = updatedLines.join('\\n');\n }\n }\n\n // 2. Remove box from layout YAML if layout exists\n const layoutCommentRegex = /<!--\\s*layout:\\s*([\\s\\S]*?)-->/i;\n const match = slideContent.match(layoutCommentRegex);\n if (match && match[1]) {\n try {\n const parsed = yaml.load(match[1]) as { boxes?: LayoutBoxConfig[] } | null;\n if (parsed && Array.isArray(parsed.boxes)) {\n const remainingBoxes = parsed.boxes.filter(b => {\n if (options.boxId && b.id === options.boxId) return false;\n if (options.target && b.target === options.target) return false;\n return true;\n });\n\n if (remainingBoxes.length > 0) {\n const yamlStr = yaml.dump({ boxes: remainingBoxes }, { indent: 2, lineWidth: -1, noRefs: true }).trim();\n slideContent = slideContent.replace(layoutCommentRegex, `<!-- layout:\\n ${yamlStr.split('\\n').join('\\n ')}\\n-->`);\n } else {\n slideContent = slideContent.replace(layoutCommentRegex, '').trim();\n }\n }\n } catch {\n // Ignore YAML parse error\n }\n }\n\n slides[slideIndex] = slideContent;\n const joinedSlides = slides.join('\\n---\\n');\n if (frontmatter) {\n return `${frontmatter}\\n\\n${joinedSlides}`;\n }\n return joinedSlides;\n}\n\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — Slide Layout Presets\n// Catalog of battle-tested single-slide layout templates with 1280x720 canvas coordinates\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport type { SlideLayoutData } from '../../types.js';\n\nexport type SlideLayoutCategory =\n | 'cover'\n | 'content'\n | 'split'\n | 'code'\n | 'metrics'\n | 'diagram'\n | 'quote'\n | 'assessment';\n\nexport interface SlideLayoutPreset {\n id: string;\n name: string;\n category: SlideLayoutCategory;\n description: string;\n layout: SlideLayoutData;\n markdownSnippet: string;\n}\n\nexport const SLIDE_LAYOUT_PRESETS: SlideLayoutPreset[] = [\n {\n id: 'title-hero',\n name: 'Title & Speaker Cover',\n category: 'cover',\n description: 'High-impact opening slide with large title, subtitle, and speaker credentials.',\n layout: {\n boxes: [\n {\n id: 'title',\n target: 'h1',\n pos: [100, 180, 1080, 140],\n fontSize: '3rem',\n textAlign: 'center',\n },\n {\n id: 'subtitle',\n target: 'h3',\n pos: [100, 350, 1080, 70],\n fontSize: '1.5rem',\n textAlign: 'center',\n },\n {\n id: 'speaker-meta',\n target: 'p',\n pos: [100, 460, 1080, 80],\n fontSize: '1.1rem',\n textAlign: 'center',\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: title\n target: h1\n pos: [100, 180, 1080, 140]\n fontSize: 3rem\n textAlign: center\n - id: subtitle\n target: h3\n pos: [100, 350, 1080, 70]\n fontSize: 1.5rem\n textAlign: center\n - id: speaker-meta\n target: p\n pos: [100, 460, 1080, 80]\n fontSize: 1.1rem\n textAlign: center\n-->\n\n# 🚀 Engineering Scalable Cloud Systems\n### Principles, Bottlenecks, and Real-World Architecture Patterns\n\n**Presenter:** Senior Systems Architect | **Duration:** 45 mins | **Level:** Intermediate\n\n<!--\nPresenter Notes:\n- Welcome the audience and outline today's primary engineering goals.\n- Spark curiosity with an opening hook about scaling under high concurrency.\n-->`,\n },\n\n {\n id: 'two-column-split',\n name: 'Two-Column Comparison',\n category: 'split',\n description: 'Balanced side-by-side comparison for legacy vs modern patterns or pros vs cons.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 50, 1120, 70],\n fontSize: '2rem',\n },\n {\n id: 'col-left',\n target: '.columns-2 > div:first-child',\n pos: [80, 150, 530, 510],\n },\n {\n id: 'col-right',\n target: '.columns-2 > div:last-child',\n pos: [670, 150, 530, 510],\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 50, 1120, 70]\n fontSize: 2rem\n - id: col-left\n target: '.columns-2 > div:first-child'\n pos: [80, 150, 530, 510]\n - id: col-right\n target: '.columns-2 > div:last-child'\n pos: [670, 150, 530, 510]\n-->\n\n## ⚖️ Monolithic Polling vs Event-Driven Architecture\n\n<div class=\"columns-2\">\n<div>\n\n### 🔴 Legacy Polling\n- Heavy database CPU overhead on idle cycles\n- High network latency between updates\n- Prone to cascading timeouts during spikes\n\n</div>\n<div>\n\n### 🟢 Event-Driven Streams\n- Real-time event propagation via webhooks\n- Zero idle compute waste with serverless consumers\n- Automatic backpressure and queue isolation\n\n</div>\n</div>\n\n<!--\nPresenter Notes:\n- Emphasize the core failure mode of periodic polling under sudden load spikes.\n- Ask the room if anyone has experienced database lockups caused by polling loops.\n-->`,\n },\n\n {\n id: 'code-explainer',\n name: 'Code Walkthrough & Analysis',\n category: 'code',\n description: 'Syntax-highlighted code block on the left with step-by-step key annotations on the right.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 45, 1120, 65],\n fontSize: '1.9rem',\n },\n {\n id: 'code-box',\n target: '.columns-2 > div:first-child',\n pos: [80, 135, 630, 535],\n },\n {\n id: 'notes-box',\n target: '.columns-2 > div:last-child',\n pos: [740, 135, 460, 535],\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 45, 1120, 65]\n fontSize: 1.9rem\n - id: code-box\n target: '.columns-2 > div:first-child'\n pos: [80, 135, 630, 535]\n - id: notes-box\n target: '.columns-2 > div:last-child'\n pos: [740, 135, 460, 535]\n-->\n\n## 💻 Robust Async Transaction Pipeline\n\n<div class=\"columns-2\">\n<div>\n\n\\`\\`\\`ts\n// Process payment with idempotency guarantee\nexport async function processPayment(order: Order) {\n const isValid = await validateOrder(order);\n if (!isValid) throw new Error(\"ValidationFailed\");\n\n const receipt = await chargeCard(order);\n return sendConfirmation(receipt);\n}\n\\`\\`\\`\n\n</div>\n<div>\n\n### 🔍 Key Engineering Invariants:\n1. **Early Guard Clause:** Validates payload immediately at line 3 before triggering external calls.\n2. **Deterministic Sequence:** Enforces strict order of operations using native \\`await\\`.\n3. **Audit Trail:** Returns immutable payment receipt upon successful execution.\n\n</div>\n</div>\n\n<!--\nPresenter Notes:\n- Walk through lines 1 to 7 sequentially.\n- Cold-call check: \"What happens if line 6 throws a network timeout?\"\n- Cognitive scaffolding: Highlight the importance of idempotency keys in payment APIs.\n-->`,\n },\n\n {\n id: 'metrics-3-card',\n name: '3-Metric Key Results Grid',\n category: 'metrics',\n description: 'Three high-visibility KPI stat cards for benchmarks, impact, and success criteria.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 50, 1120, 70],\n fontSize: '2rem',\n textAlign: 'center',\n },\n {\n id: 'metric-1',\n target: '.columns-3 > div:nth-child(1)',\n pos: [80, 165, 340, 485],\n },\n {\n id: 'metric-2',\n target: '.columns-3 > div:nth-child(2)',\n pos: [470, 165, 340, 485],\n },\n {\n id: 'metric-3',\n target: '.columns-3 > div:nth-child(3)',\n pos: [860, 165, 340, 485],\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 50, 1120, 70]\n fontSize: 2rem\n textAlign: center\n - id: metric-1\n target: '.columns-3 > div:nth-child(1)'\n pos: [80, 165, 340, 485]\n - id: metric-2\n target: '.columns-3 > div:nth-child(2)'\n pos: [470, 165, 340, 485]\n - id: metric-3\n target: '.columns-3 > div:nth-child(3)'\n pos: [860, 165, 340, 485]\n-->\n\n## 📊 Performance & Reliability Benchmarks\n\n<div class=\"columns-3\">\n<div>\n\n# ⚡ 99.99%\n### SLA Availability\nHigh-availability multi-region cluster with automated failover routing.\n\n</div>\n<div>\n\n# 🚀 15ms\n### P99 Latency\nSub-20ms roundtrip response time via distributed edge caching.\n\n</div>\n<div>\n\n# 🛡️ Zero\n### Unhandled Breaches\nFull SOC2 Type II compliance and end-to-end payload encryption.\n\n</div>\n</div>\n\n<!--\nPresenter Notes:\n- Highlight the 15ms P99 latency target as the primary technical milestone.\n- Connect these metrics directly to the architecture decisions discussed next.\n-->`,\n },\n\n {\n id: 'process-flow',\n name: 'Architecture & Process Flow',\n category: 'diagram',\n description: 'Multi-stage workflow with responsive Mermaid diagram and phase summaries.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 45, 1120, 65],\n fontSize: '1.9rem',\n },\n {\n id: 'diagram-box',\n target: 'pre.mermaid, .mermaid',\n pos: [80, 130, 1120, 310],\n },\n {\n id: 'summary-box',\n target: 'ul, p',\n pos: [80, 465, 1120, 205],\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 45, 1120, 65]\n fontSize: 1.9rem\n - id: diagram-box\n target: 'pre.mermaid, .mermaid'\n pos: [80, 130, 1120, 310]\n - id: summary-box\n target: 'ul, p'\n pos: [80, 465, 1120, 205]\n-->\n\n## 🔄 End-to-End Data Ingestion Pipeline\n\n\\`\\`\\`mermaid\ngraph LR\n A[1. Client Ingress] --> B[2. API Gateway]\n B --> C[3. Auth Verifier]\n C --> D[4. Distributed DB]\n style A fill:#0284c7,stroke:#38bdf8,stroke-width:2px,color:#fff\n style B fill:#1e293b,stroke:#64748b,stroke-width:2px,color:#fff\n style C fill:#059669,stroke:#34d399,stroke-width:2px,color:#fff\n style D fill:#7c3aed,stroke:#a78bfa,stroke-width:2px,color:#fff\n\\`\\`\\`\n\n- **Ingress & Gateway:** Rate-limits traffic and applies reverse-proxy load balancing.\n- **Verification & Storage:** Decodes cryptographic JWT tokens before transactional write commit.\n\n<!--\nPresenter Notes:\n- Trace each hop across the diagram from left to right.\n- Ask: \"Where should rate limiting be applied to prevent DDoS attacks?\"\n-->`,\n },\n\n {\n id: 'quote-highlight',\n name: 'Core Principle & Quote Highlight',\n category: 'quote',\n description: 'Prominent quote callout for fundamental engineering rules or memorable mantras.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [100, 100, 1080, 80],\n fontSize: '2.2rem',\n textAlign: 'center',\n },\n {\n id: 'quote-box',\n target: 'blockquote',\n pos: [140, 230, 1000, 360],\n fontSize: '1.4rem',\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [100, 100, 1080, 80]\n fontSize: 2.2rem\n textAlign: center\n - id: quote-box\n target: blockquote\n pos: [140, 230, 1000, 360]\n fontSize: 1.4rem\n-->\n\n## 💡 Foundational Architecture Principle\n\n> \"Simplicity is prerequisite for reliability. A well-engineered distributed system is one where a new engineer can understand the request flow within their first hour.\"\n> \n> — **Edsger W. Dijkstra**\n\n<!--\nPresenter Notes:\n- Pause for 5 seconds of silence to let the quote sink in.\n- Ask: \"How do our current architectural choices reflect this principle?\"\n-->`,\n },\n\n {\n id: 'quiz-checkpoint',\n name: 'Interactive Formative Checkpoint',\n category: 'assessment',\n description: 'Interactive multiple-choice diagnostic checkpoint with A/B/C/D voting options.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 45, 1120, 65],\n fontSize: '1.9rem',\n },\n {\n id: 'question-callout',\n target: 'blockquote',\n pos: [80, 130, 1120, 110],\n fontSize: '1.2rem',\n },\n {\n id: 'options-list',\n target: 'ul',\n pos: [80, 260, 1120, 390],\n fontSize: '1.15rem',\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 45, 1120, 65]\n fontSize: 1.9rem\n - id: question-callout\n target: blockquote\n pos: [80, 130, 1120, 110]\n fontSize: 1.2rem\n - id: options-list\n target: ul\n pos: [80, 260, 1120, 390]\n fontSize: 1.15rem\n-->\n\n## 🎯 Formative Checkpoint: Verify Your Understanding\n\n> **Question:** In an event-driven architecture, which pattern guarantees that messages are never permanently lost if a downstream consumer crashes?\n\n- **A.** Direct HTTP POST call with a short 2-second timeout\n- **B.** Persistent Message Broker with Dead-Letter Queue (DLQ) & retry policy\n- **C.** In-memory client RAM cache without disk persistence\n- **D.** Discarding failed packets and prompting the user to re-submit\n\n<!--\nPresenter Notes:\n- Give students 30 seconds to vote on option A, B, C, or D.\n- Correct answer: B.\n- Explain why options A and C introduce catastrophic data loss in production.\n-->`,\n },\n\n {\n id: 'tiered-practice-3cards',\n name: 'Tiered Differentiation (Bronze / Silver / Gold)',\n category: 'content',\n description: 'Three progressive competency tiers allowing self-paced learning acceleration.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 45, 1120, 65],\n fontSize: '1.9rem',\n },\n {\n id: 'tier-bronze',\n target: '.columns-3 > div:nth-child(1)',\n pos: [80, 140, 350, 520],\n },\n {\n id: 'tier-silver',\n target: '.columns-3 > div:nth-child(2)',\n pos: [465, 140, 350, 520],\n },\n {\n id: 'tier-gold',\n target: '.columns-3 > div:nth-child(3)',\n pos: [850, 140, 350, 520],\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 45, 1120, 65]\n fontSize: 1.9rem\n - id: tier-bronze\n target: '.columns-3 > div:nth-child(1)'\n pos: [80, 140, 350, 520]\n - id: tier-silver\n target: '.columns-3 > div:nth-child(2)'\n pos: [465, 140, 350, 520]\n - id: tier-gold\n target: '.columns-3 > div:nth-child(3)'\n pos: [850, 140, 350, 520]\n-->\n\n## 🛠️ Hands-On Challenge: 3-Tier Differentiation\n\n<div class=\"columns-3\">\n<div>\n\n### 🥉 Bronze Tier\n- Implement basic handler logic\n- Pass 3 baseline unit tests\n- *Goal: Foundational mastery*\n\n</div>\n<div>\n\n### 🥈 Silver Tier\n- Add boundary error handling\n- Enforce O(N) memory complexity\n- *Goal: Production-ready code*\n\n</div>\n<div>\n\n### 🥇 Gold Tier\n- Design distributed retry queue\n- Add 95% automated test coverage\n- *Goal: Architectural leadership*\n\n</div>\n</div>\n\n<!--\nPresenter Notes:\n- All learners begin at Bronze to establish baseline competency.\n- Accelerate self-directed learners to Silver and Gold as they complete each tier.\n-->`,\n },\n\n {\n id: 'agenda-timeline',\n name: 'Session Agenda & Milestones',\n category: 'content',\n description: 'Structured time-budgeted agenda mapping stages to measurable deliverables.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 45, 1120, 65],\n fontSize: '1.9rem',\n },\n {\n id: 'table-box',\n target: 'table',\n pos: [80, 140, 1120, 520],\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 45, 1120, 65]\n fontSize: 1.9rem\n - id: table-box\n target: table\n pos: [80, 140, 1120, 520]\n-->\n\n## 🗺️ Milestone Roadmap & Time Budget\n\n| Allocated Time | Session Stage | Core Learning Focus | Deliverable Milestone |\n|:---:|---|---|---|\n| **05 mins** | Warm-Up | Real-World Scenario & Context | Identify system bottleneck |\n| **15 mins** | Concept Discovery | Core Architectural Patterns | Deconstruct message queue models |\n| **20 mins** | Hands-On Lab | Tiered Code Implementation | Complete Bronze + Silver tasks |\n| **05 mins** | Wrap-Up | Formative Checkpoint & Debrief | Consolidate key principles |\n\n<!--\nPresenter Notes:\n- Walk through the time budget so students understand expectations and pacing.\n-->`,\n },\n\n {\n id: 'takeaways-summary',\n name: 'Key Takeaways & Wrap-up',\n category: 'content',\n description: 'Three memorable synthesis takeaways with actionable next steps.',\n layout: {\n boxes: [\n {\n id: 'heading',\n target: 'h2',\n pos: [80, 50, 1120, 70],\n fontSize: '2rem',\n },\n {\n id: 'list-box',\n target: 'ol',\n pos: [80, 150, 1120, 340],\n fontSize: '1.25rem',\n },\n {\n id: 'callout-next',\n target: 'blockquote',\n pos: [80, 520, 1120, 140],\n fontSize: '1.1rem',\n },\n ],\n },\n markdownSnippet: `<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 50, 1120, 70]\n fontSize: 2rem\n - id: list-box\n target: ol\n pos: [80, 150, 1120, 340]\n fontSize: 1.25rem\n - id: callout-next\n target: blockquote\n pos: [80, 520, 1120, 140]\n fontSize: 1.1rem\n-->\n\n## 🏁 Key Takeaways & Action Items\n\n1. **Decouple Before Scaling:** Separate producer rate from consumer processing capacity.\n2. **Design for Failure:** Always configure retries, backoff intervals, and dead-letter queues.\n3. **Measure End-to-End:** Track P99 latency and error rates across all distributed boundaries.\n\n> 📝 **Next Action Item:** Complete the Silver Tier refactoring challenge before our next peer-review session.\n\n<!--\nPresenter Notes:\n- Deliver a crisp 2-minute wrap-up reinforcing the 3 core takeaways.\n- Acknowledge strong peer collaboration during the hands-on lab.\n-->`,\n },\n];\n\n/**\n * Find a preset by its unique ID\n */\nexport function getSlideLayoutPresetById(id: string): SlideLayoutPreset | undefined {\n return SLIDE_LAYOUT_PRESETS.find(p => p.id === id);\n}\n\n/**\n * Filter presets by category\n */\nexport function getSlideLayoutPresetsByCategory(category: SlideLayoutCategory): SlideLayoutPreset[] {\n return SLIDE_LAYOUT_PRESETS.filter(p => p.category === category);\n}\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — Curated HTML Themes\n// Inspired by beautiful-html-templates (\"Anti-AI-slop\" aesthetic standards)\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport type { HtmlDeckTheme, HtmlThemeName } from './types.js';\n\nexport const HTML_THEMES: Record<HtmlThemeName, HtmlDeckTheme> = {\n 'blue-professional': {\n id: 'blue-professional',\n name: 'Blue Professional',\n scheme: 'light',\n palette: {\n bg: '#FDFAE7',\n bgSecondary: '#F4EFCF',\n primary: '#1E2BFA',\n accent: '#0D18B9',\n text: '#111111',\n textMuted: '#6B6B6B',\n border: '#E2DCB9',\n },\n typography: {\n display: \"'Space Grotesk', system-ui, -apple-system, sans-serif\",\n body: \"'Inter', system-ui, -apple-system, sans-serif\",\n code: \"'JetBrains Mono', 'Fira Code', monospace\",\n },\n },\n\n 'editorial-forest': {\n id: 'editorial-forest',\n name: 'Editorial Forest',\n scheme: 'dark',\n palette: {\n bg: '#0F1F17',\n bgSecondary: '#183024',\n primary: '#D9A74A',\n accent: '#8EA696',\n text: '#F4F1EA',\n textMuted: '#A0B4A8',\n border: 'rgba(244, 241, 234, 0.12)',\n },\n typography: {\n display: \"'Playfair Display', Georgia, serif\",\n body: \"'Inter', system-ui, -apple-system, sans-serif\",\n code: \"'JetBrains Mono', monospace\",\n },\n },\n\n 'cobalt-grid': {\n id: 'cobalt-grid',\n name: 'Cobalt Grid (Tech Modern)',\n scheme: 'dark',\n palette: {\n bg: '#090D1E',\n bgSecondary: '#111836',\n primary: '#00E5FF',\n accent: '#3B82F6',\n text: '#F8FAFC',\n textMuted: '#94A3B8',\n border: 'rgba(255, 255, 255, 0.1)',\n },\n typography: {\n display: \"'Plus Jakarta Sans', system-ui, sans-serif\",\n body: \"'Inter', system-ui, sans-serif\",\n code: \"'Fira Code', 'JetBrains Mono', monospace\",\n },\n customCss: `\n .slide-canvas {\n background-image: radial-gradient(rgba(0, 229, 255, 0.05) 1px, transparent 0);\n background-size: 32px 32px;\n }\n `,\n },\n\n studio: {\n id: 'studio',\n name: 'Studio Minimalist',\n scheme: 'light',\n palette: {\n bg: '#F8F9FA',\n bgSecondary: '#EDEFF2',\n primary: '#0F172A',\n accent: '#2563EB',\n text: '#0F172A',\n textMuted: '#64748B',\n border: '#E2E8F0',\n },\n typography: {\n display: \"'Inter', system-ui, -apple-system, sans-serif\",\n body: \"'Inter', system-ui, -apple-system, sans-serif\",\n code: \"'JetBrains Mono', monospace\",\n },\n },\n\n monochrome: {\n id: 'monochrome',\n name: 'Monochrome Dark',\n scheme: 'dark',\n palette: {\n bg: '#09090B',\n bgSecondary: '#141417',\n primary: '#FAFAFA',\n accent: '#38BDF8',\n text: '#FAFAFA',\n textMuted: '#A1A1AA',\n border: 'rgba(255, 255, 255, 0.12)',\n },\n typography: {\n display: \"'Inter', system-ui, sans-serif\",\n body: \"'Inter', system-ui, sans-serif\",\n code: \"'JetBrains Mono', monospace\",\n },\n },\n};\n\nexport function resolveHtmlTheme(themeName?: HtmlThemeName): HtmlDeckTheme {\n if (themeName && HTML_THEMES[themeName]) {\n return HTML_THEMES[themeName];\n }\n return HTML_THEMES['blue-professional'];\n}\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — 8 Standard Pedagogical Slide Layout Presets\n// Calibrated for 1920x1080 Stage Canvas (Frontend Slides & Beautiful HTML specs)\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport type { HtmlDeckTheme, HtmlSlidePreset, HtmlLayoutPresetId } from './types.js';\n\nfunction escapeHtml(str: any): string {\n if (str === undefined || str === null) return '';\n return String(str)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\nexport const HTML_SLIDE_PRESETS: Record<HtmlLayoutPresetId, HtmlSlidePreset> = {\n 'hero-cover': {\n id: 'hero-cover',\n name: 'Hero Cover',\n category: 'cover',\n description: 'Title slide with topic badge, large display heading, subtitle, and author/date info',\n slots: [\n { name: 'tag', label: 'Badge / Tag', type: 'badge', description: 'e.g. Unit 1 · Lesson 3' },\n { name: 'title', label: 'Main Title', type: 'text', description: 'Main title of the lesson or deck', required: true },\n { name: 'subtitle', label: 'Subtitle', type: 'multiline', description: 'Brief description or learning goal' },\n { name: 'author', label: 'Instructor / Author', type: 'text', description: 'Instructor name or school' },\n { name: 'date', label: 'Date / Period', type: 'text', description: 'Date or semester' },\n ],\n template: (slots, theme) => `\n <div class=\"h-full w-full flex flex-col justify-between p-20 relative overflow-hidden\">\n <div class=\"space-y-6 max-w-4xl z-10 my-auto\">\n ${slots.tag ? `<div class=\"inline-flex items-center px-4 py-1.5 rounded-full text-sm font-bold tracking-widest uppercase border border-current opacity-90\" style=\"color: var(--primary);\">${escapeHtml(slots.tag)}</div>` : ''}\n <h1 class=\"text-6xl font-extrabold leading-tight tracking-tight\" style=\"font-family: var(--font-display); color: var(--text);\">\n ${escapeHtml(slots.title || 'Slide Title')}\n </h1>\n ${slots.subtitle ? `<p class=\"text-2xl leading-relaxed opacity-85 max-w-3xl\" style=\"color: var(--text-muted);\">${escapeHtml(slots.subtitle)}</p>` : ''}\n </div>\n <div class=\"flex items-center justify-between border-t pt-6 text-base opacity-75 z-10\" style=\"border-color: var(--border); color: var(--text-muted);\">\n <span class=\"font-medium\">${escapeHtml(slots.author || '')}</span>\n <span class=\"font-mono\">${escapeHtml(slots.date || '')}</span>\n </div>\n </div>\n `,\n },\n\n 'split-concept-code': {\n id: 'split-concept-code',\n name: 'Split Concept & Code',\n category: 'split',\n description: 'Left column for theoretical concept & bullet points, right column for code walkthrough',\n slots: [\n { name: 'tag', label: 'Section Tag', type: 'badge', description: 'e.g. Syntax & Example' },\n { name: 'title', label: 'Slide Title', type: 'text', description: 'Heading for this topic', required: true },\n { name: 'points', label: 'Key Points', type: 'list', description: 'Array of key takeaways or bullet points' },\n { name: 'code', label: 'Code Snippet', type: 'code', description: 'Source code', required: true },\n { name: 'language', label: 'Programming Language', type: 'text', description: 'e.g. python, typescript, swift' },\n { name: 'codeNote', label: 'Code Footnote / Explanation', type: 'text', description: 'Small tip under the code box' },\n ],\n template: (slots, theme) => {\n const points = Array.isArray(slots.points) ? slots.points : [];\n return `\n <div class=\"h-full w-full flex flex-col p-16 gap-6 justify-between\">\n <div>\n ${slots.tag ? `<span class=\"text-xs uppercase tracking-widest font-bold opacity-80\" style=\"color: var(--primary);\">${escapeHtml(slots.tag)}</span>` : ''}\n <h2 class=\"text-4xl font-bold mt-1.5\" style=\"font-family: var(--font-display); color: var(--text);\">${escapeHtml(slots.title || '')}</h2>\n </div>\n <div class=\"flex-1 grid grid-cols-12 gap-8 items-center min-h-0\">\n <div class=\"col-span-5 flex flex-col justify-center space-y-4\">\n <ul class=\"space-y-4\">\n ${points.map((pt: string) => `\n <li class=\"flex items-start gap-3 text-lg leading-relaxed\" style=\"color: var(--text);\">\n <span class=\"inline-block mt-2 w-2 h-2 rounded-full flex-shrink-0\" style=\"background-color: var(--primary);\"></span>\n <span>${escapeHtml(pt)}</span>\n </li>\n `).join('')}\n </ul>\n </div>\n <div class=\"col-span-7 flex flex-col rounded-xl overflow-hidden border shadow-lg\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\">\n <div class=\"flex items-center justify-between px-5 py-2.5 border-b text-xs font-mono opacity-80\" style=\"border-color: var(--border); color: var(--text-muted);\">\n <div class=\"flex items-center gap-1.5\">\n <span class=\"w-3 h-3 rounded-full bg-red-500/70 inline-block\"></span>\n <span class=\"w-3 h-3 rounded-full bg-yellow-500/70 inline-block\"></span>\n <span class=\"w-3 h-3 rounded-full bg-green-500/70 inline-block\"></span>\n </div>\n <span class=\"uppercase tracking-wider font-semibold\">${escapeHtml(slots.language || 'code')}</span>\n </div>\n <pre class=\"flex-1 p-6 text-sm font-mono overflow-hidden leading-relaxed\" style=\"color: var(--text);\"><code>${escapeHtml(slots.code || '')}</code></pre>\n ${slots.codeNote ? `<div class=\"px-5 py-2.5 border-t text-xs font-mono opacity-80\" style=\"border-color: var(--border); color: var(--text-muted);\">${escapeHtml(slots.codeNote)}</div>` : ''}\n </div>\n </div>\n </div>\n `;\n },\n },\n\n 'two-columns-compare': {\n id: 'two-columns-compare',\n name: 'Two Columns Compare',\n category: 'split',\n description: 'Side-by-side comparison for Pros/Cons, Approaches, or Before/After',\n slots: [\n { name: 'tag', label: 'Section Tag', type: 'badge', description: 'e.g. Comparison' },\n { name: 'title', label: 'Slide Title', type: 'text', description: 'Comparison headline', required: true },\n { name: 'col1Title', label: 'Left Column Title', type: 'text', description: 'e.g. Approach A / Pros' },\n { name: 'col1Items', label: 'Left Column Items', type: 'list', description: 'Array of points' },\n { name: 'col2Title', label: 'Right Column Title', type: 'text', description: 'e.g. Approach B / Cons' },\n { name: 'col2Items', label: 'Right Column Items', type: 'list', description: 'Array of points' },\n ],\n template: (slots, theme) => {\n const col1 = Array.isArray(slots.col1Items) ? slots.col1Items : [];\n const col2 = Array.isArray(slots.col2Items) ? slots.col2Items : [];\n return `\n <div class=\"h-full w-full flex flex-col p-16 gap-6 justify-between\">\n <div>\n ${slots.tag ? `<span class=\"text-xs uppercase tracking-widest font-bold opacity-80\" style=\"color: var(--primary);\">${escapeHtml(slots.tag)}</span>` : ''}\n <h2 class=\"text-4xl font-bold mt-1.5\" style=\"font-family: var(--font-display); color: var(--text);\">${escapeHtml(slots.title || '')}</h2>\n </div>\n <div class=\"flex-1 grid grid-cols-2 gap-8 items-stretch min-h-0 my-auto\">\n <div class=\"p-8 rounded-xl border flex flex-col space-y-4 shadow-sm justify-center\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\">\n <h3 class=\"text-2xl font-bold\" style=\"color: var(--primary);\">${escapeHtml(slots.col1Title || 'Column 1')}</h3>\n <ul class=\"space-y-3\">\n ${col1.map((item: string) => `\n <li class=\"flex items-start gap-3 text-lg leading-relaxed\" style=\"color: var(--text);\">\n <span class=\"opacity-60 mt-0.5 font-bold\">•</span>\n <span>${escapeHtml(item)}</span>\n </li>\n `).join('')}\n </ul>\n </div>\n <div class=\"p-8 rounded-xl border flex flex-col space-y-4 shadow-sm justify-center\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\">\n <h3 class=\"text-2xl font-bold\" style=\"color: var(--text);\">${escapeHtml(slots.col2Title || 'Column 2')}</h3>\n <ul class=\"space-y-3\">\n ${col2.map((item: string) => `\n <li class=\"flex items-start gap-3 text-lg leading-relaxed\" style=\"color: var(--text);\">\n <span class=\"opacity-60 mt-0.5 font-bold\">•</span>\n <span>${escapeHtml(item)}</span>\n </li>\n `).join('')}\n </ul>\n </div>\n </div>\n </div>\n `;\n },\n },\n\n 'three-cards-grid': {\n id: 'three-cards-grid',\n name: 'Three Cards Grid',\n category: 'grid',\n description: '3 cards showcasing 3 key pillars, concepts, or architectural layers',\n slots: [\n { name: 'tag', label: 'Section Tag', type: 'badge', description: 'e.g. Core Pillars' },\n { name: 'title', label: 'Slide Title', type: 'text', description: 'Overview title', required: true },\n { name: 'cards', label: 'Cards List', type: 'options', description: 'Array of 3 cards: {badge, title, desc}' },\n ],\n template: (slots, theme) => {\n const cards = Array.isArray(slots.cards) ? slots.cards : [];\n return `\n <div class=\"h-full w-full flex flex-col p-16 gap-6 justify-between\">\n <div>\n ${slots.tag ? `<span class=\"text-xs uppercase tracking-widest font-bold opacity-80\" style=\"color: var(--primary);\">${escapeHtml(slots.tag)}</span>` : ''}\n <h2 class=\"text-4xl font-bold mt-1.5\" style=\"font-family: var(--font-display); color: var(--text);\">${escapeHtml(slots.title || '')}</h2>\n </div>\n <div class=\"flex-1 grid grid-cols-3 gap-6 items-stretch min-h-0 my-auto\">\n ${cards.map((c: any, idx: number) => `\n <div class=\"p-8 rounded-xl border flex flex-col justify-between space-y-4 shadow-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\">\n <div class=\"space-y-3\">\n <span class=\"text-xs font-mono font-bold uppercase tracking-wider px-3 py-1 rounded border inline-block\" style=\"border-color: var(--border); color: var(--primary);\">\n ${escapeHtml(c.badge || `0${idx + 1}`)}\n </span>\n <h3 class=\"text-2xl font-bold mt-2\" style=\"color: var(--text);\">${escapeHtml(c.title || '')}</h3>\n <p class=\"text-base leading-relaxed opacity-85\" style=\"color: var(--text-muted);\">${escapeHtml(c.desc || '')}</p>\n </div>\n ${c.footer ? `<div class=\"text-xs font-mono opacity-65 border-t pt-3\" style=\"border-color: var(--border); color: var(--text-muted);\">${escapeHtml(c.footer)}</div>` : ''}\n </div>\n `).join('')}\n </div>\n </div>\n `;\n },\n },\n\n 'timeline-steps': {\n id: 'timeline-steps',\n name: 'Timeline / Workflow Steps',\n category: 'timeline',\n description: 'Step-by-step workflow, pipeline stages, or algorithm execution order',\n slots: [\n { name: 'tag', label: 'Section Tag', type: 'badge', description: 'e.g. Execution Flow' },\n { name: 'title', label: 'Slide Title', type: 'text', description: 'Workflow title', required: true },\n { name: 'steps', label: 'Steps List', type: 'options', description: 'Array of {stepNum, title, desc}' },\n ],\n template: (slots, theme) => {\n const steps = Array.isArray(slots.steps) ? slots.steps : [];\n return `\n <div class=\"h-full w-full flex flex-col p-16 gap-6 justify-between\">\n <div>\n ${slots.tag ? `<span class=\"text-xs uppercase tracking-widest font-bold opacity-80\" style=\"color: var(--primary);\">${escapeHtml(slots.tag)}</span>` : ''}\n <h2 class=\"text-4xl font-bold mt-1.5\" style=\"font-family: var(--font-display); color: var(--text);\">${escapeHtml(slots.title || '')}</h2>\n </div>\n <div class=\"flex-1 flex flex-col justify-center my-auto\">\n <div class=\"grid grid-cols-${steps.length || 4} gap-5 relative\">\n ${steps.map((st: any, idx: number) => `\n <div class=\"flex flex-col space-y-3 p-6 rounded-xl border relative shadow-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\">\n <div class=\"w-10 h-10 rounded-xl flex items-center justify-center font-bold text-lg shadow\" style=\"background-color: var(--primary); color: #FFFFFF;\">\n ${escapeHtml(st.stepNum || idx + 1)}\n </div>\n <h4 class=\"text-xl font-bold\" style=\"color: var(--text);\">${escapeHtml(st.title || '')}</h4>\n <p class=\"text-sm opacity-85 leading-relaxed\" style=\"color: var(--text-muted);\">${escapeHtml(st.desc || '')}</p>\n </div>\n `).join('')}\n </div>\n </div>\n </div>\n `;\n },\n },\n\n 'metric-callout': {\n id: 'metric-callout',\n name: 'Metric / Key Callout',\n category: 'callout',\n description: 'High-impact slide emphasizing a critical benchmark, theorem, or takeaway statistic',\n slots: [\n { name: 'tag', label: 'Category Tag', type: 'badge', description: 'e.g. Performance Benchmark' },\n { name: 'metric', label: 'Big Stat / Number', type: 'metric', description: 'e.g. 10x, 99.9%, O(1)' },\n { name: 'metricLabel', label: 'Metric Label', type: 'text', description: 'Short metric description' },\n { name: 'title', label: 'Callout Headline', type: 'text', description: 'Main point of this stat', required: true },\n { name: 'desc', label: 'Context Explanation', type: 'multiline', description: 'Deep context or impact' },\n ],\n template: (slots, theme) => `\n <div class=\"h-full w-full flex flex-col justify-center items-center p-16 text-center space-y-6 my-auto\">\n ${slots.tag ? `<div class=\"px-5 py-1.5 rounded-full text-xs font-bold uppercase tracking-widest border\" style=\"border-color: var(--border); color: var(--primary);\">${escapeHtml(slots.tag)}</div>` : ''}\n <div class=\"text-8xl font-black tracking-tighter\" style=\"font-family: var(--font-display); color: var(--primary);\">\n ${escapeHtml(slots.metric || '100%')}\n </div>\n ${slots.metricLabel ? `<div class=\"text-lg font-bold tracking-widest uppercase opacity-75\" style=\"color: var(--text-muted);\">${escapeHtml(slots.metricLabel)}</div>` : ''}\n <h2 class=\"text-4xl font-extrabold max-w-3xl leading-tight\" style=\"font-family: var(--font-display); color: var(--text);\">${escapeHtml(slots.title || '')}</h2>\n ${slots.desc ? `<p class=\"text-lg max-w-2xl opacity-85 leading-relaxed\" style=\"color: var(--text-muted);\">${escapeHtml(slots.desc)}</p>` : ''}\n </div>\n `,\n },\n\n 'checkpoint-quiz': {\n id: 'checkpoint-quiz',\n name: 'Interactive Checkpoint Quiz',\n category: 'assessment',\n description: 'Interactive mid-lesson comprehension check with option cards and revealable answer',\n slots: [\n { name: 'tag', label: 'Badge', type: 'badge', description: 'e.g. Knowledge Check' },\n { name: 'question', label: 'Question Text', type: 'multiline', description: 'The question to answer', required: true },\n { name: 'options', label: 'Options List', type: 'options', description: 'Array of {label, text, isCorrect}' },\n { name: 'explanation', label: 'Explanation', type: 'multiline', description: 'Explanation revealed on answer' },\n ],\n template: (slots, theme) => {\n const opts = Array.isArray(slots.options) ? slots.options : [];\n return `\n <div class=\"h-full w-full flex flex-col p-16 gap-6 justify-between\">\n <div>\n ${slots.tag ? `<span class=\"text-xs uppercase tracking-widest font-bold opacity-80\" style=\"color: var(--primary);\">${escapeHtml(slots.tag)}</span>` : ''}\n <h2 class=\"text-3xl font-extrabold mt-1.5 leading-snug max-w-4xl\" style=\"font-family: var(--font-display); color: var(--text);\">${escapeHtml(slots.question || 'Quick Check')}</h2>\n </div>\n <div class=\"w-full grid grid-cols-2 gap-5 items-stretch min-h-0 my-auto\">\n ${opts.map((opt: any, idx: number) => {\n const letter = opt.label || String.fromCharCode(65 + idx);\n return `\n <div class=\"quiz-option p-6 rounded-xl border flex items-center gap-4 shadow-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\">\n <span class=\"opt-badge w-12 h-12 rounded-xl flex items-center justify-center font-bold text-lg border shrink-0\" style=\"border-color: var(--border); color: var(--primary);\">\n ${escapeHtml(letter)}\n </span>\n <span class=\"text-lg font-medium leading-relaxed\" style=\"color: var(--text);\">${escapeHtml(opt.text || '')}</span>\n </div>\n `;\n }).join('')}\n </div>\n ${slots.explanation ? `\n <div class=\"quiz-explanation p-4 rounded-xl border text-sm flex items-center gap-3 opacity-90 shadow-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border); color: var(--text);\">\n <span class=\"text-xl\">💡</span>\n <div><strong class=\"text-primary font-bold\">Hint / Explanation:</strong> ${escapeHtml(slots.explanation)}</div>\n </div>\n ` : ''}\n </div>\n `;\n },\n },\n\n 'summary-takeaways': {\n id: 'summary-takeaways',\n name: 'Summary & Takeaways',\n category: 'content',\n description: 'End-of-lesson wrap-up slide with bulleted takeaways and next lesson teaser',\n slots: [\n { name: 'tag', label: 'Tag', type: 'badge', description: 'e.g. Recap' },\n { name: 'title', label: 'Slide Title', type: 'text', description: 'Wrap up headline', required: true },\n { name: 'takeaways', label: 'Takeaways List', type: 'list', description: 'Key points students should remember' },\n { name: 'nextStep', label: 'Next Lesson / Challenge', type: 'text', description: 'Preview of what comes next' },\n ],\n template: (slots, theme) => {\n const takeaways = Array.isArray(slots.takeaways) ? slots.takeaways : [];\n return `\n <div class=\"h-full w-full flex flex-col p-16 gap-6 justify-between\">\n <div>\n ${slots.tag ? `<span class=\"text-xs uppercase tracking-widest font-bold opacity-80\" style=\"color: var(--primary);\">${escapeHtml(slots.tag)}</span>` : ''}\n <h2 class=\"text-4xl font-bold mt-1.5\" style=\"font-family: var(--font-display); color: var(--text);\">${escapeHtml(slots.title || 'Summary')}</h2>\n </div>\n <div class=\"flex-1 flex flex-col justify-center space-y-6 min-h-0 my-auto\">\n <div class=\"space-y-4\">\n ${takeaways.map((t: string) => `\n <div class=\"p-5 rounded-xl border flex items-start gap-4 shadow-sm\" style=\"background-color: var(--bg-secondary); border-color: var(--border);\">\n <span class=\"text-xs font-bold w-7 h-7 rounded-full flex items-center justify-center flex-shrink-0 mt-0.5 shadow-sm\" style=\"background-color: var(--primary); color: #FFF;\">✓</span>\n <span class=\"text-lg font-medium leading-relaxed\" style=\"color: var(--text);\">${escapeHtml(t)}</span>\n </div>\n `).join('')}\n </div>\n ${slots.nextStep ? `\n <div class=\"p-6 rounded-xl border flex items-center justify-between shadow-sm\" style=\"border-color: var(--primary); background-color: var(--bg-secondary);\">\n <div>\n <div class=\"text-xs uppercase font-bold tracking-widest opacity-80\" style=\"color: var(--primary);\">Next Session</div>\n <div class=\"text-lg font-bold mt-1\" style=\"color: var(--text);\">${escapeHtml(slots.nextStep)}</div>\n </div>\n <span class=\"text-2xl\" style=\"color: var(--primary);\">➔</span>\n </div>\n ` : ''}\n </div>\n </div>\n `;\n },\n },\n};\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — Self-Contained HTML Slide Shell Generator\n// 1920x1080 Fixed Canvas, Auto-Scaling, Keyboard Navigation, postMessage Bridge\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport type { HtmlDeckTheme } from './types.js';\n\nexport interface GenerateHtmlShellOptions {\n title: string;\n theme: HtmlDeckTheme;\n slidesHtml: string;\n slideCount: number;\n customHeadTags?: string;\n deckId?: string;\n}\n\nexport function generateHtmlShell(options: GenerateHtmlShellOptions): string {\n const { title, theme, slidesHtml, slideCount, customHeadTags = '', deckId = '' } = options;\n\n return `<!DOCTYPE html>\n<html lang=\"en\" class=\"${theme.scheme}\"${deckId ? ` data-deck-id=\"${deckId}\"` : ''}>\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n <title>${title}</title>\n \n <!-- Fonts -->\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Plus+Jakarta+Sans:wght@500;700;800&family=Space+Grotesk:wght@500;700&display=swap\" rel=\"stylesheet\">\n\n <!-- Core Presentation Styling & 1920x1080 Scaled Tailwind Configuration -->\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script>\n window.tailwind = window.tailwind || {};\n tailwind.config = {\n darkMode: 'class',\n theme: {\n extend: {\n fontSize: {\n 'xs': ['var(--font-size-xs, 14px)', { lineHeight: '1.4' }],\n 'sm': ['var(--font-size-sm, 16px)', { lineHeight: '1.45' }],\n 'base': ['var(--font-size-base, 18px)', { lineHeight: '1.5' }],\n 'lg': ['var(--font-size-lg, 20px)', { lineHeight: '1.5' }],\n 'xl': ['var(--font-size-xl, 22px)', { lineHeight: '1.5' }],\n '2xl': ['var(--font-size-2xl, 26px)', { lineHeight: '1.4' }],\n '3xl': ['var(--font-size-3xl, 32px)', { lineHeight: '1.3' }],\n '4xl': ['var(--font-size-4xl, 38px)', { lineHeight: '1.25' }],\n '5xl': ['var(--font-size-5xl, 46px)', { lineHeight: '1.2' }],\n '6xl': ['var(--font-size-6xl, 58px)', { lineHeight: '1.15' }],\n '7xl': ['var(--font-size-7xl, 72px)', { lineHeight: '1.1' }],\n '8xl': ['var(--font-size-8xl, 96px)', { lineHeight: '1.05' }],\n },\n spacing: {\n '2': 'calc(0.5rem * var(--scale-spacing-eff, 1))',\n '3': 'calc(0.75rem * var(--scale-spacing-eff, 1))',\n '4': 'calc(1rem * var(--scale-spacing-eff, 1))',\n '5': 'calc(1.25rem * var(--scale-spacing-eff, 1))',\n '6': 'calc(1.5rem * var(--scale-spacing-eff, 1))',\n '8': 'calc(2rem * var(--scale-spacing-eff, 1))',\n '10': 'calc(2.5rem * var(--scale-spacing-eff, 1))',\n '12': 'calc(3rem * var(--scale-spacing-eff, 1))',\n '16': 'calc(4rem * var(--scale-spacing-eff, 1))',\n '20': 'calc(5rem * var(--scale-spacing-eff, 1))',\n '24': 'calc(6rem * var(--scale-spacing-eff, 1))',\n },\n colors: {\n themeBg: 'var(--bg)',\n themeBgSecondary: 'var(--bg-secondary)',\n themePrimary: 'var(--primary)',\n themeText: 'var(--text)',\n themeMuted: 'var(--text-muted)',\n themeBorder: 'var(--border)',\n }\n }\n }\n }\n </script>\n\n <style>\n :root {\n /* Scaling Multiplier Architecture: Unified vs Independent */\n --scale-mode: unified;\n --scale-factor: 1.0;\n --scale-headings: 1.0;\n --scale-body: 1.0;\n --scale-code: 1.0;\n --scale-spacing: 1.0;\n\n /* Effective Multipliers */\n --scale-headings-eff: 1.0;\n --scale-body-eff: 1.0;\n --scale-code-eff: 1.0;\n --scale-spacing-eff: 1.0;\n\n --bg: ${theme.palette.bg};\n --bg-secondary: ${theme.palette.bgSecondary || theme.palette.bg};\n --primary: ${theme.palette.primary};\n --accent: ${theme.palette.accent || theme.palette.primary};\n --text: ${theme.palette.text};\n --text-muted: ${theme.palette.textMuted};\n --border: ${theme.palette.border || 'rgba(0, 0, 0, 0.12)'};\n --font-display: ${theme.typography.display};\n --font-body: ${theme.typography.body};\n --font-code: ${theme.typography.code || 'monospace'};\n\n /* Dynamic Typography calculated from effective multipliers */\n --font-size-xs: calc(14px * var(--scale-code-eff));\n --font-size-sm: calc(16px * var(--scale-code-eff));\n --font-size-base: calc(18px * var(--scale-body-eff));\n --font-size-lg: calc(20px * var(--scale-body-eff));\n --font-size-xl: calc(22px * var(--scale-body-eff));\n --font-size-2xl: calc(26px * var(--scale-body-eff));\n --font-size-3xl: calc(32px * var(--scale-headings-eff));\n --font-size-4xl: calc(38px * var(--scale-headings-eff));\n --font-size-5xl: calc(46px * var(--scale-headings-eff));\n --font-size-6xl: calc(58px * var(--scale-headings-eff));\n --font-size-7xl: calc(72px * var(--scale-headings-eff));\n --font-size-8xl: calc(96px * var(--scale-headings-eff));\n }\n\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n html, body {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background-color: #050507;\n font-family: var(--font-body);\n color: var(--text);\n user-select: none;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n #viewport {\n position: absolute;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: #050507;\n overflow: hidden;\n }\n\n .slide-canvas {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 1920px;\n height: 1080px;\n transform: translate(-50%, -50%);\n transform-origin: center center;\n background-color: var(--bg);\n overflow: hidden;\n box-shadow: 0 30px 90px rgba(0, 0, 0, 0.6);\n border-radius: 4px;\n }\n\n .slide-page {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: none;\n opacity: 0;\n transition: opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n .slide-page.active {\n display: block;\n opacity: 1;\n }\n\n /* Top Progress Bar */\n #progress-bar {\n position: absolute;\n top: 0;\n left: 0;\n height: 5px;\n background-color: var(--primary);\n transition: width 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n z-index: 50;\n }\n\n /* Floating Navigation Controls */\n #controls {\n position: absolute;\n bottom: 28px;\n right: 28px;\n display: flex;\n align-items: center;\n gap: 12px;\n background: rgba(15, 15, 20, 0.75);\n backdrop-filter: blur(16px);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 9999px;\n padding: 8px 20px;\n z-index: 100;\n opacity: 0;\n transition: opacity 0.25s ease;\n }\n\n body:hover #controls {\n opacity: 1;\n }\n\n .control-btn {\n background: transparent;\n border: none;\n color: #ffffff;\n cursor: pointer;\n font-size: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 6px;\n border-radius: 8px;\n transition: background-color 0.15s, transform 0.1s;\n }\n\n .control-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(1.08);\n }\n\n #slide-counter {\n color: #ffffff;\n font-size: 15px;\n font-family: var(--font-code);\n font-weight: 600;\n letter-spacing: 0.08em;\n padding: 0 4px;\n }\n\n /* Interactive Quiz Styling */\n .quiz-option {\n cursor: pointer;\n user-select: none;\n transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n .quiz-option:hover {\n transform: translateY(-2px);\n border-color: var(--primary) !important;\n box-shadow: 0 12px 30px -8px rgba(0, 0, 0, 0.15);\n }\n\n .quiz-option.selected {\n border-color: var(--primary) !important;\n box-shadow: 0 0 0 3px var(--primary);\n }\n\n .quiz-option.selected .opt-badge {\n background-color: var(--primary) !important;\n color: #ffffff !important;\n border-color: var(--primary) !important;\n }\n\n .quiz-explanation {\n transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n /* ── WYSIWYG Inline Editing (Level 1) Styles ── */\n .edit-hotzone {\n position: fixed;\n top: 0;\n left: 0;\n width: 90px;\n height: 90px;\n z-index: 9999;\n cursor: pointer;\n }\n\n .edit-toggle {\n position: fixed;\n top: 24px;\n left: 24px;\n z-index: 10000;\n background: rgba(15, 15, 20, 0.85);\n backdrop-filter: blur(14px);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 9999px;\n color: #ffffff;\n padding: 7px 16px;\n font-size: 14px;\n font-family: var(--font-body);\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.25s cubic-bezier(0.16, 1, 0.3, 1), transform 0.15s;\n }\n\n .edit-toggle:hover {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(1.04);\n }\n\n .edit-toggle.show,\n .edit-toggle.active {\n opacity: 1;\n pointer-events: auto;\n }\n\n .edit-toggle.active {\n background: var(--primary);\n border-color: var(--primary);\n color: #ffffff;\n box-shadow: 0 0 20px rgba(0, 0, 0, 0.4);\n }\n\n #edit-bar {\n position: fixed;\n bottom: 28px;\n left: 50%;\n transform: translateX(-50%);\n background: rgba(15, 15, 20, 0.92);\n backdrop-filter: blur(16px);\n border: 1px solid rgba(255, 255, 255, 0.22);\n border-radius: 9999px;\n padding: 6px 18px;\n display: flex;\n align-items: center;\n gap: 10px;\n z-index: 10000;\n box-shadow: 0 20px 45px rgba(0, 0, 0, 0.5);\n animation: editBarSlideUp 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n @keyframes editBarSlideUp {\n from { opacity: 0; transform: translate(-50%, 15px); }\n to { opacity: 1; transform: translate(-50%, 0); }\n }\n\n .edit-bar-btn {\n background: transparent;\n border: none;\n color: #ffffff;\n font-size: 14px;\n font-weight: 600;\n padding: 6px 12px;\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: background 0.15s, transform 0.1s;\n }\n\n .edit-bar-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n transform: translateY(-1px);\n }\n\n .edit-bar-btn.save-btn {\n background: var(--primary);\n color: #ffffff;\n }\n .edit-bar-btn.save-btn:hover {\n filter: brightness(1.12);\n }\n\n .edit-bar-divider {\n width: 1px;\n height: 20px;\n background: rgba(255, 255, 255, 0.2);\n }\n\n /* Editable active styles */\n body.edit-mode-active [contenteditable=\"true\"] {\n outline: 1px dashed rgba(100, 149, 237, 0.35);\n outline-offset: 3px;\n cursor: text;\n border-radius: 4px;\n }\n\n body.edit-mode-active [contenteditable=\"true\"]:hover {\n outline: 2px dashed var(--primary);\n }\n\n body.edit-mode-active [contenteditable=\"true\"]:focus {\n outline: 2px solid var(--primary);\n background: rgba(100, 149, 237, 0.08);\n }\n\n /* ─── Floating Scale Tuning Panel (Unified vs Independent) ─── */\n #scale-panel {\n position: fixed;\n bottom: 82px;\n left: 50%;\n transform: translateX(-50%);\n width: 390px;\n background: rgba(18, 18, 26, 0.94);\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 16px;\n padding: 16px 20px;\n z-index: 10002;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.65), 0 0 0 1px rgba(255, 255, 255, 0.08);\n color: #f4f4f5;\n font-family: var(--font-body);\n animation: scalePanelPop 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n @keyframes scalePanelPop {\n from { opacity: 0; transform: translate(-50%, 10px) scale(0.97); }\n to { opacity: 1; transform: translate(-50%, 0) scale(1); }\n }\n\n .scale-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 14px;\n padding-bottom: 10px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.12);\n }\n\n .scale-panel-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: #ffffff;\n text-transform: uppercase;\n }\n\n .scale-mode-switch {\n display: flex;\n background: rgba(0, 0, 0, 0.35);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 9999px;\n padding: 2px;\n gap: 2px;\n }\n\n .mode-tab {\n background: transparent;\n border: none;\n color: #a1a1aa;\n font-size: 11px;\n font-weight: 600;\n padding: 3px 10px;\n border-radius: 9999px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n\n .mode-tab.active {\n background: var(--primary);\n color: #ffffff;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);\n }\n\n .scale-panel-close {\n background: transparent;\n border: none;\n color: #71717a;\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: color 0.15s, background 0.15s;\n }\n\n .scale-panel-close:hover {\n color: #ffffff;\n background: rgba(255, 255, 255, 0.1);\n }\n\n .scale-slider-row {\n margin-bottom: 12px;\n }\n\n .scale-slider-row:last-child {\n margin-bottom: 0;\n }\n\n .scale-slider-label-wrap {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 12px;\n font-weight: 500;\n color: #d4d4d8;\n margin-bottom: 5px;\n }\n\n .scale-badge {\n font-family: var(--font-code);\n font-size: 11px;\n font-weight: 600;\n background: rgba(255, 255, 255, 0.1);\n padding: 1px 6px;\n border-radius: 4px;\n color: #38bdf8;\n }\n\n .scale-range-slider {\n -webkit-appearance: none;\n appearance: none;\n width: 100%;\n height: 6px;\n border-radius: 3px;\n background: rgba(255, 255, 255, 0.18);\n outline: none;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .scale-range-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--primary);\n cursor: pointer;\n box-shadow: 0 0 6px rgba(0, 0, 0, 0.5);\n transition: transform 0.1s;\n }\n\n .scale-range-slider::-webkit-slider-thumb:hover {\n transform: scale(1.2);\n }\n\n .density-presets {\n display: flex;\n gap: 8px;\n margin-top: 14px;\n }\n\n .density-chip {\n flex: 1;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 8px;\n color: #d4d4d8;\n font-size: 11px;\n font-weight: 600;\n padding: 6px 0;\n cursor: pointer;\n text-align: center;\n transition: all 0.15s ease;\n }\n\n .density-chip:hover {\n background: rgba(255, 255, 255, 0.12);\n color: #ffffff;\n }\n\n .density-chip.active {\n background: rgba(56, 189, 248, 0.2);\n border-color: #38bdf8;\n color: #38bdf8;\n }\n\n .scale-independent-footer {\n display: flex;\n justify-content: flex-end;\n margin-top: 12px;\n padding-top: 10px;\n border-top: 1px solid rgba(255, 255, 255, 0.08);\n }\n\n .btn-reset-scales {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 6px;\n color: #a1a1aa;\n font-size: 11px;\n font-weight: 600;\n padding: 4px 10px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n\n .btn-reset-scales:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #ffffff;\n border-color: rgba(255, 255, 255, 0.3);\n }\n\n /* ─── Step-by-Step Reveal (Animation Steps / Build-In) ─── */\n .step-reveal,\n [data-step],\n [data-reveal],\n [data-click],\n .v-click {\n opacity: 0;\n transform: translateY(10px);\n transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1), transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);\n pointer-events: none;\n }\n\n .step-reveal.revealed,\n [data-step].revealed,\n [data-reveal].revealed,\n [data-click].revealed,\n .v-click.visible,\n body.is-editing .step-reveal,\n body.is-editing [data-step],\n body.is-editing [data-reveal],\n body.is-editing [data-click],\n body.is-editing .v-click,\n body.mode-deck .step-reveal,\n body.mode-deck [data-step],\n body.mode-deck [data-reveal],\n body.mode-deck [data-click],\n body.mode-deck .v-click {\n opacity: 1 !important;\n transform: translateY(0) !important;\n pointer-events: auto !important;\n }\n\n /* ─── Deck Mode (Continuous Vertical Scroll) ─── */\n body.mode-deck {\n overflow-y: auto !important;\n height: auto !important;\n min-height: 100vh;\n background-color: #08080c !important;\n user-select: auto !important;\n }\n\n body.mode-deck #viewport {\n position: relative !important;\n width: 100% !important;\n height: auto !important;\n min-height: 100vh;\n overflow-y: visible !important;\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n padding: 60px 24px 140px 24px !important;\n gap: 36px !important;\n background-color: transparent !important;\n }\n\n body.mode-deck .slide-canvas {\n position: relative !important;\n top: auto !important;\n left: auto !important;\n transform: none !important;\n width: 100% !important;\n max-width: 1200px !important;\n height: auto !important;\n aspect-ratio: 16 / 9 !important;\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6) !important;\n border: 1px solid rgba(255, 255, 255, 0.1) !important;\n border-radius: 8px !important;\n }\n\n body.mode-deck .slide-page {\n display: block !important;\n opacity: 1 !important;\n position: relative !important;\n width: 100% !important;\n height: 100% !important;\n }\n\n /* Deck Notes Card under each slide */\n .deck-notes-card {\n display: none;\n width: 100%;\n max-width: 1200px;\n margin-top: -16px;\n margin-bottom: 24px;\n background: rgba(20, 20, 28, 0.95);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-left: 4px solid var(--primary);\n border-radius: 8px;\n padding: 16px 22px;\n color: #e4e4e7;\n font-size: 14px;\n line-height: 1.65;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);\n }\n\n .deck-notes-card-header {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: var(--primary);\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n body.mode-deck .deck-notes-card,\n body.show-deck-notes .deck-notes-card {\n display: block;\n }\n\n /* ─── Presenter Drawer (In-Page) ─── */\n #presenter-drawer {\n position: fixed;\n bottom: 0;\n left: 0;\n width: 100%;\n max-height: 380px;\n background: rgba(14, 14, 20, 0.96);\n backdrop-filter: blur(24px);\n -webkit-backdrop-filter: blur(24px);\n border-top: 1px solid rgba(255, 255, 255, 0.18);\n border-top-left-radius: 18px;\n border-top-right-radius: 18px;\n padding: 18px 28px 24px 28px;\n z-index: 10005;\n box-shadow: 0 -15px 40px rgba(0, 0, 0, 0.7);\n color: #f4f4f5;\n display: flex;\n flex-direction: column;\n gap: 12px;\n transform: translateY(100%);\n transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n #presenter-drawer.open {\n transform: translateY(0);\n }\n\n .presenter-drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n padding-bottom: 12px;\n }\n\n .presenter-meta-group {\n display: flex;\n align-items: center;\n gap: 18px;\n }\n\n .presenter-timer-badge {\n font-family: var(--font-code);\n font-size: 15px;\n font-weight: 700;\n color: #38bdf8;\n background: rgba(56, 189, 248, 0.12);\n border: 1px solid rgba(56, 189, 248, 0.3);\n padding: 3px 10px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .presenter-notes-box {\n flex: 1;\n overflow-y: auto;\n font-size: 16px;\n line-height: 1.7;\n color: #f1f5f9;\n background: rgba(0, 0, 0, 0.25);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 8px;\n padding: 14px 18px;\n max-height: 220px;\n user-select: text;\n }\n\n /* ─── Print Modal / Dialog ─── */\n #print-modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n background: rgba(0, 0, 0, 0.65);\n backdrop-filter: blur(8px);\n z-index: 10010;\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #print-modal.open {\n display: flex;\n }\n\n .print-dialog-card {\n width: 440px;\n background: #181822;\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 16px;\n padding: 24px;\n box-shadow: 0 25px 60px rgba(0, 0, 0, 0.7);\n color: #ffffff;\n display: flex;\n flex-direction: column;\n gap: 18px;\n }\n\n .print-dialog-title {\n font-size: 17px;\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .print-option-row {\n display: flex;\n align-items: center;\n gap: 10px;\n background: rgba(255, 255, 255, 0.05);\n padding: 12px 14px;\n border-radius: 8px;\n cursor: pointer;\n font-size: 14px;\n }\n\n .print-dialog-actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 10px;\n }\n\n /* ─── Controls Extra Buttons & Badges ─── */\n .step-badge {\n font-family: var(--font-code);\n font-size: 11px;\n font-weight: 600;\n background: rgba(255, 255, 255, 0.12);\n color: #a5f3fc;\n padding: 2px 7px;\n border-radius: 4px;\n display: none;\n }\n\n .control-divider {\n width: 1px;\n height: 16px;\n background: rgba(255, 255, 255, 0.18);\n margin: 0 2px;\n }\n\n /* ─── Print Engine (@media print) ─── */\n @media print {\n @page {\n size: landscape;\n margin: 0;\n }\n\n html, body {\n width: 100% !important;\n height: auto !important;\n background: #ffffff !important;\n color: #000000 !important;\n overflow: visible !important;\n user-select: text !important;\n }\n\n #controls,\n #edit-bar,\n #scale-panel,\n #progress-bar,\n .edit-hotzone,\n .edit-toggle,\n #presenter-drawer,\n #print-modal {\n display: none !important;\n }\n\n #viewport {\n position: static !important;\n width: 100% !important;\n height: auto !important;\n display: block !important;\n padding: 0 !important;\n background: transparent !important;\n overflow: visible !important;\n }\n\n .slide-canvas {\n position: relative !important;\n top: auto !important;\n left: auto !important;\n transform: none !important;\n width: 100vw !important;\n height: 56.25vw !important; /* 16:9 ratio */\n max-height: 100vh !important;\n margin: 0 auto !important;\n page-break-inside: avoid !important;\n break-inside: avoid !important;\n page-break-after: always !important;\n break-after: page !important;\n box-shadow: none !important;\n border: none !important;\n border-radius: 0 !important;\n background-color: var(--bg) !important;\n -webkit-print-color-adjust: exact !important;\n print-color-adjust: exact !important;\n }\n\n .slide-page {\n display: block !important;\n opacity: 1 !important;\n position: relative !important;\n width: 100% !important;\n height: 100% !important;\n }\n\n /* Step elements always visible when printing */\n .step-reveal, [data-step], [data-reveal], [data-click], .v-click {\n opacity: 1 !important;\n transform: none !important;\n }\n\n /* When printing with notes */\n body.print-with-notes .slide-canvas {\n height: 48vw !important;\n page-break-after: avoid !important;\n break-after: avoid !important;\n }\n\n body.print-with-notes .deck-notes-card {\n display: block !important;\n page-break-after: always !important;\n break-after: page !important;\n background: #f8fafc !important;\n border: 1px solid #cbd5e1 !important;\n border-left: 5px solid #2563eb !important;\n color: #1e293b !important;\n margin: 12px auto 32px auto !important;\n width: 95vw !important;\n box-shadow: none !important;\n font-size: 12pt !important;\n line-height: 1.5 !important;\n padding: 12px 18px !important;\n }\n\n body.print-with-notes .deck-notes-card-header {\n color: #1e40af !important;\n font-size: 10pt !important;\n }\n }\n\n ${theme.customCss || ''}\n </style>\n ${customHeadTags}\n</head>\n<body>\n <div id=\"viewport\">\n <div class=\"slide-canvas\" id=\"canvas\">\n <div id=\"progress-bar\"></div>\n ${slidesHtml}\n </div>\n </div>\n\n <!-- WYSIWYG Inline Edit UI (Level 1) -->\n <div class=\"edit-hotzone\" id=\"edit-hotzone\"></div>\n <button class=\"edit-toggle\" id=\"btn-edit-toggle\" title=\"Toggle Inline Edit Mode (E)\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\"/></svg>\n <span id=\"edit-toggle-label\">Edit Mode (E)</span>\n </button>\n\n <!-- Floating Scale Tuning Panel -->\n <div id=\"scale-panel\" style=\"display: none;\">\n <div class=\"scale-panel-header\">\n <div class=\"scale-panel-title\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\"><path d=\"M21 3 3 21\"/><path d=\"m14 4 6 6\"/><path d=\"m4 14 6 6\"/></svg>\n <span>Scale Tuning</span>\n </div>\n <div class=\"scale-mode-switch\">\n <button type=\"button\" class=\"mode-tab active\" id=\"tab-mode-unified\">Unified</button>\n <button type=\"button\" class=\"mode-tab\" id=\"tab-mode-independent\">Independent</button>\n </div>\n <button type=\"button\" class=\"scale-panel-close\" id=\"btn-scale-panel-close\" title=\"Close Panel\" style=\"display: flex; align-items: center; justify-content: center;\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>\n </button>\n </div>\n\n <!-- Unified Mode Content -->\n <div id=\"scale-unified-content\" class=\"scale-content-block\">\n <div class=\"scale-slider-row\">\n <div class=\"scale-slider-label-wrap\">\n <span class=\"scale-slider-label\">Scale All</span>\n <span class=\"scale-badge\" id=\"badge-scale-factor\">100%</span>\n </div>\n <input type=\"range\" id=\"input-scale-factor\" min=\"70\" max=\"150\" value=\"100\" class=\"scale-range-slider\" />\n </div>\n <div class=\"density-presets\">\n <button type=\"button\" class=\"density-chip\" data-scale=\"85\">Compact (85%)</button>\n <button type=\"button\" class=\"density-chip active\" data-scale=\"100\">Default (100%)</button>\n <button type=\"button\" class=\"density-chip\" data-scale=\"120\">Spacious (120%)</button>\n </div>\n </div>\n\n <!-- Independent Mode Content -->\n <div id=\"scale-independent-content\" class=\"scale-content-block\" style=\"display: none;\">\n <div class=\"scale-slider-row\">\n <div class=\"scale-slider-label-wrap\">\n <span class=\"scale-slider-label\">Headings (H1–H4)</span>\n <span class=\"scale-badge\" id=\"badge-scale-headings\">100%</span>\n </div>\n <input type=\"range\" id=\"input-scale-headings\" min=\"70\" max=\"150\" value=\"100\" class=\"scale-range-slider\" />\n </div>\n <div class=\"scale-slider-row\">\n <div class=\"scale-slider-label-wrap\">\n <span class=\"scale-slider-label\">Body &amp; Lists</span>\n <span class=\"scale-badge\" id=\"badge-scale-body\">100%</span>\n </div>\n <input type=\"range\" id=\"input-scale-body\" min=\"70\" max=\"150\" value=\"100\" class=\"scale-range-slider\" />\n </div>\n <div class=\"scale-slider-row\">\n <div class=\"scale-slider-label-wrap\">\n <span class=\"scale-slider-label\">Code &amp; Notes</span>\n <span class=\"scale-badge\" id=\"badge-scale-code\">100%</span>\n </div>\n <input type=\"range\" id=\"input-scale-code\" min=\"70\" max=\"150\" value=\"100\" class=\"scale-range-slider\" />\n </div>\n <div class=\"scale-slider-row\">\n <div class=\"scale-slider-label-wrap\">\n <span class=\"scale-slider-label\">Padding &amp; Gaps</span>\n <span class=\"scale-badge\" id=\"badge-scale-spacing\">100%</span>\n </div>\n <input type=\"range\" id=\"input-scale-spacing\" min=\"70\" max=\"150\" value=\"100\" class=\"scale-range-slider\" />\n </div>\n <div class=\"scale-independent-footer\">\n <button type=\"button\" class=\"btn-reset-scales\" id=\"btn-reset-scales\" style=\"display: flex; align-items: center; gap: 4px;\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"/><path d=\"M3 3v5h5\"/></svg>\n <span>Reset All</span>\n </button>\n </div>\n </div>\n </div>\n\n <div id=\"edit-bar\" style=\"display: none;\">\n <span style=\"font-size: 13px; font-weight: 700; color: #a1a1aa; text-transform: uppercase; letter-spacing: 0.05em; padding-left: 4px;\">Editing</span>\n <div class=\"edit-bar-divider\"></div>\n <button class=\"edit-bar-btn\" id=\"btn-format-bold\" title=\"Bold (Cmd+B)\"><strong>B</strong></button>\n <button class=\"edit-bar-btn\" id=\"btn-format-italic\" title=\"Italic (Cmd+I)\"><em>I</em></button>\n <button class=\"edit-bar-btn\" id=\"btn-format-underline\" title=\"Underline (Cmd+U)\"><u>U</u></button>\n <div class=\"edit-bar-divider\"></div>\n <button class=\"edit-bar-btn\" id=\"btn-editbar-scale\" title=\"Tune Element Scales (Unified / Independent)\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 3 3 21\"/><path d=\"m14 4 6 6\"/><path d=\"m4 14 6 6\"/></svg>\n <span>Scale</span>\n </button>\n <div class=\"edit-bar-divider\"></div>\n <button class=\"edit-bar-btn\" id=\"btn-reset-edits\" title=\"Restore original content\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"/><path d=\"M3 3v5h5\"/></svg>\n <span>Reset</span>\n </button>\n <button class=\"edit-bar-btn save-btn\" id=\"btn-save-html\" title=\"Save and download clean HTML file\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z\"/><polyline points=\"17 21 17 13 7 13 7 21\"/><polyline points=\"7 3 7 8 15 8\"/></svg>\n <span>Save HTML</span>\n </button>\n <button class=\"edit-bar-btn\" id=\"btn-done-edit\" title=\"Done editing (E)\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"/></svg>\n <span>Done</span>\n </button>\n </div>\n\n <!-- Presenter Drawer (Quick In-Page Notes & Timer) -->\n <div id=\"presenter-drawer\">\n <div class=\"presenter-drawer-header\">\n <div class=\"presenter-meta-group\">\n <span style=\"font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: #a1a1aa;\">Presenter Console</span>\n <div class=\"presenter-timer-badge\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12 6 12 12 16 14\"/></svg>\n <span id=\"presenter-timer-text\">00:00</span>\n </div>\n </div>\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n <button type=\"button\" class=\"btn-reset-scales\" id=\"btn-open-dual-presenter\" title=\"Open separate synced presenter console window for multi-monitor display\" style=\"display: flex; align-items: center; gap: 4px;\">\n <span>Launch 2nd Window</span>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M7 17 17 7\"/><path d=\"M7 7h10v10\"/></svg>\n </button>\n <button type=\"button\" class=\"scale-panel-close\" id=\"btn-close-presenter-drawer\" title=\"Close Drawer (P)\" style=\"display: flex; align-items: center; justify-content: center;\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/></svg>\n </button>\n </div>\n </div>\n <div class=\"presenter-notes-box\" id=\"presenter-notes-text\">\n No notes for this slide.\n </div>\n </div>\n\n <!-- Print Configuration Modal -->\n <div id=\"print-modal\">\n <div class=\"print-dialog-card\">\n <div class=\"print-dialog-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"6 9 6 2 18 2 18 9\"></polyline><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"></path><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"></rect></svg>\n <span>Print &amp; Export PDF</span>\n </div>\n <label class=\"print-option-row\">\n <input type=\"checkbox\" id=\"chk-print-notes\" style=\"width: 18px; height: 18px; accent-color: var(--primary); cursor: pointer;\" />\n <span style=\"user-select: none;\">In kèm ghi chú giảng viên (Handout / Teacher Notes)</span>\n </label>\n <p style=\"font-size: 12px; color: #a1a1aa; line-height: 1.5; margin: 0;\">\n Lưu ý: Chọn trang in Khổ ngang (Landscape), Bật &quot;Background graphics&quot; trong hộp thoại in của trình duyệt để màu sắc hiển thị đúng 100%.\n </p>\n <div class=\"print-dialog-actions\">\n <button type=\"button\" class=\"btn-reset-scales\" id=\"btn-cancel-print\">Hủy</button>\n <button type=\"button\" class=\"edit-bar-btn save-btn\" id=\"btn-start-print\" style=\"padding: 6px 16px; display: flex; align-items: center; gap: 6px;\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 6 2 18 2 18 9\"></polyline><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"></path><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"></rect></svg>\n <span>In ngay (Print)</span>\n </button>\n </div>\n </div>\n </div>\n\n <div id=\"controls\">\n <button class=\"control-btn\" id=\"btn-prev\" title=\"Previous Slide (←)\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"15 18 9 12 15 6\"></polyline></svg>\n </button>\n <span id=\"slide-counter\">01 / ${String(slideCount).padStart(2, '0')}</span>\n <span id=\"step-badge\" class=\"step-badge\">1/1</span>\n <button class=\"control-btn\" id=\"btn-next\" title=\"Next Slide (→)\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"9 18 15 12 9 6\"></polyline></svg>\n </button>\n <div class=\"control-divider\"></div>\n <button class=\"control-btn\" id=\"btn-controls-presenter\" title=\"Presenter Console &amp; Notes (P)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\"/><line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\"/><line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\"/></svg>\n </button>\n <button class=\"control-btn\" id=\"btn-controls-view\" title=\"Toggle Slide / Deck View (D)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"3\" x2=\"21\" y1=\"6\" y2=\"6\"/><line x1=\"3\" x2=\"21\" y1=\"12\" y2=\"12\"/><line x1=\"3\" x2=\"21\" y1=\"18\" y2=\"18\"/></svg>\n </button>\n <button class=\"control-btn\" id=\"btn-controls-print\" title=\"Print &amp; Export PDF (Cmd+P)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"6 9 6 2 18 2 18 9\"></polyline><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"></path><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"></rect></svg>\n </button>\n <button class=\"control-btn\" id=\"btn-controls-scale\" title=\"Tune Scale\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 3 3 21\"/><path d=\"m14 4 6 6\"/><path d=\"m4 14 6 6\"/></svg>\n </button>\n <button class=\"control-btn\" id=\"btn-fullscreen\" title=\"Toggle Fullscreen (F)\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3\"></path></svg>\n </button>\n </div>\n\n <script>\n (function() {\n const TOTAL_SLIDES = ${slideCount};\n let currentSlide = 0;\n let isEditMode = false;\n const canvas = document.getElementById('canvas');\n const originalCanvasHtml = canvas ? canvas.innerHTML : '';\n\n function computeDeckContentHash(str) {\n let h = 0;\n for (let i = 0; i < str.length; i++) {\n h = (Math.imul(31, h) + str.charCodeAt(i)) | 0;\n }\n return Math.abs(h).toString(36);\n }\n\n const deckIdAttr = document.documentElement.getAttribute('data-deck-id');\n const contentHash = computeDeckContentHash(originalCanvasHtml);\n const deckKeyPrefix = deckIdAttr ? encodeURIComponent(deckIdAttr) : (encodeURIComponent(document.title.trim() || 'deck') + '_' + contentHash);\n const STORAGE_KEY = 'deck_edit_' + deckKeyPrefix;\n const slides = document.querySelectorAll('.slide-page');\n const progressBar = document.getElementById('progress-bar');\n const counter = document.getElementById('slide-counter');\n\n // Edit UI elements\n const hotzone = document.getElementById('edit-hotzone');\n const editToggleBtn = document.getElementById('btn-edit-toggle');\n const editBar = document.getElementById('edit-bar');\n const btnBold = document.getElementById('btn-format-bold');\n const btnItalic = document.getElementById('btn-format-italic');\n const btnUnderline = document.getElementById('btn-format-underline');\n const btnReset = document.getElementById('btn-reset-edits');\n const btnSave = document.getElementById('btn-save-html');\n const btnDone = document.getElementById('btn-done-edit');\n\n // Scale Panel UI Elements\n const scalePanel = document.getElementById('scale-panel');\n const tabModeUnified = document.getElementById('tab-mode-unified');\n const tabModeIndependent = document.getElementById('tab-mode-independent');\n const btnScalePanelClose = document.getElementById('btn-scale-panel-close');\n const scaleUnifiedContent = document.getElementById('scale-unified-content');\n const scaleIndependentContent = document.getElementById('scale-independent-content');\n\n const inputScaleFactor = document.getElementById('input-scale-factor');\n const badgeScaleFactor = document.getElementById('badge-scale-factor');\n const inputScaleHeadings = document.getElementById('input-scale-headings');\n const badgeScaleHeadings = document.getElementById('badge-scale-headings');\n const inputScaleBody = document.getElementById('input-scale-body');\n const badgeScaleBody = document.getElementById('badge-scale-body');\n const inputScaleCode = document.getElementById('input-scale-code');\n const badgeScaleCode = document.getElementById('badge-scale-code');\n const inputScaleSpacing = document.getElementById('input-scale-spacing');\n const badgeScaleSpacing = document.getElementById('badge-scale-spacing');\n const btnResetScales = document.getElementById('btn-reset-scales');\n const densityChips = document.querySelectorAll('.density-chip');\n\n const btnEditbarScale = document.getElementById('btn-editbar-scale');\n const btnControlsScale = document.getElementById('btn-controls-scale');\n\n // Presenter, Deck & Print UI Elements\n const stepBadge = document.getElementById('step-badge');\n const btnPresenter = document.getElementById('btn-controls-presenter');\n const btnViewMode = document.getElementById('btn-controls-view');\n const btnPrint = document.getElementById('btn-controls-print');\n const presenterDrawer = document.getElementById('presenter-drawer');\n const btnClosePresenterDrawer = document.getElementById('btn-close-presenter-drawer');\n const btnOpenDualPresenter = document.getElementById('btn-open-dual-presenter');\n const presenterNotesText = document.getElementById('presenter-notes-text');\n const printModal = document.getElementById('print-modal');\n const chkPrintNotes = document.getElementById('chk-print-notes');\n const btnStartPrint = document.getElementById('btn-start-print');\n const btnCancelPrint = document.getElementById('btn-cancel-print');\n\n let isDeckMode = false;\n let presenterWindow = null;\n let timerSeconds = 0;\n let timerInterval = null;\n let isTimerRunning = false;\n\n const SCALE_STORAGE_KEY = 'deck_scale_' + deckKeyPrefix;\n let scaleState = {\n mode: 'unified', // 'unified' | 'independent'\n factor: 1.0,\n headings: 1.0,\n body: 1.0,\n code: 1.0,\n spacing: 1.0\n };\n\n // Restore saved scale state if present\n try {\n const savedScale = localStorage.getItem(SCALE_STORAGE_KEY);\n if (savedScale) {\n const parsed = JSON.parse(savedScale);\n if (parsed && typeof parsed === 'object') {\n scaleState = Object.assign(scaleState, parsed);\n }\n }\n } catch (e) {}\n\n // Auto-scale 1920x1080 canvas to fit window\n function resizeCanvas() {\n if (isDeckMode) return;\n const vw = window.innerWidth || document.documentElement.clientWidth || 1920;\n const vh = window.innerHeight || document.documentElement.clientHeight || 1080;\n if (vw <= 0 || vh <= 0) return;\n const scaleX = vw / 1920;\n const scaleY = vh / 1080;\n const scale = Math.min(scaleX, scaleY);\n canvas.style.transform = 'translate(-50%, -50%) scale(' + scale + ')';\n }\n\n window.addEventListener('resize', resizeCanvas);\n window.addEventListener('load', resizeCanvas);\n document.addEventListener('DOMContentLoaded', resizeCanvas);\n resizeCanvas();\n requestAnimationFrame(resizeCanvas);\n\n function getSlideNotes(slideIndex) {\n if (slideIndex < 0 || slideIndex >= slides.length) return '';\n const slide = slides[slideIndex];\n const rawNotes = slide.getAttribute('data-notes');\n if (!rawNotes) return '';\n try {\n return decodeURIComponent(rawNotes);\n } catch (e) {\n return rawNotes;\n }\n }\n\n function renderTimerText() {\n const mins = String(Math.floor(timerSeconds / 60)).padStart(2, '0');\n const secs = String(timerSeconds % 60).padStart(2, '0');\n const str = mins + ':' + secs;\n const badge = document.getElementById('presenter-timer-text');\n if (badge) badge.textContent = str;\n return str;\n }\n\n function startTimer() {\n if (timerInterval) return;\n isTimerRunning = true;\n timerInterval = setInterval(() => {\n timerSeconds++;\n renderTimerText();\n }, 1000);\n }\n\n function pauseTimer() {\n if (timerInterval) {\n clearInterval(timerInterval);\n timerInterval = null;\n }\n isTimerRunning = false;\n }\n\n function resetTimer() {\n pauseTimer();\n timerSeconds = 0;\n renderTimerText();\n }\n\n // Step-by-Step Reveal (Animation Steps / Build-In)\n function getSlideSteps(slideIndex) {\n if (slideIndex < 0 || slideIndex >= slides.length) return [];\n const slide = slides[slideIndex];\n let stepEls = Array.from(slide.querySelectorAll('[data-step], [data-reveal], [data-click], .step-reveal, .v-click, .step-item'));\n if (stepEls.length === 0) {\n const autoContainers = slide.querySelectorAll('[data-auto-reveal=\"true\"], .auto-reveal, .step-group');\n autoContainers.forEach(container => {\n const children = container.querySelectorAll('li, .card-item, .step-card, .compare-col');\n children.forEach(c => {\n c.classList.add('step-reveal');\n stepEls.push(c);\n });\n });\n }\n return stepEls;\n }\n\n function updateStepBadge() {\n if (!stepBadge) return;\n if (isDeckMode) {\n stepBadge.style.display = 'none';\n return;\n }\n const steps = getSlideSteps(currentSlide);\n if (steps.length === 0) {\n stepBadge.style.display = 'none';\n return;\n }\n const revealedCount = steps.filter(el => el.classList.contains('revealed') || el.classList.contains('visible')).length;\n stepBadge.style.display = 'inline-block';\n stepBadge.textContent = 'Step ' + revealedCount + '/' + steps.length;\n }\n\n function stepForward() {\n if (isEditMode || isDeckMode) {\n nextSlide();\n return;\n }\n const steps = getSlideSteps(currentSlide);\n if (steps.length > 0) {\n const nextUnrevealed = steps.find(el => !el.classList.contains('revealed') && !el.classList.contains('visible'));\n if (nextUnrevealed) {\n nextUnrevealed.classList.add('revealed', 'visible');\n updateStepBadge();\n broadcastDeckState();\n return;\n }\n }\n if (currentSlide < TOTAL_SLIDES - 1) {\n showSlide(currentSlide + 1);\n }\n }\n\n function stepBackward() {\n if (isEditMode || isDeckMode) {\n prevSlide();\n return;\n }\n const steps = getSlideSteps(currentSlide);\n if (steps.length > 0) {\n const revealedList = steps.filter(el => el.classList.contains('revealed') || el.classList.contains('visible'));\n if (revealedList.length > 0) {\n const lastRevealed = revealedList[revealedList.length - 1];\n lastRevealed.classList.remove('revealed', 'visible');\n updateStepBadge();\n broadcastDeckState();\n return;\n }\n }\n if (currentSlide > 0) {\n showSlide(currentSlide - 1);\n const prevSteps = getSlideSteps(currentSlide);\n prevSteps.forEach(s => s.classList.add('revealed', 'visible'));\n updateStepBadge();\n broadcastDeckState();\n }\n }\n\n // Presenter State & Sync\n const SYNC_CHANNEL_NAME = 'deck_sync_' + encodeURIComponent(document.title.trim() || 'default');\n let syncChannel = null;\n try {\n syncChannel = new BroadcastChannel(SYNC_CHANNEL_NAME);\n syncChannel.onmessage = function(e) {\n if (!e.data) return;\n if (e.data.type === 'COMMAND') {\n if (e.data.action === 'NEXT') stepForward();\n else if (e.data.action === 'PREV') stepBackward();\n else if (e.data.action === 'GOTO' && typeof e.data.index === 'number') showSlide(e.data.index);\n else if (e.data.action === 'RESET_TIMER') resetTimer();\n else if (e.data.action === 'TOGGLE_TIMER') {\n if (isTimerRunning) pauseTimer(); else startTimer();\n }\n } else if (e.data.type === 'REQUEST_STATE') {\n broadcastDeckState();\n }\n };\n } catch (err) {}\n\n function broadcastDeckState() {\n const currentNotes = getSlideNotes(currentSlide);\n const nextNotes = getSlideNotes(currentSlide + 1);\n const payload = {\n type: 'STATE_UPDATE',\n currentSlide: currentSlide,\n totalSlides: TOTAL_SLIDES,\n notes: currentNotes,\n nextNotes: nextNotes,\n title: document.title,\n timerSeconds: timerSeconds,\n timerRunning: isTimerRunning\n };\n\n if (syncChannel) {\n try { syncChannel.postMessage(payload); } catch (e) {}\n }\n if (presenterWindow && !presenterWindow.closed) {\n try { presenterWindow.postMessage(payload, '*'); } catch (e) {}\n }\n updatePresenterDrawerUI();\n }\n\n function updatePresenterDrawerUI() {\n if (!presenterNotesText) return;\n const notes = getSlideNotes(currentSlide);\n if (notes && notes.trim()) {\n presenterNotesText.innerHTML = notes.split('\\\\n').join('<br/>');\n } else {\n presenterNotesText.innerHTML = '<span style=\"opacity: 0.5; font-style: italic;\">No speaker notes for Slide ' + (currentSlide + 1) + '.</span>';\n }\n }\n\n function togglePresenterDrawer() {\n if (!presenterDrawer) return;\n const isOpen = presenterDrawer.classList.toggle('open');\n if (isOpen) {\n startTimer();\n updatePresenterDrawerUI();\n }\n }\n\n function openPresenterConsole() {\n startTimer();\n const popupName = 'PresenterConsole_' + encodeURIComponent(document.title.replace(/[^a-zA-Z0-9_]/g, ''));\n const win = window.open('', popupName, 'width=1100,height=720,menubar=no,toolbar=no,location=no,status=no');\n if (!win) {\n togglePresenterDrawer();\n return;\n }\n presenterWindow = win;\n\n const currentNotes = getSlideNotes(currentSlide);\n const curSlideTitle = 'Slide ' + (currentSlide + 1) + ' / ' + TOTAL_SLIDES;\n\n const consoleHtml = [\n '<!DOCTYPE html>',\n '<html>',\n '<head>',\n '<meta charset=\"UTF-8\"><title>Presenter Console — ' + (document.title || 'Slides') + '</title>',\n '<style>',\n '* { box-sizing: border-box; margin: 0; padding: 0; }',\n 'body { background: #0c0d14; color: #f4f4f5; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif; display: flex; flex-direction: column; height: 100vh; overflow: hidden; user-select: none; }',\n '.top-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 24px; background: #141522; border-bottom: 1px solid rgba(255,255,255,0.12); }',\n '.timer-badge { font-family: monospace; font-size: 20px; font-weight: 700; color: #38bdf8; background: rgba(56,189,248,0.15); border: 1px solid rgba(56,189,248,0.3); padding: 4px 14px; border-radius: 8px; display: flex; align-items: center; gap: 8px; }',\n '.grid-container { flex: 1; display: grid; grid-template-columns: 1fr 1fr; gap: 20px; padding: 20px 24px; overflow: hidden; }',\n '.panel-card { background: #181926; border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; display: flex; flex-direction: column; overflow: hidden; }',\n '.card-header { padding: 10px 16px; background: rgba(255,255,255,0.04); border-bottom: 1px solid rgba(255,255,255,0.08); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: #a1a1aa; display: flex; justify-content: space-between; }',\n '.notes-content { flex: 1; padding: 20px; font-size: 19px; line-height: 1.7; overflow-y: auto; color: #f1f5f9; user-select: text; white-space: pre-wrap; }',\n '.preview-box { flex: 1; display: flex; align-items: center; justify-content: center; background: #000; overflow: hidden; padding: 16px; }',\n '.btn { background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.15); color: #fff; padding: 6px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; }',\n '.btn:hover { background: rgba(255,255,255,0.2); }',\n '.btn-nav { font-size: 16px; padding: 10px 24px; border-radius: 8px; }',\n '.bottom-nav { display: flex; align-items: center; justify-content: space-between; padding: 14px 24px; background: #141522; border-top: 1px solid rgba(255,255,255,0.12); }',\n '</style>',\n '</head>',\n '<body>',\n '<div class=\"top-bar\">',\n ' <div style=\"font-weight: 700; font-size: 16px;\">' + (document.title || 'Slide Deck') + '</div>',\n ' <div style=\"display: flex; align-items: center; gap: 12px;\">',\n ' <div class=\"timer-badge\">⏱ <span id=\"timer-val\">00:00</span></div>',\n ' <button class=\"btn\" id=\"btn-toggle-t\">Pause</button>',\n ' <button class=\"btn\" id=\"btn-reset-t\">Reset</button>',\n ' </div>',\n '</div>',\n '<div class=\"grid-container\">',\n ' <div class=\"panel-card\">',\n ' <div class=\"card-header\"><span>CURRENT SLIDE</span><span id=\"slide-num\">' + curSlideTitle + '</span></div>',\n ' <div class=\"preview-box\"><div style=\"font-size: 22px; color: #94a3b8; text-align: center;\">Active Slide On Screen<br/><span style=\"font-size: 14px; color: #38bdf8;\">(Broadcasting Synced)</span></div></div>',\n ' <div class=\"card-header\" style=\"border-top: 1px solid rgba(255,255,255,0.08);\"><span>NEXT SLIDE PREVIEW</span></div>',\n ' <div style=\"padding: 12px 16px; font-size: 14px; color: #94a3b8; background: rgba(0,0,0,0.3); min-height: 80px;\" id=\"next-preview-text\">Upcoming: Slide ' + (currentSlide + 2) + '</div>',\n ' </div>',\n ' <div class=\"panel-card\">',\n ' <div class=\"card-header\"><span>SPEAKER NOTES / TALK TRACK</span><div><button class=\"btn\" id=\"font-dn\" style=\"padding: 2px 8px;\">A-</button> <button class=\"btn\" id=\"font-up\" style=\"padding: 2px 8px;\">A+</button></div></div>',\n ' <div class=\"notes-content\" id=\"speaker-notes\">' + (currentNotes ? currentNotes : '<span style=\"opacity: 0.4;\">No speaker notes for this slide.</span>') + '</div>',\n ' </div>',\n '</div>',\n '<div class=\"bottom-nav\">',\n ' <button class=\"btn btn-nav\" id=\"btn-prev-p\">‹ Previous (←)</button>',\n ' <span style=\"font-size: 14px; color: #a1a1aa;\">Use Arrow Keys or Space to advance</span>',\n ' <button class=\"btn btn-nav\" id=\"btn-next-p\" style=\"background: #0284c7; border-color: #0284c7;\">Next (→ / Space) ›</button>',\n '</div>',\n '<script>',\n ' const bc = new BroadcastChannel(\"' + SYNC_CHANNEL_NAME + '\");',\n ' let curSecs = ' + timerSeconds + ';',\n ' function sendCmd(action, idx) { bc.postMessage({ type: \"COMMAND\", action: action, index: idx }); }',\n ' document.getElementById(\"btn-prev-p\").onclick = () => sendCmd(\"PREV\");',\n ' document.getElementById(\"btn-next-p\").onclick = () => sendCmd(\"NEXT\");',\n ' document.getElementById(\"btn-reset-t\").onclick = () => sendCmd(\"RESET_TIMER\");',\n ' document.getElementById(\"btn-toggle-t\").onclick = () => sendCmd(\"TOGGLE_TIMER\");',\n ' let curFontSize = 19;',\n ' document.getElementById(\"font-up\").onclick = () => { curFontSize += 2; document.getElementById(\"speaker-notes\").style.fontSize = curFontSize + \"px\"; };',\n ' document.getElementById(\"font-dn\").onclick = () => { curFontSize = Math.max(12, curFontSize - 2); document.getElementById(\"speaker-notes\").style.fontSize = curFontSize + \"px\"; };',\n ' window.onkeydown = (e) => {',\n ' if ([\"ArrowRight\", \"Space\", \"PageDown\"].includes(e.code)) { e.preventDefault(); sendCmd(\"NEXT\"); }',\n ' else if ([\"ArrowLeft\", \"PageUp\"].includes(e.code)) { e.preventDefault(); sendCmd(\"PREV\"); }',\n ' };',\n ' bc.onmessage = (e) => {',\n ' if (!e.data || e.data.type !== \"STATE_UPDATE\") return;',\n ' document.getElementById(\"slide-num\").textContent = \"Slide \" + (e.data.currentSlide + 1) + \" / \" + e.data.totalSlides;',\n ' document.getElementById(\"speaker-notes\").textContent = e.data.notes || \"No speaker notes for this slide.\";',\n ' document.getElementById(\"next-preview-text\").textContent = e.data.nextNotes ? \"Next Notes: \" + e.data.nextNotes : \"Next: Slide \" + (e.data.currentSlide + 2);',\n ' curSecs = e.data.timerSeconds || 0;',\n ' const m = String(Math.floor(curSecs / 60)).padStart(2, \"0\");',\n ' const s = String(curSecs % 60).padStart(2, \"0\");',\n ' document.getElementById(\"timer-val\").textContent = m + \":\" + s;',\n ' document.getElementById(\"btn-toggle-t\").textContent = e.data.timerRunning ? \"Pause\" : \"Start\";',\n ' };',\n ' bc.postMessage({ type: \"REQUEST_STATE\" });',\n '<' + '/script>',\n '</body>',\n '</html>'\n ].join('\\\\n');\n\n win.document.open();\n win.document.write(consoleHtml);\n win.document.close();\n }\n\n // Deck Mode & Print Engine\n function ensureDeckNotesCards() {\n slides.forEach((slide, idx) => {\n const notes = getSlideNotes(idx);\n let existingCard = slide.parentElement.querySelector('.deck-notes-card[data-for-slide=\"' + idx + '\"]');\n if (!existingCard && notes) {\n const card = document.createElement('div');\n card.className = 'deck-notes-card';\n card.setAttribute('data-for-slide', String(idx));\n card.innerHTML = '<div class=\"deck-notes-card-header\"><span>📝</span><span>Presenter Notes (Slide ' + (idx + 1) + ')</span></div><div>' + notes.split('\\\\n').join('<br/>') + '</div>';\n slide.after(card);\n }\n });\n }\n\n function toggleDeckMode(force) {\n isDeckMode = typeof force === 'boolean' ? force : !isDeckMode;\n document.body.classList.toggle('mode-deck', isDeckMode);\n if (isDeckMode) {\n ensureDeckNotesCards();\n document.querySelectorAll('.step-reveal, [data-step], [data-reveal], [data-click], .v-click').forEach(el => {\n el.classList.add('revealed', 'visible');\n });\n } else {\n resizeCanvas();\n }\n updateStepBadge();\n }\n\n function openPrintModal() {\n if (printModal) printModal.classList.add('open');\n }\n\n function closePrintModal() {\n if (printModal) printModal.classList.remove('open');\n }\n\n function executePrint() {\n closePrintModal();\n const withNotes = chkPrintNotes ? chkPrintNotes.checked : false;\n document.body.classList.toggle('print-with-notes', withNotes);\n ensureDeckNotesCards();\n document.querySelectorAll('.step-reveal, [data-step], [data-reveal], [data-click], .v-click').forEach(el => {\n el.classList.add('revealed', 'visible');\n });\n setTimeout(() => {\n window.print();\n }, 100);\n }\n\n // Show slide by index\n function showSlide(index) {\n if (index < 0) index = 0;\n if (index >= TOTAL_SLIDES) index = TOTAL_SLIDES - 1;\n currentSlide = index;\n\n slides.forEach((s, idx) => {\n if (idx === currentSlide) {\n s.classList.add('active');\n } else {\n s.classList.remove('active');\n }\n });\n\n // Reset step state for newly shown slide\n const steps = getSlideSteps(currentSlide);\n steps.forEach(s => s.classList.remove('revealed', 'visible'));\n updateStepBadge();\n updatePresenterDrawerUI();\n broadcastDeckState();\n\n // Update progress bar\n const pct = TOTAL_SLIDES > 1 ? ((currentSlide) / (TOTAL_SLIDES - 1)) * 100 : 100;\n if (progressBar) progressBar.style.width = pct + '%';\n\n // Update counter\n if (counter) {\n const curStr = String(currentSlide + 1).padStart(2, '0');\n const totStr = String(TOTAL_SLIDES).padStart(2, '0');\n counter.textContent = curStr + ' / ' + totStr;\n }\n\n // Send postMessage to parent window if embedded in iframe\n if (window.parent && window.parent !== window) {\n window.parent.postMessage({\n type: 'PRESENTATION_SLIDE_CHANGE',\n currentIndex: currentSlide,\n totalSlides: TOTAL_SLIDES\n }, '*');\n }\n }\n\n function nextSlide() {\n showSlide(currentSlide + 1);\n }\n\n function prevSlide() {\n showSlide(currentSlide - 1);\n }\n\n function toggleFullscreen() {\n if (!document.fullscreenElement) {\n document.documentElement.requestFullscreen().catch(() => {});\n } else {\n document.exitFullscreen().catch(() => {});\n }\n }\n\n // ─── Scale Architecture Controller (Unified vs Independent) ───\n function applyScales() {\n const root = document.documentElement;\n root.style.setProperty('--scale-mode', scaleState.mode);\n root.style.setProperty('--scale-factor', scaleState.factor);\n root.style.setProperty('--scale-headings', scaleState.headings);\n root.style.setProperty('--scale-body', scaleState.body);\n root.style.setProperty('--scale-code', scaleState.code);\n root.style.setProperty('--scale-spacing', scaleState.spacing);\n\n const isUnified = scaleState.mode === 'unified';\n const effHeadings = isUnified ? scaleState.factor : scaleState.headings;\n const effBody = isUnified ? scaleState.factor : scaleState.body;\n const effCode = isUnified ? scaleState.factor : scaleState.code;\n const effSpacing = isUnified ? scaleState.factor : scaleState.spacing;\n\n root.style.setProperty('--scale-headings-eff', effHeadings);\n root.style.setProperty('--scale-body-eff', effBody);\n root.style.setProperty('--scale-code-eff', effCode);\n root.style.setProperty('--scale-spacing-eff', effSpacing);\n\n // Synchronize UI widgets\n if (inputScaleFactor) inputScaleFactor.value = Math.round(scaleState.factor * 100);\n if (badgeScaleFactor) badgeScaleFactor.textContent = Math.round(scaleState.factor * 100) + '%';\n\n if (inputScaleHeadings) inputScaleHeadings.value = Math.round(scaleState.headings * 100);\n if (badgeScaleHeadings) badgeScaleHeadings.textContent = Math.round(scaleState.headings * 100) + '%';\n\n if (inputScaleBody) inputScaleBody.value = Math.round(scaleState.body * 100);\n if (badgeScaleBody) badgeScaleBody.textContent = Math.round(scaleState.body * 100) + '%';\n\n if (inputScaleCode) inputScaleCode.value = Math.round(scaleState.code * 100);\n if (badgeScaleCode) badgeScaleCode.textContent = Math.round(scaleState.code * 100) + '%';\n\n if (inputScaleSpacing) inputScaleSpacing.value = Math.round(scaleState.spacing * 100);\n if (badgeScaleSpacing) badgeScaleSpacing.textContent = Math.round(scaleState.spacing * 100) + '%';\n\n // Update density chips\n densityChips.forEach(chip => {\n const s = parseInt(chip.getAttribute('data-scale'), 10);\n chip.classList.toggle('active', isUnified && Math.round(scaleState.factor * 100) === s);\n });\n\n // Save to localStorage\n try {\n localStorage.setItem(SCALE_STORAGE_KEY, JSON.stringify(scaleState));\n } catch (e) {}\n\n // Notify parent React app if embedded\n if (window.parent && window.parent !== window) {\n window.parent.postMessage({\n type: 'SLIDE_SCALE_CHANGED',\n scaleState: Object.assign({}, scaleState),\n effective: {\n headings: effHeadings,\n body: effBody,\n code: effCode,\n spacing: effSpacing\n }\n }, '*');\n }\n }\n\n function setScaleMode(mode) {\n scaleState.mode = mode;\n if (tabModeUnified && tabModeIndependent) {\n tabModeUnified.classList.toggle('active', mode === 'unified');\n tabModeIndependent.classList.toggle('active', mode === 'independent');\n }\n if (scaleUnifiedContent && scaleIndependentContent) {\n scaleUnifiedContent.style.display = mode === 'unified' ? 'block' : 'none';\n scaleIndependentContent.style.display = mode === 'independent' ? 'block' : 'none';\n }\n applyScales();\n }\n\n function toggleScalePanel(show) {\n if (!scalePanel) return;\n const currentOpen = scalePanel.style.display !== 'none';\n const willOpen = show !== undefined ? show : !currentOpen;\n scalePanel.style.display = willOpen ? 'block' : 'none';\n if (willOpen) {\n setScaleMode(scaleState.mode);\n }\n }\n\n // ─── Scale Panel Event Listeners ───\n if (tabModeUnified) tabModeUnified.addEventListener('click', () => setScaleMode('unified'));\n if (tabModeIndependent) tabModeIndependent.addEventListener('click', () => setScaleMode('independent'));\n if (btnScalePanelClose) btnScalePanelClose.addEventListener('click', () => toggleScalePanel(false));\n\n if (inputScaleFactor) {\n inputScaleFactor.addEventListener('input', (e) => {\n scaleState.factor = parseFloat(e.target.value) / 100;\n applyScales();\n });\n }\n if (inputScaleHeadings) {\n inputScaleHeadings.addEventListener('input', (e) => {\n scaleState.headings = parseFloat(e.target.value) / 100;\n applyScales();\n });\n }\n if (inputScaleBody) {\n inputScaleBody.addEventListener('input', (e) => {\n scaleState.body = parseFloat(e.target.value) / 100;\n applyScales();\n });\n }\n if (inputScaleCode) {\n inputScaleCode.addEventListener('input', (e) => {\n scaleState.code = parseFloat(e.target.value) / 100;\n applyScales();\n });\n }\n if (inputScaleSpacing) {\n inputScaleSpacing.addEventListener('input', (e) => {\n scaleState.spacing = parseFloat(e.target.value) / 100;\n applyScales();\n });\n }\n\n densityChips.forEach(chip => {\n chip.addEventListener('click', () => {\n const val = parseInt(chip.getAttribute('data-scale'), 10) / 100;\n scaleState.factor = val;\n setScaleMode('unified');\n });\n });\n\n if (btnResetScales) {\n btnResetScales.addEventListener('click', () => {\n scaleState.factor = 1.0;\n scaleState.headings = 1.0;\n scaleState.body = 1.0;\n scaleState.code = 1.0;\n scaleState.spacing = 1.0;\n applyScales();\n });\n }\n\n if (btnEditbarScale) btnEditbarScale.addEventListener('click', () => toggleScalePanel());\n if (btnControlsScale) btnControlsScale.addEventListener('click', () => toggleScalePanel());\n\n // ─── Level 1 Inline Editing Controller ──────────────────────────────\n function toggleEditMode(force) {\n isEditMode = force !== undefined ? force : !isEditMode;\n\n document.body.classList.toggle('edit-mode-active', isEditMode);\n editToggleBtn.classList.toggle('active', isEditMode);\n editBar.style.display = isEditMode ? 'flex' : 'none';\n\n const editableSelectors = 'h1, h2, h3, h4, p, li, span, pre code, .opt-badge';\n const targets = canvas.querySelectorAll(editableSelectors);\n\n targets.forEach(el => {\n if (isEditMode) {\n el.setAttribute('contenteditable', 'true');\n el.setAttribute('spellcheck', 'false');\n } else {\n el.removeAttribute('contenteditable');\n }\n });\n\n if (window.parent && window.parent !== window) {\n window.parent.postMessage({\n type: 'SLIDE_EDIT_MODE_CHANGED',\n isEditMode: isEditMode\n }, '*');\n }\n }\n\n // Hotzone hover with 400ms delay timeout (frontend-slides standard)\n let hideHotzoneTimeout = null;\n if (hotzone && editToggleBtn) {\n hotzone.addEventListener('mouseenter', () => {\n clearTimeout(hideHotzoneTimeout);\n editToggleBtn.classList.add('show');\n });\n hotzone.addEventListener('mouseleave', () => {\n hideHotzoneTimeout = setTimeout(() => {\n if (!isEditMode) editToggleBtn.classList.remove('show');\n }, 400);\n });\n editToggleBtn.addEventListener('mouseenter', () => {\n clearTimeout(hideHotzoneTimeout);\n });\n editToggleBtn.addEventListener('mouseleave', () => {\n hideHotzoneTimeout = setTimeout(() => {\n if (!isEditMode) editToggleBtn.classList.remove('show');\n }, 400);\n });\n hotzone.addEventListener('click', () => toggleEditMode());\n editToggleBtn.addEventListener('click', () => toggleEditMode());\n }\n\n // Format actions\n if (btnBold) btnBold.addEventListener('click', () => document.execCommand('bold'));\n if (btnItalic) btnItalic.addEventListener('click', () => document.execCommand('italic'));\n if (btnUnderline) btnUnderline.addEventListener('click', () => document.execCommand('underline'));\n if (btnDone) btnDone.addEventListener('click', () => toggleEditMode(false));\n\n // Reset action\n if (btnReset) {\n btnReset.addEventListener('click', () => {\n if (confirm('Are you sure you want to reset all edits back to original?')) {\n canvas.innerHTML = originalCanvasHtml;\n try { localStorage.removeItem(STORAGE_KEY); } catch (e) {}\n showSlide(currentSlide);\n if (isEditMode) toggleEditMode(true);\n }\n });\n }\n\n // Auto-save to LocalStorage on edit\n let saveTimer = null;\n canvas.addEventListener('input', () => {\n if (!isEditMode) return;\n clearTimeout(saveTimer);\n saveTimer = setTimeout(() => {\n try {\n localStorage.setItem(STORAGE_KEY, canvas.innerHTML);\n } catch (e) {}\n }, 500);\n });\n\n // Restore from localStorage if present\n try {\n const saved = localStorage.getItem(STORAGE_KEY);\n if (saved && saved.trim()) {\n canvas.innerHTML = saved;\n }\n } catch (e) {}\n\n // Save & Clean HTML Export\n function exportAndSaveHtml() {\n const wasEditing = isEditMode;\n if (wasEditing) toggleEditMode(false);\n if (scalePanel) scalePanel.style.display = 'none';\n\n // Take snapshot of full HTML\n let cleanHtml = '<!DOCTYPE html>' + '\\\\n' + document.documentElement.outerHTML;\n\n // Clean any temporary runtime inline styles or attributes\n cleanHtml = cleanHtml\n .replace(/contenteditable=\"true\"/g, '')\n .replace(/spellcheck=\"false\"/g, '')\n .replace(/edit-mode-active/g, '')\n .replace(/class=\"edit-toggle[^\"]*\"/g, 'class=\"edit-toggle\"');\n\n // Embed current scale settings into :root style definition so exported HTML is permanently styled with chosen scales\n const scaleVarsReplacement = [\n '--scale-mode: ' + scaleState.mode + ';',\n ' --scale-factor: ' + scaleState.factor + ';',\n ' --scale-headings: ' + scaleState.headings + ';',\n ' --scale-body: ' + scaleState.body + ';',\n ' --scale-code: ' + scaleState.code + ';',\n ' --scale-spacing: ' + scaleState.spacing + ';',\n ' --scale-headings-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.headings) + ';',\n ' --scale-body-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.body) + ';',\n ' --scale-code-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.code) + ';',\n ' --scale-spacing-eff: ' + (scaleState.mode === 'unified' ? scaleState.factor : scaleState.spacing) + ';'\n ].join('\\\\n');\n\n cleanHtml = cleanHtml.replace(/--scale-mode:\\\\s*[^;]+;[\\\\s\\\\S]*?--scale-spacing-eff:\\\\s*[^;]+;/, scaleVarsReplacement);\n\n // Create Blob and trigger download\n const blob = new Blob([cleanHtml], { type: 'text/html;charset=utf-8' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n const filename = (document.title.replace(/[^a-zA-Z0-9_-]/g, '_').toLowerCase() || 'presentation') + '.html';\n a.href = url;\n a.download = filename;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n\n // Notify parent React frame if embedded\n if (window.parent && window.parent !== window) {\n window.parent.postMessage({\n type: 'SLIDE_HTML_SAVED',\n html: cleanHtml,\n filename: filename\n }, '*');\n }\n\n if (wasEditing) toggleEditMode(true);\n }\n\n if (btnSave) btnSave.addEventListener('click', exportAndSaveHtml);\n\n // Keyboard navigation & Shortcuts\n window.addEventListener('keydown', function(e) {\n // Guard: If typing inside contenteditable, allow normal cursor movement and typing\n if (e.target.isContentEditable || e.target.getAttribute('contenteditable') === 'true') {\n if (e.key === 'Escape') {\n e.target.blur();\n }\n return;\n }\n\n // Shortcut: E key toggles edit mode\n if (e.key === 'e' || e.key === 'E') {\n e.preventDefault();\n toggleEditMode();\n return;\n }\n\n // Shortcut: Cmd+S / Ctrl+S saves HTML\n if ((e.metaKey || e.ctrlKey) && (e.key === 's' || e.key === 'S')) {\n e.preventDefault();\n exportAndSaveHtml();\n return;\n }\n\n // Shortcut: Cmd+P / Ctrl+P opens Print & PDF dialog\n if ((e.metaKey || e.ctrlKey) && (e.key === 'p' || e.key === 'P')) {\n e.preventDefault();\n openPrintModal();\n return;\n }\n\n // Shortcut: P toggles Presenter Console / Drawer\n if (e.key === 'p' || e.key === 'P') {\n e.preventDefault();\n togglePresenterDrawer();\n return;\n }\n\n // Shortcut: D toggles Deck Mode (continuous scroll)\n if (e.key === 'd' || e.key === 'D') {\n e.preventDefault();\n toggleDeckMode();\n return;\n }\n\n if (['ArrowRight', 'ArrowDown', 'Space', 'PageDown'].includes(e.code)) {\n e.preventDefault();\n stepForward();\n } else if (['ArrowLeft', 'ArrowUp', 'PageUp'].includes(e.code)) {\n e.preventDefault();\n stepBackward();\n } else if (e.code === 'KeyF') {\n e.preventDefault();\n toggleFullscreen();\n } else if (e.code === 'Home') {\n e.preventDefault();\n showSlide(0);\n } else if (e.code === 'End') {\n e.preventDefault();\n showSlide(TOTAL_SLIDES - 1);\n }\n });\n\n // Canvas click to advance step / slide in Presentation mode\n document.getElementById('viewport').addEventListener('click', function(e) {\n if (isEditMode || isDeckMode) return;\n if (e.target.closest('#controls, #edit-bar, #scale-panel, #presenter-drawer, #print-modal, .edit-toggle, .quiz-option, button, a, input, select')) return;\n stepForward();\n });\n\n // Quiz interactivity: click option to toggle selected state\n document.addEventListener('click', function(e) {\n if (isEditMode) return; // In edit mode, let user click to edit text instead of quiz logic\n const option = e.target.closest('.quiz-option');\n if (option) {\n const parentGrid = option.parentElement;\n if (parentGrid) {\n parentGrid.querySelectorAll('.quiz-option').forEach(el => el.classList.remove('selected'));\n }\n option.classList.add('selected');\n\n const currentSlideEl = option.closest('.slide-page');\n if (currentSlideEl) {\n const exp = currentSlideEl.querySelector('.quiz-explanation');\n if (exp) {\n exp.style.opacity = '1';\n exp.style.filter = 'none';\n }\n }\n }\n });\n\n // Controls click\n document.getElementById('btn-next').addEventListener('click', stepForward);\n document.getElementById('btn-prev').addEventListener('click', stepBackward);\n document.getElementById('btn-fullscreen').addEventListener('click', toggleFullscreen);\n\n if (btnPresenter) btnPresenter.addEventListener('click', togglePresenterDrawer);\n if (btnViewMode) btnViewMode.addEventListener('click', () => toggleDeckMode());\n if (btnPrint) btnPrint.addEventListener('click', openPrintModal);\n if (btnClosePresenterDrawer) btnClosePresenterDrawer.addEventListener('click', togglePresenterDrawer);\n if (btnOpenDualPresenter) btnOpenDualPresenter.addEventListener('click', openPresenterConsole);\n if (btnStartPrint) btnStartPrint.addEventListener('click', executePrint);\n if (btnCancelPrint) btnCancelPrint.addEventListener('click', closePrintModal);\n if (printModal) {\n printModal.addEventListener('click', function(e) {\n if (e.target === printModal) closePrintModal();\n });\n }\n\n // Listen for messages from parent container\n window.addEventListener('message', function(e) {\n if (!e.data || typeof e.data !== 'object') return;\n if (e.data.type === 'GOTO_SLIDE' && typeof e.data.index === 'number') {\n showSlide(e.data.index);\n } else if (e.data.type === 'NEXT_SLIDE' || e.data.type === 'STEP_FORWARD') {\n stepForward();\n } else if (e.data.type === 'PREV_SLIDE' || e.data.type === 'STEP_BACKWARD') {\n stepBackward();\n } else if (e.data.type === 'TOGGLE_EDIT_MODE') {\n toggleEditMode();\n } else if (e.data.type === 'EXPORT_HTML') {\n exportAndSaveHtml();\n } else if (e.data.type === 'TOGGLE_PRESENTER') {\n togglePresenterDrawer();\n } else if (e.data.type === 'OPEN_PRESENTER_CONSOLE') {\n openPresenterConsole();\n } else if (e.data.type === 'TOGGLE_DECK_MODE') {\n toggleDeckMode();\n } else if (e.data.type === 'PRINT_DECK') {\n executePrint();\n } else if (e.data.type === 'SET_SCALE') {\n if (e.data.mode) setScaleMode(e.data.mode);\n if (typeof e.data.factor === 'number') scaleState.factor = e.data.factor;\n if (typeof e.data.headings === 'number') scaleState.headings = e.data.headings;\n if (typeof e.data.body === 'number') scaleState.body = e.data.body;\n if (typeof e.data.code === 'number') scaleState.code = e.data.code;\n if (typeof e.data.spacing === 'number') scaleState.spacing = e.data.spacing;\n applyScales();\n } else if (e.data.type === 'TOGGLE_SCALE_PANEL') {\n toggleScalePanel();\n } else if (e.data.type === 'RESIZE') {\n resizeCanvas();\n }\n });\n\n // Initial setup\n applyScales();\n setScaleMode(scaleState.mode);\n showSlide(0);\n })();\n </script>\n</body>\n</html>`;\n}\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — HTML Slide Deck Compiler\n// Compiles structured slide slot data into a single self-contained HTML deck\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport type {\n HtmlDeckData,\n HtmlCompileOptions,\n CompiledHtmlDeckResult,\n} from './types.js';\nimport { resolveHtmlTheme } from './themes.js';\nimport { HTML_SLIDE_PRESETS } from './presets.js';\nimport { generateHtmlShell } from './shell.js';\n\nexport function compileHtmlDeck(\n deckData: HtmlDeckData,\n options?: HtmlCompileOptions\n): CompiledHtmlDeckResult {\n const theme = options?.themeOverride || resolveHtmlTheme(deckData.theme);\n const slides = deckData.slides || [];\n const slideCount = Math.max(slides.length, 1);\n\n const renderedSlides = slides.map((slide, index) => {\n const preset = HTML_SLIDE_PRESETS[slide.layoutId] || HTML_SLIDE_PRESETS['hero-cover'];\n const innerHtml = preset.template(slide.slots || {}, theme);\n const notesAttr = slide.notes ? ` data-notes=\"${encodeURIComponent(slide.notes)}\"` : '';\n const customClass = slide.customClass ? ` ${slide.customClass}` : '';\n\n return `\n <!-- Slide ${index + 1}: ${preset.name} -->\n <section class=\"slide-page${customClass}\" data-index=\"${index}\" data-layout=\"${preset.id}\"${notesAttr}>\n ${innerHtml}\n </section>\n `;\n });\n\n const slidesHtml = renderedSlides.join('\\n');\n\n const fullHtml = generateHtmlShell({\n title: deckData.title || 'Presentation',\n theme,\n slidesHtml,\n slideCount,\n customHeadTags: options?.customHeadTags,\n deckId: (deckData as any)?.id || (options as any)?.deckId,\n });\n\n return {\n html: fullHtml,\n slideCount,\n theme,\n title: deckData.title,\n };\n}\n"]}