playwright-director 0.2.0

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.
Files changed (122) hide show
  1. package/README.md +860 -0
  2. package/dist/Tutorial.d.ts +108 -0
  3. package/dist/Tutorial.d.ts.map +1 -0
  4. package/dist/Tutorial.js +767 -0
  5. package/dist/Tutorial.js.map +1 -0
  6. package/dist/bin/export-transcript.d.ts +3 -0
  7. package/dist/bin/export-transcript.d.ts.map +1 -0
  8. package/dist/bin/export-transcript.js +111 -0
  9. package/dist/bin/export-transcript.js.map +1 -0
  10. package/dist/cursor.d.ts +24 -0
  11. package/dist/cursor.d.ts.map +1 -0
  12. package/dist/cursor.js +96 -0
  13. package/dist/cursor.js.map +1 -0
  14. package/dist/index.d.ts +16 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +12 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/init.d.ts +3 -0
  19. package/dist/init.d.ts.map +1 -0
  20. package/dist/init.js +183 -0
  21. package/dist/init.js.map +1 -0
  22. package/dist/merge.d.ts +26 -0
  23. package/dist/merge.d.ts.map +1 -0
  24. package/dist/merge.js +65 -0
  25. package/dist/merge.js.map +1 -0
  26. package/dist/music.d.ts +29 -0
  27. package/dist/music.d.ts.map +1 -0
  28. package/dist/music.js +107 -0
  29. package/dist/music.js.map +1 -0
  30. package/dist/overlay-html.d.ts +44 -0
  31. package/dist/overlay-html.d.ts.map +1 -0
  32. package/dist/overlay-html.js +150 -0
  33. package/dist/overlay-html.js.map +1 -0
  34. package/dist/overlay.d.ts +39 -0
  35. package/dist/overlay.d.ts.map +1 -0
  36. package/dist/overlay.js +134 -0
  37. package/dist/overlay.js.map +1 -0
  38. package/dist/postinstall.d.ts +3 -0
  39. package/dist/postinstall.d.ts.map +1 -0
  40. package/dist/postinstall.js +38 -0
  41. package/dist/postinstall.js.map +1 -0
  42. package/dist/reporter.d.ts +22 -0
  43. package/dist/reporter.d.ts.map +1 -0
  44. package/dist/reporter.js +166 -0
  45. package/dist/reporter.js.map +1 -0
  46. package/dist/site/build-site.d.ts +2 -0
  47. package/dist/site/build-site.d.ts.map +1 -0
  48. package/dist/site/build-site.js +82 -0
  49. package/dist/site/build-site.js.map +1 -0
  50. package/dist/site/embed.d.ts +48 -0
  51. package/dist/site/embed.d.ts.map +1 -0
  52. package/dist/site/embed.js +45 -0
  53. package/dist/site/embed.js.map +1 -0
  54. package/dist/site/generate-manifest.d.ts +15 -0
  55. package/dist/site/generate-manifest.d.ts.map +1 -0
  56. package/dist/site/generate-manifest.js +106 -0
  57. package/dist/site/generate-manifest.js.map +1 -0
  58. package/dist/site/scaffold.d.ts +3 -0
  59. package/dist/site/scaffold.d.ts.map +1 -0
  60. package/dist/site/scaffold.js +70 -0
  61. package/dist/site/scaffold.js.map +1 -0
  62. package/dist/site/scan-tutorials.d.ts +12 -0
  63. package/dist/site/scan-tutorials.d.ts.map +1 -0
  64. package/dist/site/scan-tutorials.js +54 -0
  65. package/dist/site/scan-tutorials.js.map +1 -0
  66. package/dist/site/types.d.ts +75 -0
  67. package/dist/site/types.d.ts.map +1 -0
  68. package/dist/site/types.js +2 -0
  69. package/dist/site/types.js.map +1 -0
  70. package/dist/skill-stamp.d.ts +21 -0
  71. package/dist/skill-stamp.d.ts.map +1 -0
  72. package/dist/skill-stamp.js +39 -0
  73. package/dist/skill-stamp.js.map +1 -0
  74. package/dist/slugify.d.ts +19 -0
  75. package/dist/slugify.d.ts.map +1 -0
  76. package/dist/slugify.js +29 -0
  77. package/dist/slugify.js.map +1 -0
  78. package/dist/stage-presets.d.ts +51 -0
  79. package/dist/stage-presets.d.ts.map +1 -0
  80. package/dist/stage-presets.js +45 -0
  81. package/dist/stage-presets.js.map +1 -0
  82. package/dist/styles.css +637 -0
  83. package/dist/timeline.d.ts +87 -0
  84. package/dist/timeline.d.ts.map +1 -0
  85. package/dist/timeline.js +108 -0
  86. package/dist/timeline.js.map +1 -0
  87. package/dist/transcript.d.ts +87 -0
  88. package/dist/transcript.d.ts.map +1 -0
  89. package/dist/transcript.js +291 -0
  90. package/dist/transcript.js.map +1 -0
  91. package/dist/tts-provider.d.ts +69 -0
  92. package/dist/tts-provider.d.ts.map +1 -0
  93. package/dist/tts-provider.js +182 -0
  94. package/dist/tts-provider.js.map +1 -0
  95. package/dist/types.d.ts +109 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +2 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/voice-prerender.d.ts +41 -0
  100. package/dist/voice-prerender.d.ts.map +1 -0
  101. package/dist/voice-prerender.js +122 -0
  102. package/dist/voice-prerender.js.map +1 -0
  103. package/dist/voice.d.ts +76 -0
  104. package/dist/voice.d.ts.map +1 -0
  105. package/dist/voice.js +244 -0
  106. package/dist/voice.js.map +1 -0
  107. package/package.json +87 -0
  108. package/skills/tutorialize/SKILL.md +54 -0
  109. package/skills/tutorialize/agent.md +58 -0
  110. package/skills/tutorialize/references/api.md +489 -0
  111. package/skills/tutorialize/references/storytelling.md +193 -0
  112. package/src/styles.css +637 -0
  113. package/templates/site/public/.gitkeep +0 -0
  114. package/templates/site/public/widget.js +273 -0
  115. package/templates/site/src/components/TutorialsHome.astro +141 -0
  116. package/templates/site/src/components/VideoCard.astro +192 -0
  117. package/templates/site/src/components/VideoModal.astro +170 -0
  118. package/templates/site/src/data/.gitkeep +0 -0
  119. package/templates/site/src/layouts/Base.astro +56 -0
  120. package/templates/site/src/pages/[slug].astro +745 -0
  121. package/templates/site/src/pages/index.astro +5 -0
  122. package/templates/site/src/styles/tutorials.css +303 -0
package/src/styles.css ADDED
@@ -0,0 +1,637 @@
1
+ /* Tutorial overlay styles - injected in tutorial mode */
2
+ /* Uses scoped CSS variables for easy customization */
3
+
4
+ :root {
5
+ /* Colors */
6
+ --tutorial-primary: #0066fd;
7
+ --tutorial-primary-light: rgba(59, 130, 246, 0.5);
8
+ --tutorial-primary-lighter: rgba(59, 130, 246, 0.3);
9
+ --tutorial-secondary: #8b5cf6;
10
+ --tutorial-bg-start: #1e293b;
11
+ --tutorial-bg-end: #0f172a;
12
+ --tutorial-border: rgb(231, 234, 239.5);
13
+ --tutorial-text: #000000;
14
+ --tutorial-text-muted: #1b1b1b;
15
+ --tutorial-text-bright: #000000;
16
+ --tutorial-shadow: rgba(0, 0, 0, 0.5);
17
+ --tutorial-cursor-stroke: #1e293b;
18
+
19
+ /* Sizing */
20
+ --tutorial-overlay-width: 320px;
21
+ --tutorial-overlay-top: 20px;
22
+ --tutorial-overlay-offset: 20px;
23
+ --tutorial-border-radius: 12px;
24
+ --tutorial-padding: 20px;
25
+ --tutorial-z-index: 999999;
26
+
27
+ /* Overlay surface — override --tutorial-overlay-bg with an rgba() for transparency */
28
+ --tutorial-overlay-bg: #fff;
29
+ --tutorial-overlay-blur: 12px;
30
+ --tutorial-overlay-shadow: 0 25px 50px -12px var(--tutorial-shadow), 0 0 0 1px rgba(255, 255, 255, 0.05) inset;
31
+ --tutorial-icon-size: 24px;
32
+ --tutorial-context-max-width: 500px;
33
+ --tutorial-scene-inactive-opacity: 0.55;
34
+
35
+ /* Animation */
36
+ --tutorial-animation-duration: 0.3s;
37
+ --tutorial-pulse-duration: 1.5s;
38
+
39
+ /* Multi-scene stage (tab bar + scene panes) */
40
+ --tutorial-stage-bg: #1e293b;
41
+ --tutorial-stage-gap: 4px;
42
+ --tutorial-scene-bg: #ffffff;
43
+ --tutorial-tabbar-padding: 8px 8px 0;
44
+ --tutorial-tab-bg: #334155;
45
+ --tutorial-tab-text: #94a3b8;
46
+ --tutorial-tab-bg-active: #f8fafc;
47
+ --tutorial-tab-text-active: #0f172a;
48
+ --tutorial-tab-dot: #64748b;
49
+ --tutorial-tab-dot-active: #22c55e;
50
+ --tutorial-tab-padding: 10px 20px;
51
+ --tutorial-tab-radius: 10px 10px 0 0;
52
+ --tutorial-tab-size: 15px;
53
+ --tutorial-tab-transition: 250ms;
54
+
55
+ /* Typography */
56
+ --tutorial-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
57
+ --tutorial-title-size: 14px;
58
+ --tutorial-step-title-size: 18px;
59
+ --tutorial-description-size: 14px;
60
+ --tutorial-badge-size: 12px;
61
+
62
+ /* Mobile variant values — the html[data-tutorial-variant='mobile'] block below
63
+ only remaps the base variables to these, so tuning the mobile look from a
64
+ consuming project is a plain `:root { ... }` override. */
65
+ --tutorial-overlay-width-mobile: min(250px, calc(100vw - 2 * var(--tutorial-overlay-offset)));
66
+ --tutorial-overlay-top-mobile: 12px;
67
+ --tutorial-overlay-offset-mobile: 12px;
68
+ --tutorial-padding-mobile: 12px;
69
+ --tutorial-title-size-mobile: 12px;
70
+ --tutorial-step-title-size-mobile: 14px;
71
+ --tutorial-description-size-mobile: 12px;
72
+ --tutorial-badge-size-mobile: 10px;
73
+ --tutorial-icon-size-mobile: 16px;
74
+ --tutorial-overlay-blur-mobile: 6px;
75
+ --tutorial-overlay-shadow-mobile: 0 10px 25px -8px var(--tutorial-shadow);
76
+ --tutorial-context-max-width-mobile: min(420px, 85vw);
77
+ /* Lightened content: icon and step badge hidden — bring them back with
78
+ `:root { --tutorial-icon-display-mobile: inline-flex; }` */
79
+ --tutorial-icon-display-mobile: none;
80
+ --tutorial-badge-display-mobile: none;
81
+ }
82
+
83
+ /* ── Mobile variant (data-tutorial-variant set by the Tutorial class) ──────
84
+ Compact overlay for phone-sized panes: pure variable remaps + two display
85
+ toggles, nothing structural. */
86
+ html[data-tutorial-variant='mobile'] {
87
+ --tutorial-overlay-width: var(--tutorial-overlay-width-mobile);
88
+ --tutorial-overlay-top: var(--tutorial-overlay-top-mobile);
89
+ --tutorial-overlay-offset: var(--tutorial-overlay-offset-mobile);
90
+ --tutorial-padding: var(--tutorial-padding-mobile);
91
+ --tutorial-title-size: var(--tutorial-title-size-mobile);
92
+ --tutorial-step-title-size: var(--tutorial-step-title-size-mobile);
93
+ --tutorial-description-size: var(--tutorial-description-size-mobile);
94
+ --tutorial-badge-size: var(--tutorial-badge-size-mobile);
95
+ --tutorial-icon-size: var(--tutorial-icon-size-mobile);
96
+ --tutorial-overlay-blur: var(--tutorial-overlay-blur-mobile);
97
+ --tutorial-overlay-shadow: var(--tutorial-overlay-shadow-mobile);
98
+ --tutorial-context-max-width: var(--tutorial-context-max-width-mobile);
99
+ }
100
+
101
+ html[data-tutorial-variant='mobile'] .tutorial-icon {
102
+ display: var(--tutorial-icon-display-mobile);
103
+ }
104
+
105
+ html[data-tutorial-variant='mobile'] .tutorial-step-badge {
106
+ display: var(--tutorial-badge-display-mobile);
107
+ }
108
+
109
+ html[data-tutorial-variant='mobile'] .tutorial-header {
110
+ margin-bottom: 8px;
111
+ padding-bottom: 6px;
112
+ }
113
+
114
+ html[data-tutorial-variant='mobile'] .tutorial-progress {
115
+ margin-top: 8px;
116
+ height: 3px;
117
+ }
118
+
119
+ @keyframes tutorial-pulse {
120
+ 0%, 100% {
121
+ box-shadow: 0 0 0 4px var(--tutorial-primary-light);
122
+ }
123
+ 50% {
124
+ box-shadow: 0 0 0 8px var(--tutorial-primary-lighter), 0 0 20px var(--tutorial-primary-light);
125
+ }
126
+ }
127
+
128
+ @keyframes tutorial-fade-in {
129
+ from {
130
+ opacity: 0;
131
+ transform: translateY(-10px);
132
+ }
133
+ to {
134
+ opacity: 1;
135
+ transform: translateY(0);
136
+ }
137
+ }
138
+
139
+ @keyframes tutorial-fade-in-center {
140
+ from {
141
+ opacity: 0;
142
+ transform: translate(-50%, calc(-50% - 10px));
143
+ }
144
+ to {
145
+ opacity: 1;
146
+ transform: translate(-50%, -50%);
147
+ }
148
+ }
149
+
150
+ @keyframes tutorial-fade-in-bottom {
151
+ from {
152
+ opacity: 0;
153
+ transform: translateY(10px);
154
+ }
155
+ to {
156
+ opacity: 1;
157
+ transform: translateY(0);
158
+ }
159
+ }
160
+
161
+ @keyframes cursor-click {
162
+ 0%, 100% {
163
+ transform: translate(-50%, -50%) scale(1);
164
+ }
165
+ 50% {
166
+ transform: translate(-50%, -50%) scale(0.8);
167
+ }
168
+ }
169
+
170
+ .tutorial-overlay {
171
+ position: fixed;
172
+ top: var(--tutorial-overlay-top);
173
+ left: var(--tutorial-overlay-offset);
174
+ width: var(--tutorial-overlay-width);
175
+ background: var(--tutorial-overlay-bg);
176
+ backdrop-filter: blur(var(--tutorial-overlay-blur));
177
+ -webkit-backdrop-filter: blur(var(--tutorial-overlay-blur));
178
+ border: 1px solid rgba(255, 255, 255, 0.1);
179
+ border-radius: var(--tutorial-border-radius);
180
+ padding: var(--tutorial-padding);
181
+ z-index: var(--tutorial-z-index);
182
+ font-family: var(--tutorial-font-family);
183
+ color: var(--tutorial-text);
184
+ box-shadow: var(--tutorial-overlay-shadow);
185
+ animation: tutorial-fade-in var(--tutorial-animation-duration) ease-out;
186
+ /* Never swallow clicks on app elements behind the overlay — the tutorial
187
+ * is read-only and narrating, not interactive. Without this, fixed-position
188
+ * UI that overlaps the overlay (e.g. the top-right scan-fab) becomes
189
+ * un-clickable and tutorial.click() times out. */
190
+ pointer-events: none;
191
+ }
192
+
193
+ .tutorial-overlay-rtl {
194
+ left: auto;
195
+ right: var(--tutorial-overlay-offset);
196
+ direction: rtl;
197
+ }
198
+
199
+ .tutorial-overlay-tr {
200
+ left: auto;
201
+ right: var(--tutorial-overlay-offset);
202
+ }
203
+
204
+ .tutorial-overlay-bl {
205
+ top: auto;
206
+ bottom: var(--tutorial-overlay-top);
207
+ }
208
+
209
+ .tutorial-overlay-br {
210
+ left: auto;
211
+ right: var(--tutorial-overlay-offset);
212
+ top: auto;
213
+ bottom: var(--tutorial-overlay-top);
214
+ }
215
+
216
+ .tutorial-overlay-bl,
217
+ .tutorial-overlay-br {
218
+ animation: tutorial-fade-in-bottom var(--tutorial-animation-duration) ease-out;
219
+ }
220
+
221
+ .tutorial-overlay-context {
222
+ /* Context overlay: centered, larger, more prominent */
223
+ top: 50%;
224
+ left: 50%;
225
+ right: auto;
226
+ transform: translate(-50%, -50%);
227
+ width: auto;
228
+ min-width: var(--tutorial-overlay-width);
229
+ max-width: var(--tutorial-context-max-width);
230
+ text-align: center;
231
+ padding: calc(var(--tutorial-padding) * 1.5);
232
+ background: var(--tutorial-overlay-bg);
233
+ border: 1px solid var(--tutorial-border);
234
+ box-shadow: 0 25px 80px -12px var(--tutorial-shadow), 0 0 40px var(--tutorial-primary-lighter);
235
+ animation: tutorial-fade-in-center var(--tutorial-animation-duration) ease-out;
236
+ }
237
+
238
+ .tutorial-overlay-context .tutorial-header {
239
+ justify-content: center;
240
+ border-bottom: none;
241
+ margin-bottom: 12px;
242
+ padding-bottom: 0;
243
+ }
244
+
245
+ .tutorial-overlay-context .tutorial-icon {
246
+ font-size: 32px;
247
+ }
248
+
249
+ .tutorial-overlay-context .tutorial-title {
250
+ font-size: calc(var(--tutorial-title-size) + 2px);
251
+ color: var(--tutorial-text);
252
+ flex: none;
253
+ }
254
+
255
+ .tutorial-overlay-context .tutorial-step-title {
256
+ font-size: calc(var(--tutorial-step-title-size) + 2px);
257
+ color: var(--tutorial-text-bright);
258
+ }
259
+
260
+ .tutorial-context-text {
261
+ font-size: var(--tutorial-description-size);
262
+ color: var(--tutorial-text-muted);
263
+ margin: 8px 0 0 0;
264
+ line-height: 1.5;
265
+ }
266
+
267
+ /* Context style variations */
268
+ .tutorial-context-goal {
269
+ box-shadow: 0 25px 80px -12px var(--tutorial-shadow), 0 0 40px rgba(59, 130, 246, 0.3);
270
+ }
271
+
272
+ .tutorial-context-clarification {
273
+ box-shadow: 0 25px 80px -12px var(--tutorial-shadow), 0 0 40px rgba(250, 204, 21, 0.2);
274
+ }
275
+
276
+ .tutorial-context-clarification .tutorial-icon {
277
+ filter: drop-shadow(0 0 8px rgba(250, 204, 21, 0.5));
278
+ }
279
+
280
+ .tutorial-context-attention {
281
+ box-shadow: 0 25px 80px -12px var(--tutorial-shadow), 0 0 40px rgba(239, 68, 68, 0.2);
282
+ border-color: rgba(239, 68, 68, 0.3);
283
+ }
284
+
285
+ .tutorial-context-attention .tutorial-icon {
286
+ filter: drop-shadow(0 0 8px rgba(239, 68, 68, 0.5));
287
+ }
288
+
289
+ .tutorial-header {
290
+ display: flex;
291
+ align-items: center;
292
+ gap: 10px;
293
+ margin-bottom: 16px;
294
+ padding-bottom: 12px;
295
+ border-bottom: 1px solid var(--tutorial-border);
296
+ }
297
+
298
+ .tutorial-icon {
299
+ font-size: var(--tutorial-icon-size);
300
+ }
301
+
302
+ .tutorial-title {
303
+ font-size: var(--tutorial-title-size);
304
+ font-weight: 600;
305
+ color: var(--tutorial-text-muted);
306
+ margin: 0;
307
+ flex: 1;
308
+ }
309
+
310
+ .tutorial-step-badge {
311
+ background: var(--tutorial-primary);
312
+ color: white;
313
+ font-size: var(--tutorial-badge-size);
314
+ font-weight: 700;
315
+ padding: 4px 10px;
316
+ border-radius: 20px;
317
+ }
318
+
319
+ .tutorial-step-title {
320
+ font-size: var(--tutorial-step-title-size);
321
+ font-weight: 600;
322
+ color: var(--tutorial-text-bright);
323
+ margin: 0 0 8px 0;
324
+ line-height: 1.3;
325
+ }
326
+
327
+ .tutorial-step-description {
328
+ font-size: var(--tutorial-description-size);
329
+ color: var(--tutorial-text-muted);
330
+ margin: 0;
331
+ line-height: 1.5;
332
+ }
333
+
334
+ .tutorial-progress {
335
+ margin-top: 16px;
336
+ height: 4px;
337
+ background: var(--tutorial-border);
338
+ border-radius: 2px;
339
+ overflow: hidden;
340
+ }
341
+
342
+ .tutorial-progress-bar {
343
+ height: 100%;
344
+ background: linear-gradient(90deg, var(--tutorial-primary), var(--tutorial-secondary));
345
+ border-radius: 2px;
346
+ transition: width var(--tutorial-animation-duration) ease;
347
+ }
348
+
349
+ .tutorial-highlight {
350
+ position: relative;
351
+ z-index: calc(var(--tutorial-z-index) - 1);
352
+ animation: tutorial-pulse var(--tutorial-pulse-duration) ease-in-out infinite;
353
+ border-radius: 4px;
354
+ }
355
+
356
+ .tutorial-cursor {
357
+ position: fixed;
358
+ width: 24px;
359
+ height: 24px;
360
+ pointer-events: none;
361
+ z-index: var(--tutorial-z-index);
362
+ transform: translate(-50%, -50%);
363
+ transition: none;
364
+ }
365
+
366
+ .tutorial-cursor-clicking {
367
+ animation: cursor-click 0.15s ease-out;
368
+ }
369
+
370
+ .tutorial-cursor svg {
371
+ width: 100%;
372
+ height: 100%;
373
+ filter: drop-shadow(2px 2px 2px var(--tutorial-shadow));
374
+ }
375
+
376
+ .tutorial-spotlight {
377
+ position: fixed;
378
+ top: 0;
379
+ left: 0;
380
+ width: 100vw;
381
+ height: 100vh;
382
+ background: var(--tutorial-shadow);
383
+ z-index: calc(var(--tutorial-z-index) - 2);
384
+ pointer-events: none;
385
+ opacity: 0;
386
+ transition: opacity var(--tutorial-animation-duration) ease;
387
+ }
388
+
389
+ .tutorial-spotlight.active {
390
+ opacity: 1;
391
+ }
392
+
393
+ /* Email preview popup - simulates receiving an email */
394
+ .tutorial-email-preview {
395
+ position: fixed;
396
+ top: 50%;
397
+ left: 50%;
398
+ transform: translate(-50%, -50%);
399
+ z-index: calc(var(--tutorial-z-index) + 1);
400
+ font-family: var(--tutorial-font-family);
401
+ animation: tutorial-fade-in-center var(--tutorial-animation-duration) ease-out;
402
+ }
403
+
404
+ .tutorial-email-window {
405
+ width: 900px;
406
+ max-width: 90vw;
407
+ background: #ffffff;
408
+ border-radius: 12px;
409
+ box-shadow: 0 25px 80px -12px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.1);
410
+ overflow: hidden;
411
+ }
412
+
413
+ .tutorial-email-titlebar {
414
+ display: flex;
415
+ align-items: center;
416
+ gap: 8px;
417
+ padding: 12px 16px;
418
+ background: linear-gradient(180deg, #f7f7f7 0%, #e8e8e8 100%);
419
+ border-bottom: 1px solid #d1d1d1;
420
+ }
421
+
422
+ .tutorial-email-dot {
423
+ width: 12px;
424
+ height: 12px;
425
+ border-radius: 50%;
426
+ }
427
+
428
+ .tutorial-email-dot.red { background: #ff5f57; }
429
+ .tutorial-email-dot.yellow { background: #ffbd2e; }
430
+ .tutorial-email-dot.green { background: #28c840; }
431
+
432
+ .tutorial-email-app {
433
+ margin-left: auto;
434
+ font-size: 13px;
435
+ color: #666;
436
+ font-weight: 500;
437
+ }
438
+
439
+ .tutorial-email-header {
440
+ padding: 16px;
441
+ background: #fafafa;
442
+ border-bottom: 1px solid #e5e5e5;
443
+ font-size: 13px;
444
+ color: #333;
445
+ }
446
+
447
+ .tutorial-email-field {
448
+ margin-bottom: 4px;
449
+ }
450
+
451
+ .tutorial-email-field:last-child {
452
+ margin-bottom: 0;
453
+ }
454
+
455
+ .tutorial-email-field strong {
456
+ color: #666;
457
+ font-weight: 500;
458
+ margin-right: 8px;
459
+ }
460
+
461
+ .tutorial-email-body-container {
462
+ background: #fff;
463
+ max-height: 350px;
464
+ overflow: hidden;
465
+ }
466
+
467
+ /* The email body is an isolated iframe — sizing the outer iframe gives the
468
+ * preview a fixed viewport; the inner document scrolls via requestAnimationFrame. */
469
+ .tutorial-email-iframe {
470
+ width: 100%;
471
+ height: 350px;
472
+ border: none;
473
+ display: block;
474
+ background: #fff;
475
+ }
476
+
477
+ .tutorial-email-code {
478
+ background: #fff3cd;
479
+ color: #856404;
480
+ padding: 4px 12px;
481
+ border-radius: 4px;
482
+ font-weight: 700;
483
+ font-size: 18px;
484
+ letter-spacing: 2px;
485
+ display: inline-block;
486
+ margin: 8px 0;
487
+ border: 2px solid #ffc107;
488
+ animation: tutorial-pulse 1.5s ease-in-out infinite;
489
+ }
490
+
491
+ .tutorial-email-preview.tutorial-overlay-rtl .tutorial-email-field strong {
492
+ margin-right: 0;
493
+ margin-left: 8px;
494
+ }
495
+
496
+ /* ── Multi-scene stage ──────────────────────────────────────
497
+ A browser-like tab bar over a row of iframes. Every value is a
498
+ --tutorial-* variable, like the rest of this file: override them in
499
+ `customStyles` to match the product being demonstrated. */
500
+
501
+ .tutorial-stage {
502
+ position: fixed;
503
+ inset: 0;
504
+ display: flex;
505
+ flex-direction: column;
506
+ background: var(--tutorial-stage-bg);
507
+ z-index: 0;
508
+ }
509
+
510
+ .tutorial-tabbar {
511
+ display: flex;
512
+ gap: var(--tutorial-stage-gap);
513
+ padding: var(--tutorial-tabbar-padding);
514
+ flex: 0 0 auto;
515
+ font-family: var(--tutorial-font-family);
516
+ }
517
+
518
+ /* Hide the shared tab bar in split mode — per-scene labels take over */
519
+ .tutorial-stage[data-split='true'] .tutorial-tabbar {
520
+ display: none;
521
+ }
522
+
523
+ .tutorial-tab {
524
+ display: flex;
525
+ align-items: center;
526
+ gap: 8px;
527
+ padding: var(--tutorial-tab-padding);
528
+ border-radius: var(--tutorial-tab-radius);
529
+ background: var(--tutorial-tab-bg);
530
+ color: var(--tutorial-tab-text);
531
+ font-size: var(--tutorial-tab-size);
532
+ font-weight: 500;
533
+ white-space: nowrap;
534
+ transition: background var(--tutorial-tab-transition) ease,
535
+ color var(--tutorial-tab-transition) ease;
536
+ }
537
+
538
+ .tutorial-tab[data-active='true'] {
539
+ background: var(--tutorial-tab-bg-active);
540
+ color: var(--tutorial-tab-text-active);
541
+ font-weight: 600;
542
+ }
543
+
544
+ .tutorial-tab-dot {
545
+ width: 8px;
546
+ height: 8px;
547
+ border-radius: 50%;
548
+ background: var(--tutorial-tab-dot);
549
+ transition: background var(--tutorial-tab-transition) ease;
550
+ }
551
+
552
+ .tutorial-tab[data-active='true'] .tutorial-tab-dot {
553
+ background: var(--tutorial-tab-dot-active);
554
+ }
555
+
556
+ .tutorial-scenes {
557
+ flex: 1 1 auto;
558
+ display: flex;
559
+ gap: 0;
560
+ min-height: 0;
561
+ }
562
+
563
+ .tutorial-stage[data-split='true'] .tutorial-scenes {
564
+ gap: var(--tutorial-stage-gap);
565
+ background: var(--tutorial-stage-bg);
566
+ }
567
+
568
+ .tutorial-scene {
569
+ flex: 1 1 0;
570
+ min-width: 0;
571
+ display: flex;
572
+ flex-direction: column;
573
+ }
574
+
575
+ .tutorial-scene[data-active='false'] {
576
+ display: none;
577
+ }
578
+
579
+ /* Per-scene label: hidden in single mode, visible in split mode */
580
+ .tutorial-scene-label {
581
+ display: none;
582
+ align-items: center;
583
+ justify-content: center;
584
+ gap: 8px;
585
+ padding: 8px 16px;
586
+ background: var(--tutorial-tab-bg-active);
587
+ color: var(--tutorial-tab-text-active);
588
+ font-size: var(--tutorial-tab-size);
589
+ font-weight: 600;
590
+ font-family: var(--tutorial-font-family);
591
+ white-space: nowrap;
592
+ flex: 0 0 auto;
593
+ }
594
+
595
+ .tutorial-stage[data-split='true'] .tutorial-scene-label {
596
+ display: flex;
597
+ }
598
+
599
+ .tutorial-scene-label .tutorial-tab-dot {
600
+ background: var(--tutorial-tab-dot-active);
601
+ }
602
+
603
+ .tutorial-scene iframe {
604
+ flex: 1 1 auto;
605
+ width: 100%;
606
+ height: 100%;
607
+ border: 0;
608
+ background: var(--tutorial-scene-bg);
609
+ }
610
+
611
+ /* ── Pinned split (mobile multi-scene) ──────────────────────
612
+ Every scene stays visible at equal width for the whole tutorial: the tab
613
+ bar never shows, per-scene labels take over, and focus() only dims the
614
+ inactive labels. Set via data-layout="split" by the Tutorial class. */
615
+
616
+ .tutorial-stage[data-layout='split'] .tutorial-tabbar {
617
+ display: none;
618
+ }
619
+
620
+ .tutorial-stage[data-layout='split'] .tutorial-scenes {
621
+ gap: var(--tutorial-stage-gap);
622
+ background: var(--tutorial-stage-bg);
623
+ }
624
+
625
+ .tutorial-stage[data-layout='split'] .tutorial-scene,
626
+ .tutorial-stage[data-layout='split'] .tutorial-scene[data-active='false'] {
627
+ display: flex;
628
+ flex: 1 1 0;
629
+ }
630
+
631
+ .tutorial-stage[data-layout='split'] .tutorial-scene-label {
632
+ display: flex;
633
+ }
634
+
635
+ .tutorial-stage[data-layout='split'] .tutorial-scene[data-active='false'] .tutorial-scene-label {
636
+ opacity: var(--tutorial-scene-inactive-opacity);
637
+ }
File without changes