PageSourceSearch

https://www.hamienet.com/assets/TutorialManager-DmaWaJKT.js

js hamienet.com collected 2026-09-24 19:01:14 UTC 148,914 bytes, 3,371 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
2import { B as BLANK_SOLO_STAFF_HUMDRUM } from "./index--Kd7xwwe.js";
3import { cs as BookOpen, bI as Star, cm as ArrowRight, cy as Trophy, cY as ChevronLeft, bE as ChevronRight, cj as Layers, bF as CircleQuestionMark, bU as Play, a_ as CircleCheck, bZ as Pause, bT as Volume2, bW as VolumeX, bi as Sparkles, du as GripHorizontal } from "./vendor-dVNaLJx_.js";
4import "./vendor-react-three-MDLA5jog.js";
5import "./vendor-i18n-R-bMoYp_.js";
6import "./vendor-audio-DH3w0BzW.js";
7import "./index-D0Bmh-UX.js";
8const SNAPSHOT_CHAPTER_1 = `!!!verovio: breaks encoded
9!!!COM: Robert Schumann
10!!!OTL: Widmung
11!!!ODT: 1840
12!!!OMD: Innig, lebhaft.
13**kern	**dynam	**kern	**kern	**text
14*clefF4	*	*clefG2	*clefG2	*
15*k[b-e-a-d-]	*	*k[b-e-a-d-]	*k[b-e-a-d-]	*
16*M3/2	*M3/2	*M3/2	*M3/2	*
17=1	=1	=1	=1	=1
181.r	.	1.r	1.r	.
19=2	=2	=2	=2	=2
201.r	.	1.r	1.r	.
21=3	=3	=3	=3	=3
221.r	.	1.r	1.r	.
23=4	=4	=4	=4	=4
241.r	.	1.r	1.r	.
25=5	=5	=5	=5	=5
261.r	.	1.r	1.r	.
27=6	=6	=6	=6	=6
281.r	.	1.r	1.r	.
29=7	=7	=7	=7	=7
301.r	.	1.r	1.r	.
31=8	=8	=8	=8	=8
321.r	.	1.r	1.r	.
33=9	=9	=9	=9	=9
341.r	.	1.r	1.r	.
35=10	=10	=10	=10	=10
361.r	.	1.r	1.r	.
37=11	=11	=11	=11	=11
381.r	.	1.r	1.r	.
39=12	=12	=12	=12	=12
401.r	.	1.r	1.r	.
41=13	=13	=13	=13	=13
421.r	.	1.r	1.r	.
43=14	=14	=14	=14	=14
441.r	.	1.r	1.r	.
45=15	=15	=15	=15	=15
461.r	.	1.r	1.r	.
47=16	=16	=16	=16	=16
481.r	.	1.r	1.r	.
49=17	=17	=17	=17	=17
501.r	.	1.r	1.r	.
51=18	=18	=18	=18	=18
521.r	.	1.r	1.r	.
53==	==	==	==	==
54*-	*-	*-	*-	*-`;
55let SNAPSHOT_CHAPTER_8;
56const WIDMUNG_KRN_RAW = `!!!verovio: breaks encoded
57!!!COM: Robert Schumann
58!!!OTL: Widmung
59!!!ODT: 1840
60!!!OMD: Innig, lebhaft.
61**kern	**dynam	**kern	**kern	**text
62*clefF4	*	*clefG2	*clefG2	*
63*k[b-e-a-d-]	*	*k[b-e-a-d-]	*k[b-e-a-d-]	*
64*M3/2	*M3/2	*M3/2	*M3/2	*
65=1	=1	=1	=1	=1
66*^	*	*	*	*
67*	*ped	*	*	*	*
681AAA- 1AA-	(8E-L\\	mf	(8cL/	1.r	.
69.	8A-\\	<	8e-/	.	.
70.	8.c\\	.	8.a-/	.	.
71.	16e-J\\	.	16ccJ/	.	.
72.	8e-L\\	.	8ccL/	.	.
73.	8c\\	.	8a-/	.	.
74*	*Xped	*	*	*	*
75.	8A-\\	[	8e-/	.	.
76*	*ped	*	*	*	*
77.	8E-J)\\	.	8cJ)/	.	.
782AAA-\\ 2AA-\\	(8E-L\\	.	(8cL/	.	.
79.	8A-\\	.	8e-/	.	.
80*	*Xped	*	*	*	*
81.	8E-\\	.	8B-/	.	.
82.	8A-J)\\	.	8e-J)/	.	.
83=2	=2	=2	=2	=2	=
84*	*ped	*	*	*	*
851AAA- 1AA-	(8E-L\\	.	(8cL/	4cc	Du
86.	8A-\\	<	8e-/	.	.
87.	8.c\\	.	8.a-/	8cc	mei-
88.	.	.	.	8cc	ne
89.	16e-J\\	.	16ccJ/	.	.
90.	8e-L\\	.	8ccL/	4.ee-	See-
91.	8c\\	.	8a-/	.	.
92*	*Xped	*	*	*	*
93.	8A-\\	[	8e-/	.	.
94*	*ped	*	*	*	*
95.	8E-J)\\	.	8cJ)/	8a-	le,
962AAA-\\ 2AA-\\	(8E-L\\	.	(8cL/	4a-	du
97.	8A-\\	.	8e-/	.	.
98*	*Xped	*	*	*	*
99.	8E-\\	.	8B-/	4b-	mein
100.	8A-J)\\	.	8e-J)/	.	.
101=3	=3	=3	=3	=3	=
102*	*ped	*	*	*	*
1031AAA- 1AA-	(8E-L\\	.	(8cL/	2cc	Herz,
104.	8A-\\	<	8e-/	.	.
105.	8.c\\	.	8.a-/	.	.
106.	16e-J\\	.	16ccJ/	.	.
107.	8e-L\\	.	8ccL/	2r	.
108.	8c\\	.	8a-/	.	.
109*	*Xped	*	*	*	*
110.	8A-\\	[	8e-/	.	.
111*	*ped	*	*	*	*
112.	8E-J)\\	.	8cJ)/	.	.
1132AAA-\\ 2AA-\\	(8E-L\\	.	(8cL/	4a-	du
114.	8A-\\	.	8e-/	.	.
115*	*Xped	*	*	*	*
116.	8E-\\	.	8c/	8a-	mei-
117.	8cJ)\\	.	8A-J)/	8a-	ne
118=4	=4	=4	=4	=4	=
119*	*ped	*	*	*	*
120.	.	.	.	qgg	.
1211DDD- 1DD-	(8A-L\\	.	(8fL/	2ff[	Wonn’,
122.	8d-\\	.	8a-/	.	.
123.	8.f\\	.	8.dd-/	.	.
124.	16a-J\\	.	16ffJ/	.	.
125.	8a-L\\	.	8ffL/	4ff]	.
126.	8A-\\	.	8f/	.	.
127.	8g\\	.	8ee-/	4ee-	o
128.	8A-J)\\	.	8fJ)/	.	.
129*	*Xped	*	*	*	*
1302r	(8fL\\	.	(8dd-L/	4dd-	du
131.	8A-\\	.	8f/	.	.
132.	8e-\\	.	8cc/	4cc	mein
133.	8A-J)\\	.	8fJ)/	.	.
134!!LO:LB:g=original
135=5	=5	=5	=5	=5	=
1361DDD- 1DD-	(8A-L\\	.	(2b-L/	2b-	Schmerz,
137.	8d-\\	.	.	.	.
138.	8.f-\\	.	.	.	.
139.	16b-J\\	.	.	.	.
140.	8b-L\\	.	2r	2r	.
141.	8g\\	.	.	.	.
142.	8D-\\	.	.	.	.
143.	8AA-J)\\	.	.	.	.
1442DD-\\ 2EE-\\	(8GGL\\	.	4b-^/	4b-^	du
145.	8BB-\\	.	.	.	.
146.	4r	.	8g/	8g	mei-
147.	.	.	8e-J/	8e-	ne
148=6	=6	=6	=6	=6	=
1491CC 1E-	8A-\\	.	1a-L	2a-[	Welt,
150.	8cJ)\\	.	.	.	.
151.	(8.e-L\\	.	.	.	.
152.	16a-\\	.	.	.	.
153.	8a-\\	.	.	4a-]	.
154.	8e-J\\	.	.	.	.
155.	8cL\\	.	.	4a-	in
156.	8A-\\	.	.	.	.
157*	*ped	*	*	*	*
1582BBB-\\	8g\\	.	2dd-/	4.dd-	der
159.	8e-J)\\	.	.	.	.
160.	(8d-L\\	.	.	.	.
161*	*Xped	*	*	*	*
162.	8G\\	.	.	8dd-	ich
163=7	=7	=7	=7	=7	=
164*	*ped	*	*	*	*
1654AAA-\\	8g\\	.	2dd-/	2dd-	le-
166.	8e-J)\\	.	.	.	.
1674r	(8d-L\\	.	.	.	.
168.	8G\\	.	.	.	.
1694AA-\\	8a-\\	.	4ccJ)/	4cc	be,
170.	8e-J\\	.	.	.	.
171*	*Xped	*	*	*	*
1724r	8cL\\	.	4r	4cc	mein
173.	8A-\\	.	.	.	.
1742GG- 2AA-	4c\\	.	(4ee-^L/	4.ee-^	Him-
175.	4r	.	8cc/	.	.
176.	.	.	8a-/	8a-	mel
177=8	=8	=8	=8	=8	=
1781FF 1AA-	8D-J)\\	.	2dd-[J)/	2dd-[	du,
179.	(8FL\\	.	.	.	.
180.	8.A-\\	.	.	.	.
181.	16d-\\	.	.	.	.
182.	8d-J)\\	.	(4dd-L/	4dd-]	.
183.	(8A-L\\	.	.	.	.
184.	8F\\	.	4dd-/	4dd-	da-
185.	8D-\\	.	.	.	.
186*	*ped	*	*	*	*
1872EE-\\	8cJ\\	.	4gg-/	4.gg-	rein
188.	8A-L\\	.	.	.	.
189.	8G-\\	.	4gg-J/	.	.
190*	*Xped	*	*	*	*
191.	8C\\	.	.	8gg-	ich
192!!LO:LB:g=original
193=9	=9	=9	=9	=9	=
194*	*ped	*	*	*	*
1954DD-\\	8cJ)\\	.	2gg-L/	2gg-	schwe-
196.	(8A-L\\	.	.	.	.
1972r	8G-\\	.	.	.	.
198.	8C\\	.	.	.	.
199.	4DJ)\\	.	4ff/	4ff	be,
200*	*Xped	*	*	*	*
2012DD-\\	(4AAL\\	.	4ee-/	4ee-	o
202.	4BB\\	.	4dd-J)/	4dd-	du
2034DD-\\	4D\\	.	(4ccL/	4cc	mein
204=10	=10	=10	=10	=10	=
2051DD-	8BB-J\\	.	2b-[/	2b-	Grab,
206.	8DL\\	.	.	.	.
207.	8.F-\\	.	.	.	.
208.	16G\\	.	.	.	.
209.	8GJ)\\	.	4b-/	4r	.
210.	(8F-L\\	.	.	.	.
211.	8D\\	.	4b-J)/	4b-	in
212.	8BB-\\	.	.	.	.
2132DD-\\	8GGJ)\\	.	(4ccL/	4cc	das
214.	(8BB-L\\	.	.	.	.
215.	8F-\\	.	4dd-/	4dd-	hin-
216.	8G\\	.	.	.	.
217=11	=11	=11	=11	=11	=
2181CC	8AA-J\\	.	2ee-/	4ee-	ab
219.	8E-L\\	.	.	.	.
220.	8.G-\\	.	.	4a-	ich
221.	16A-\\	.	.	.	.
222.	8A-J)\\	.	2a-[J/	2a-[	e-
223.	(8G-L\\	.	.	.	.
224.	8E-\\	.	.	.	.
225.	8AA-\\	.	.	.	.
2264DD-\\	8DJ)\\	.	4a-L/	4a-]	.
227.	(8A-L\\	.	.	.	.
2284BBB-\\	8BB\\	.	4dd-/	4dd-	wig
229.	8D\\	.	.	.	.
230=12	=12	=12	=12	=12	=
2312EE-\\	8AA-J\\	.	2cc/	4cc	mei-
232.	8CL\\	.	.	.	.
233.	8E-\\	.	.	4cc	nen
234.	8A-\\	.	.	.	.
235.	.	.	.	qcc	.
2361EE-	8AA-J)\\	.	2b-[J)/	2b-[	Kum-
237.	(8BB-L\\	.	.	.	.
238.	8.D-\\	.	.	.	.
239.	16E\\	.	.	.	.
240.	8EJ)\\	.	(4b-L/	4b-]	.
241.	(8D-L\\	.	.	.	.
242.	8GG\\	.	4cc/	4cc	mer
243.	8EE\\	.	.	.	.
244=13	=13	=13	=13	=13	=
2451AAA-	8E-J\\	.	1.a-	2a-	gab!
246.	8A-L\\	.	.	.	.
247.	8.C\\	.	.	.	.
248.	16E-\\	.	.	.	.
249.	8E-J)\\	.	.	2r	.
250.	(8CL\\	.	.	.	.
251.	8AA-\\	.	.	.	.
252.	8EE-\\	.	.	.	.
2532EE-	2r	>	.	2r	.
254.	.	[	.	.	.
255!!LO:LB:g=original
256==||	==||	==||	==||	==||	==||
257=14	=14	=14	=14	=14	=14
258*k[f#c#g#d#]	*k[f#c#g#d#]	*	*k[f#c#g#d#]	*k[f#c#g#d#]	*
259*	*ped	*	*	*	*
2601EE	(6EL\\	p	6eJ)/	1g#	Du
261.	6E\\	.	(6eL/	.	.
262.	6EJ)\\	.	6e/	.	.
263.	(6EL\\	.	6eJ)/	.	.
264.	6E\\	.	(6eL/	.	.
265.	6EJ)\\	.	6e/	.	.
266*	*Xped	*	*	*	*
2672EE\\	(6DL\\	.	6eJ)/	4f#	bist
268.	6D\\	.	(6eL/	.	.
269.	.	.	.	4g#	die
270.	6DJ)\\	.	6e/	.	.
271=15	=15	=15	=15	=15	=15
272*	*ped	*	*	*	*
2731EE	(6CL\\	.	6aJ)/	1a	Ruh’,
274.	6C\\	.	(6aL/	.	.
275.	6CJ)\\	.	6a/	.	.
276.	(6CL\\	.	6aJ)/	.	.
277.	6C\\	.	(6aL/	.	.
278.	6CJ)\\	.	6a/	.	.
279*	*Xped	*	*	*	*
2802EE\\	(6BBL\\	.	6gJ)/	2g#	du
281.	6BB\\	.	(6gL/	.	.
282.	6BBJ)\\	.	6g/	.	.
283=16	=16	=16	=16	=16	=16
284*	*ped	*	*	*	*
2851EE	(6AAL\\	.	6fJ)/	1f#[	bist
286.	6AA\\	.	(6fL/	.	.
287.	6AAJ)\\	.	6f/	.	.
288.	(6AAL\\	.	6fJ)/	.	.
289.	6AA\\	.	(6fL/	.	.
290.	6AAJ)\\	.	6f/	.	.
291*	*Xped	*	*	*	*
2922EE\\	(6BBL\\	.	6fJ)/	4f#]	.
293.	6BB\\	.	(6fL/	.	.
294.	.	.	.	4g#	der
295.	6BBJ)\\	.	6f/	.	.
296=17	=17	=17	=17	=17	=17
297*	*ped	*	*	*	*
2981r	(2EL\\	.	6eJ)/	2b	Frie-
299.	.	.	(6eL/	.	.
300.	.	.	6e/	.	.
301.	2r	.	6BJ)/	2e	den,
302.	.	.	(6BL/	.	.
303.	.	.	6B/	.	.
304*	*Xped	*	*	*	*
3052r	2BB\\	.	6BJ)/	4e	du
306.	.	.	(6BL/	.	.
307.	.	.	.	4f#	bist
308.	.	.	6B/	.	.
309=18	=18	=18	=18	=18	=18
3104r	4r	.	4r	4g#	vom
311*v	*v	*	*	*	*
312==	==	==	==	==
313*-	*-	*-	*-	*-
314!!!hamienet: systemIndents=0_350`;
315SNAPSHOT_CHAPTER_8 = WIDMUNG_KRN_RAW;
316const setupChapterSteps = [
317  {
318    id: "setup-welcome",
319    instruction: "Welcome to the Robert Schumann - Widmung transcription tutorial! Click the Setup Wizard card.",
320    mode: "both",
321    action: { type: "click", selector: '[data-testid="start-setup-wizard-card"]' },
322    validation: { type: "element-exists", value: ".setup-wizard-modal" },
323    cursorTarget: { selector: '[data-testid="start-setup-wizard-card"]' },
324    interactionMilestone: {
325      promptText: 'Your turn! Click the "Setup Wizard" card to begin configuring the score.',
326      targetSelector: '[data-testid="start-setup-wizard-card"]',
327      successMessage: "Excellent! The Score Setup Wizard is now open. 👍"
328    },
329    durationMs: 2200
330  },
331  {
332    id: "setup-title",
333    instruction: `Let's configure Widmung's initial metadata. Fill in Title: "Widmung".`,
334    mode: "both",
335    action: { type: "click", selector: '[data-testid="wizard-title-input"]' },
336    cursorTarget: { selector: '[data-testid="wizard-title-input"]' },
337    durationMs: 1800
338  },
339  {
340    id: "setup-composer",
341    instruction: 'Now fill in Composer: "Robert Schumann".',
342    mode: "both",
343    action: { type: "click", selector: '[data-testid="wizard-composer-input"]' },
344    cursorTarget: { selector: '[data-testid="wizard-composer-input"]' },
345    durationMs: 1800
346  },
347  {
348    id: "setup-next-1",
349    instruction: "Click Next to choose the instruments for the score.",
350    mode: "both",
351    action: { type: "click", selector: '[data-testid="wizard-next-btn"]' },
352    cursorTarget: { selector: '[data-testid="wizard-next-btn"]' },
353    durationMs: 1800
354  },
355  {
356    id: "setup-next-2",
357    instruction: "Piano is selected by default. Click Next to set the key and time signatures.",
358    mode: "both",
359    action: { type: "click", selector: '[data-testid="wizard-next-btn"]' },
360    cursorTarget: { selector: '[data-testid="wizard-next-btn"]' },
361    durationMs: 1800
362  },
363  {
364    id: "setup-sig",
365    instruction: "Set the key signature to A-flat Major (4 flats) and the meter to 3/2 time.",
366    mode: "both",
367    action: { type: "click", selector: '[data-testid="wizard-key-Ab"]' },
368    cursorTarget: { selector: '[data-testid="wizard-key-Ab"]' },
369    durationMs: 2500
370  },
371  {
372    id: "setup-generate",
373    instruction: 'Excellent! Click "Finish & Create" to create the blank Grand Staff staves.',
374    mode: "both",
375    action: { type: "wizard-fill", title: "Widmung", composer: "Robert Schumann", keySig: "A-flat Major", timeSig: "3/2", tempo: 120, tempoText: "Innig, lebhaft." },
376    validation: { type: "wizard-completed", value: "" },
377    cursorTarget: { selector: '[data-testid="wizard-finish-btn"]' },
378    interactionMilestone: {
379      promptText: 'Your turn! Click "Finish & Create" to create your new score layout.',
380      targetSelector: '[data-testid="wizard-finish-btn"]',
381      triggerSelector: '[data-testid="wizard-finish-btn"]',
382      successMessage: "Fantastic! The blank score is now generated. 🎹"
383    },
384    durationMs: 3e3
385  }
386];
387const generateStepsProgrammatically = () => {
388  var _a;
389  const krnLines = WIDMUNG_KRN_RAW.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
390  const parsedLines = krnLines.map((line) => {
391    if (line.startsWith("!") || line.startsWith("*") || line.startsWith("=")) {
392      return { isMeta: true, raw: line, cols: [] };
393    }
394    return { isMeta: false, raw: line, cols: line.split("	") };
395  });
396  const activeGrid = parsedLines.map((line) => {
397    if (line.isMeta) return [...line.cols];
398    return line.cols.map(() => ".");
399  });
400  const compileHumdrumSnapshot = () => {
401    return parsedLines.map((line, lineIdx) => {
402      if (line.isMeta) return line.raw;
403      return activeGrid[lineIdx].join("	");
404    }).join("\n") + "\n";
405  };
406  const generatedSteps = [];
407  let noteIndex = 1;
408  let currentMeasure = 1;
409  let currentBeat = 1;
410  parsedLines.forEach((line, lineIdx) => {
411    if (line.isMeta) {
412      if (line.raw.startsWith("=")) {
413        const m = parseInt(line.raw.replace(/[^0-9]/g, ""), 10);
414        if (!isNaN(m)) {
415          currentMeasure = m;
416          currentBeat = 1;
417        }
418      }
419      return;
420    }
421    const lineBeat = currentBeat;
422    currentBeat = currentBeat % 3 + 1;
423    const cols = line.cols;
424    const bassToken = cols[0];
425    if (bassToken && bassToken !== "." && !bassToken.startsWith("!")) {
426      activeGrid[lineIdx][0] = bassToken;
427      const isRest = bassToken.includes("r");
428      const durMatch = bassToken.match(/^(\d+)/);
429      durMatch ? durMatch[1] : "1";
430      generatedSteps.push({
431        id: `gen-step-${noteIndex++}`,
432        instruction: isRest ? `Add bass rest in lower staff.` : `Place bass note ${bassToken} in lower staff.`,
433        mode: "both",
434        action: { type: "set-humdrum", content: compileHumdrumSnapshot() },
435        cursorTarget: { selector: `.measure-${currentMeasure} .beat-1-target` },
436        durationMs: isRest ? 600 : 900,
437        goalSnapshot: compileHumdrumSnapshot(),
438        position: { measure: currentMeasure, beat: lineBeat, tick: 0 }
439      });
440    }
441    const accToken = cols[2];
442    if (accToken && accToken !== "." && !accToken.startsWith("!")) {
443      activeGrid[lineIdx][2] = accToken;
444      const isRest = accToken.includes("r");
445      const durMatch = accToken.match(/^(\d+)/);
446      durMatch ? durMatch[1] : "8";
447      generatedSteps.push({
448        id: `gen-step-${noteIndex++}`,
449        instruction: isRest ? `Add rest in accompaniment.` : `Place accompaniment note ${accToken} in upper Left Hand staff.`,
450        mode: "both",
451        action: { type: "set-humdrum", content: compileHumdrumSnapshot() },
452        cursorTarget: { selector: `.measure-${currentMeasure} .beat-1-target` },
453        durationMs: isRest ? 600 : 900,
454        goalSnapshot: compileHumdrumSnapshot(),
455        position: { measure: currentMeasure, beat: lineBeat, tick: 0 }
456      });
457    }
458    const vocalToken = cols[3];
459    const textToken = cols[4];
460    if (vocalToken && vocalToken !== "." && !vocalToken.startsWith("!")) {
461      activeGrid[lineIdx][3] = vocalToken;
462      if (textToken && textToken !== ".") {
463        activeGrid[lineIdx][4] = textToken;
464      }
465      const isRest = vocalToken.includes("r");
466      const durMatch = vocalToken.match(/^(\d+)/);
467      durMatch ? durMatch[1] : "4";
468      let instr = isRest ? `Add rest in vocal line.` : `Place vocal melody note ${vocalToken} on Soprano staff.`;
469      if (textToken && textToken !== "." && textToken !== "r" && !textToken.startsWith("!")) {
470        instr += ` (Lyrics: "${textToken}")`;
471      }
472      generatedSteps.push({
473        id: `gen-step-${noteIndex++}`,
474        instruction: instr,
475        mode: "both",
476        action: { type: "set-humdrum", content: compileHumdrumSnapshot() },
477        cursorTarget: { selector: `.measure-${currentMeasure} .beat-1-target` },
478        durationMs: isRest ? 600 : 900,
479        goalSnapshot: compileHumdrumSnapshot(),
480        position: { measure: currentMeasure, beat: lineBeat, tick: 0 }
481      });
482    }
483  });
484  const totalGenSteps = generatedSteps.length;
485  const stepsPerChapter = Math.max(15, Math.ceil(totalGenSteps / 7));
486  const chapters = [
487    {
488      id: "setup",
489      title: "Setting Up the Score",
490      description: "Use the Score Wizard to configure Widmung's initial grand staff layout, meter, and composer details.",
491      skillLearned: "Score Configuration",
492      goalSnapshot: SNAPSHOT_CHAPTER_1,
493      steps: setupChapterSteps
494    }
495  ];
496  const chapterNames = [
497    { id: "piano-bass", title: "Entering the Bass Foundation", desc: "Place whole and half note bass foundations on the lower piano staff." },
498    { id: "piano-triplets", title: "Flowing Accompaniment Triplets", desc: "Type flowing arpeggiated accompaniment triplets into the LH upper voice." },
499    { id: "vocal-melody", title: "Transcribing Vocal Melody", desc: "Configure Soprano Vocal clef staves and transcribe lead vocal lines." },
500    { id: "ties-articulation", title: "Ties, Slurs & Pedal marks", desc: "Apply expression slurs, note ties, and damper pedal markings to staves." },
501    { id: "lyrics-text", title: "Vocal Lyrics Alignment", desc: "Map vocal text syllables to note positions in lyrics tracks." },
502    { id: "modulation", title: "Modulation & E Major key change", desc: "Apply a key signature change to E Major (4 sharps) with flat natural cancellations." },
503    { id: "engraving-polish", title: "System Indents & Layout polish", desc: "Set Breitkopf Leipzig edition system indents and spacing properties." }
504  ];
505  for (let cIdx = 0; cIdx < 7; cIdx++) {
506    const start = cIdx * stepsPerChapter;
507    const end = Math.min(totalGenSteps, (cIdx + 1) * stepsPerChapter);
508    const chapterSteps = generatedSteps.slice(start, end);
509    const info = chapterNames[cIdx];
510    const stepsWithKeypadHops = [];
511    chapterSteps.forEach((step, sIdx) => {
512      if (sIdx % 4 === 0) {
513        const durKeys = ['[data-testid="keypad-btn-2-2"]', '[data-testid="keypad-btn-1-0"]', '[data-testid="keypad-btn-1-2"]'];
514        const randomKey = durKeys[sIdx % durKeys.length];
515        stepsWithKeypadHops.push({
516          id: `${step.id}-keypad`,
517          instruction: "Select duration on the Notation Keypad.",
518          mode: "both",
519          action: { type: "click", selector: randomKey },
520          cursorTarget: { selector: randomKey },
521          durationMs: 700,
522          goalSnapshot: step.goalSnapshot
523        });
524      }
525      stepsWithKeypadHops.push(step);
526    });
527    chapters.push({
528      id: info.id,
529      title: info.title,
530      description: info.desc,
531      skillLearned: "Notation Engraving",
532      goalSnapshot: ((_a = chapterSteps[chapterSteps.length - 1]) == null ? void 0 : _a.goalSnapshot) || SNAPSHOT_CHAPTER_8,
533      steps: stepsWithKeypadHops
534    });
535  }
536  chapters[chapters.length - 1].goalSnapshot = SNAPSHOT_CHAPTER_8;
537  const lastChapSteps = chapters[chapters.length - 1].steps;
538  if (lastChapSteps.length > 0) {
539    lastChapSteps[lastChapSteps.length - 1].goalSnapshot = SNAPSHOT_CHAPTER_8;
540  }
541  return { chapters };
542};
543const { chapters: tutorialChapters } = generateStepsProgrammatically();
544const SIMPLE_GOAL_SNAPSHOT = `**kern
545*clefG2
546*k[]
547*M4/4
548=1
5494e
5504d
5514c
5524d
553=2
5544e
5554e
5562e
557=3
5584d
5594d
5602d
561=4
5624e
5634g
5642g
565==
566*-`;
567const simpleChapters = [
568  {
569    id: "simple-setup",
570    title: "Setting Up Your Song",
571    description: "Let's open the Score Wizard and create a blank page to start writing our notes.",
572    skillLearned: "Score Configuration",
573    goalSnapshot: `**kern
574*clefG2
575*k[]
576*M4/4
577=1
5781r
579=2
5801r
581=3
5821r
583=4
5841r
585==
586*-`,
587    steps: [
588      {
589        id: "simple-setup-welcome",
590        instruction: `Welcome to the music editor! Let's start by clicking the "Setup Wizard" card to create our song sheet.`,
591        kidFriendlyInstruction: `Welcome! Let's build our music sheet by clicking the "Setup Wizard" card.`,
592        mode: "both",
593        action: { type: "click", selector: '[data-testid="start-setup-wizard-card"]' },
594        validation: { type: "element-exists", value: ".setup-wizard-modal" },
595        cursorTarget: { selector: '[data-testid="start-setup-wizard-card"]' },
596        interactionMilestone: {
597          promptText: 'Your turn! Click the "Setup Wizard" card to begin configuring the score.',
598          targetSelector: '[data-testid="start-setup-wizard-card"]',
599          successMessage: "Excellent! The Score Setup Wizard is now open. 👍"
600        },
601        durationMs: 2500
602      },
603      {
604        id: "simple-setup-fill",
605        instruction: 'Type "Mary Had a Little Lamb" in the Title box, then click Next.',
606        kidFriendlyInstruction: 'Type "Mary Had a Little Lamb" in the Title box, then click Next.',
607        mode: "both",
608        action: { type: "click", selector: '[data-testid="wizard-next-btn"]' },
609        cursorTarget: { selector: '[data-testid="wizard-title-input"]' },
610        interactionMilestone: {
611          promptText: 'Your turn! Type "Mary Had a Little Lamb" in the Title box, then click Next.',
612          targetSelector: '[data-testid="wizard-title-input"]',
613          triggerSelector: '[data-testid="wizard-next-btn"]',
614          successMessage: "Great job! Score title configured. 📝"
615        },
616        durationMs: 3e3
617      },
618      {
619        id: "simple-setup-instruments",
620        instruction: "Piano is pre-selected for our song layout. Click Next to set the key signature and meter.",
621        kidFriendlyInstruction: "Piano is pre-selected for our song layout. Click Next to set the key signature and meter.",
622        mode: "both",
623        action: { type: "click", selector: '[data-testid="wizard-next-btn"]' },
624        cursorTarget: { selector: '[data-testid="wizard-next-btn"]' },
625        interactionMilestone: {
626          promptText: "Your turn! Click Next to continue to Key & Time Signature.",
627          targetSelector: '[data-testid="wizard-next-btn"]',
628          triggerSelector: '[data-testid="wizard-next-btn"]',
629          successMessage: "Awesome! Next page opened. 🎵"
630        },
631        durationMs: 2500
632      },
633      {
634        id: "simple-setup-generate",
635        instruction: 'Perfect! Click "Finish & Create" to generate your fresh, clean blank staff.',
636        kidFriendlyInstruction: 'Awesome! Click "Finish & Create" to see your empty music sheet.',
637        mode: "both",
638        action: {
639          type: "wizard-fill",
640          title: "Mary Had a Little Lamb",
641          composer: "Traditional",
642          keySig: "C Major",
643          timeSig: "4/4",
644          tempo: 100,
645          tempoText: "Moderato"
646        },
647        validation: { type: "wizard-completed", value: "" },
648        cursorTarget: { selector: '[data-testid="wizard-finish-btn"]' },
649        interactionMilestone: {
650          promptText: 'Your turn! Click "Finish & Create" to create your new score layout.',
651          targetSelector: '[data-testid="wizard-finish-btn"]',
652          triggerSelector: '[data-testid="wizard-finish-btn"]',
653          successMessage: "Fantastic! The blank score is now generated. 🎹"
654        },
655        durationMs: 3e3,
656        goalSnapshot: `**kern
657*clefG2
658*k[]
659*M4/4
660=1
6611r
662=2
6631r
664=3
6651r
666=4
6671r
668==
669*-`
670      }
671    ]
672  },
673  {
674    id: "simple-melody-1",
675    title: "Entering the First Notes",
676    description: 'We will enter the first part of the melody: "Ma-ry had a lit-tle lamb".',
677    skillLearned: "Entering Quarter Notes",
678    goalSnapshot: `**kern
679*clefG2
680*k[]
681*M4/4
682=1
6834e
6844d
6854c
6864d
687=2
6884e
6894e
6902e
691=3
6921r
693=4
6941r
695==
696*-`,
697    steps: [
698      {
699        id: "simple-step-4",
700        instruction: "First, select the Quarter Note (1/4) duration button on the keypad.",
701        kidFriendlyInstruction: "Select the Quarter Note button (the one that looks like a filled black note with a stick).",
702        mode: "both",
703        action: { type: "click", selector: '[data-testid="keypad-btn-1-0"]' },
704        cursorTarget: { selector: '[data-testid="keypad-btn-1-0"]' },
705        interactionMilestone: {
706          promptText: "Your turn! Click the Quarter Note button on the keypad.",
707          targetSelector: '[data-testid="keypad-btn-1-0"]',
708          successMessage: "Great job! You selected the quarter note. 🎉"
709        },
710        durationMs: 2500,
711        goalSnapshot: `**kern
712*clefG2
713*k[]
714*M4/4
715=1
7161r
717=2
7181r
719=3
7201r
721=4
7221r
723==
724*-`
725      },
726      {
727        id: "simple-step-5",
728        instruction: 'Now place the first note, E4, on the staff. This represents the syllable "Ma-".',
729        kidFriendlyInstruction: "Let's place our first note, E (Ma-).",
730        mode: "both",
731        action: {
732          type: "set-humdrum",
733          content: `**kern
734*clefG2
735*k[]
736*M4/4
737=1
7384e
7392.r
740=2
7411r
742=3
7431r
744=4
7451r
746==
747*-`
748        },
749        cursorTarget: { selector: ".measure-1 .beat-1-target" },
750        interactionMilestone: {
751          promptText: "Your turn! Click Measure 1, Beat 1 on the staff to place the first note.",
752          targetSelector: ".measure-1 .beat-1-target",
753          successMessage: "Awesome! First note placed on Measure 1, Beat 1. 🎵"
754        },
755        position: { measure: 1, beat: 1, tick: 0 },
756        durationMs: 2e3,
757        goalSnapshot: `**kern
758*clefG2
759*k[]
760*M4/4
761=1
7624e
7632.r
764=2
7651r
766=3
7671r
768=4
7691r
770==
771*-`
772      },
773      {
774        id: "simple-step-6",
775        instruction: 'Add the next note, D4, for "ry".',
776        kidFriendlyInstruction: "Add the next note, D (-ry).",
777        mode: "both",
778        action: {
779          type: "set-humdrum",
780          content: `**kern
781*clefG2
782*k[]
783*M4/4
784=1
7854e
7864d
7872r
788=2
7891r
790=3
7911r
792=4
7931r
794==
795*-`
796        },
797        cursorTarget: { selector: "#verovio-svg" },
798        durationMs: 1500,
799        goalSnapshot: `**kern
800*clefG2
801*k[]
802*M4/4
803=1
8044e
8054d
8062r
807=2
8081r
809=3
8101r
811=4
8121r
813==
814*-`
815      },
816      {
817        id: "simple-step-7",
818        instruction: 'Add a C4 note for "had".',
819        kidFriendlyInstruction: 'Add a C note for "had".',
820        mode: "both",
821        action: {
822          type: "set-humdrum",
823          content: `**kern
824*clefG2
825*k[]
826*M4/4
827=1
8284e
8294d
8304c
8314r
832=2
8331r
834=3
8351r
836=4
8371r
838==
839*-`
840        },
841        cursorTarget: { selector: "#verovio-svg" },
842        durationMs: 1500,
843        goalSnapshot: `**kern
844*clefG2
845*k[]
846*M4/4
847=1
8484e
8494d
8504c
8514r
852=2
8531r
854=3
8551r
856=4
8571r
858==
859*-`
860      },
861      {
862        id: "simple-step-8",
863        instruction: 'Add D4 again for "a". Now the first measure is full!',
864        kidFriendlyInstruction: 'Add D note for "a". The first bar is complete!',
865        mode: "both",
866        action: {
867          type: "set-humdrum",
868          content: `**kern
869*clefG2
870*k[]
871*M4/4
872=1
8734e
8744d
8754c
8764d
877=2
8781r
879=3
8801r
881=4
8821r
883==
884*-`
885        },
886        cursorTarget: { selector: "#verovio-svg" },
887        durationMs: 1500,
888        goalSnapshot: `**kern
889*clefG2
890*k[]
891*M4/4
892=1
8934e
8944d
8954c
8964d
897=2
8981r
899=3
9001r
901=4
9021r
903==
904*-`
905      },
906      {
907        id: "simple-step-9",
908        instruction: `Let's start the second measure. Place an E4 note for the syllable "lit-".`,
909        kidFriendlyInstruction: "Start the second measure by placing an E note (lit-).",
910        mode: "both",
911        action: {
912          type: "set-humdrum",
913          content: `**kern
914*clefG2
915*k[]
916*M4/4
917=1
9184e
9194d
9204c
9214d
922=2
9234e
9242.r
925=3
9261r
927=4
9281r
929==
930*-`
931        },
932        cursorTarget: { selector: "#verovio-svg" },
933        durationMs: 1500,
934        goalSnapshot: `**kern
935*clefG2
936*k[]
937*M4/4
938=1
9394e
9404d
9414c
9424d
943=2
9444e
9452.r
946=3
9471r
948=4
9491r
950==
951*-`
952      },
953      {
954        id: "simple-step-10",
955        instruction: 'Place another E4 note for "-tle".',
956        kidFriendlyInstruction: "Place another E note (-tle).",
957        mode: "both",
958        action: {
959          type: "set-humdrum",
960          content: `**kern
961*clefG2
962*k[]
963*M4/4
964=1
9654e
9664d
9674c
9684d
969=2
9704e
9714e
9722r
973=3
9741r
975=4
9761r
977==
978*-`
979        },
980        cursorTarget: { selector: "#verovio-svg" },
981        durationMs: 1500,
982        goalSnapshot: `**kern
983*clefG2
984*k[]
985*M4/4
986=1
9874e
9884d
9894c
9904d
991=2
9924e
9934e
9942r
995=3
9961r
997=4
9981r
999==
1000*-`
1001      },
1002      {
1003        id: "simple-step-11",
1004        instruction: "Now, select the Half Note (1/2) duration button on the keypad. This note lasts twice as long!",
1005        kidFriendlyInstruction: "Select the Half Note button (the empty note head with a stick). It holds for two beats!",
1006        mode: "both",
1007        action: { type: "click", selector: '[data-testid="keypad-btn-1-1"]' },
1008        cursorTarget: { selector: '[data-testid="keypad-btn-1-1"]' },
1009        interactionMilestone: {
1010          promptText: "Your turn! Click the Half Note button on the keypad.",
1011          targetSelector: '[data-testid="keypad-btn-1-1"]',
1012          successMessage: "Splendid! You selected the half note. 🌟"
1013        },
1014        durationMs: 2500,
1015        goalSnapshot: `**kern
1016*clefG2
1017*k[]
1018*M4/4
1019=1
10204e
10214d
10224c
10234d
1024=2
10254e
10264e
10272r
1028=3
10291r
1030=4
10311r
1032==
1033*-`
1034      },
1035      {
1036        id: "simple-step-12",
1037        instruction: 'Place the half note E4 on the staff for the word "lamb".',
1038        kidFriendlyInstruction: 'Place the E half note for "lamb".',
1039        mode: "both",
1040        action: {
1041          type: "set-humdrum",
1042          content: `**kern
1043*clefG2
1044*k[]
1045*M4/4
1046=1
10474e
10484d
10494c
10504d
1051=2
10524e
10534e
10542e
1055=3
10561r
1057=4
10581r
1059==
1060*-`
1061        },
1062        cursorTarget: { selector: "#verovio-svg" },
1063        durationMs: 2e3,
1064        goalSnapshot: `**kern
1065*clefG2
1066*k[]
1067*M4/4
1068=1
10694e
10704d
10714c
10724d
1073=2
10744e
10754e
10762e
1077=3
10781r
1079=4
10801r
1081==
1082*-`
1083      }
1084    ]
1085  },
1086  {
1087    id: "simple-melody-2",
1088    title: "Finishing Your Song",
1089    description: "We will enter the remaining notes and then play our so
1089ng!",
1090    skillLearned: "Playing Back a Song",
1091    goalSnapshot: SIMPLE_GOAL_SNAPSHOT,
1092    steps: [
1093      {
1094        id: "simple-step-13",
1095        instruction: `Let's finish the next measure with three notes: D, D, and a half note D. ("Lit-tle lamb, lit-tle lamb")`,
1096        kidFriendlyInstruction: "Let's add three notes: D, D, and a longer D note for the next measure.",
1097        mode: "both",
1098        action: {
1099          type: "set-humdrum",
1100          content: `**kern
1101*clefG2
1102*k[]
1103*M4/4
1104=1
11054e
11064d
11074c
11084d
1109=2
11104e
11114e
11122e
1113=3
11144d
11154d
11162d
1117=4
11181r
1119==
1120*-`
1121        },
1122        cursorTarget: { selector: "#verovio-svg" },
1123        durationMs: 2500,
1124        goalSnapshot: `**kern
1125*clefG2
1126*k[]
1127*M4/4
1128=1
11294e
11304d
11314c
11324d
1133=2
11344e
11354e
11362e
1137=3
11384d
11394d
11402d
1141=4
11421r
1143==
1144*-`
1145      },
1146      {
1147        id: "simple-step-14",
1148        instruction: 'Finally, enter the last measure: E, G, and a half note G. ("Its fleece was white as snow")',
1149        kidFriendlyInstruction: "Let's fill the last measure: E, G, and a longer G note to finish the song!",
1150        mode: "both",
1151        action: {
1152          type: "set-humdrum",
1153          content: SIMPLE_GOAL_SNAPSHOT
1154        },
1155        cursorTarget: { selector: "#verovio-svg" },
1156        durationMs: 2500,
1157        goalSnapshot: SIMPLE_GOAL_SNAPSHOT
1158      },
1159      {
1160        id: "simple-step-play",
1161        instruction: "Congratulations! Your song is written. Click the Play button to hear how it sounds.",
1162        kidFriendlyInstruction: "Hooray! Your song is complete. Let's play it! Click the Play button.",
1163        mode: "both",
1164        action: { type: "click", selector: '[data-testid="tutorial-play-btn"]' },
1165        cursorTarget: { selector: '[data-testid="tutorial-play-btn"]' },
1166        interactionMilestone: {
1167          promptText: "Your turn! Click the Play button in the tutorial controls to listen to your song.",
1168          targetSelector: '[data-testid="tutorial-play-btn"]',
1169          successMessage: "Great job! Enjoy your music. 🎵"
1170        },
1171        durationMs: 3e3,
1172        goalSnapshot: SIMPLE_GOAL_SNAPSHOT
1173      }
1174    ]
1175  },
1176  {
1177    id: "simple-editor-controls",
1178    title: "Editor Controls & Workflow",
1179    description: "Learn playback controls, keyboard hotkeys, staff & measure management, and exporting options.",
1180    skillLearned: "Mastering Full Editor Controls",
1181    goalSnapshot: SIMPLE_GOAL_SNAPSHOT,
1182    steps: [
1183      {
1184        id: "control-toolbar-overview",
1185        instruction: "1. Toolbar Overview: Configure Clefs, Key Signatures, Time Signatures, and Tempo BPM in the main menu toolbar.",
1186        kidFriendlyInstruction: "1. Toolbar Overview: Use the top toolbar to pick your Key, Meter, Clefs, and Tempo!",
1187        mode: "both",
1188        action: { type: "click", selector: '[data-testid="file-menu-btn"]' },
1189        cursorTarget: { selector: '[data-testid="file-menu-btn"]' },
1190        interactionMilestone: {
1191          promptText: "Inspect the top menu bar to explore key, meter, clef, and score setup options.",
1192          targetSelector: '[data-testid="file-menu-btn"]',
1193          triggerSelector: '[data-testid="file-menu-btn"]',
1194          successMessage: "Great! Toolbar overview completed. 🎼"
1195        },
1196        durationMs: 3e3,
1197        goalSnapshot: SIMPLE_GOAL_SNAPSHOT
1198      },
1199      {
1200        id: "control-playback-synth",
1201        instruction: "2. Playback & Synth Controls: Use the Play/Pause buttons and Sound Preset selector (Grand, E-Piano, Pad) to customize sound.",
1202        kidFriendlyInstruction: "2. Playback & Synth: Click Play/Pause and pick your favorite instrument sound preset!",
1203        mode: "both",
1204        action: { type: "click", selector: '[data-testid="playback-play-btn"]' },
1205        cursorTarget: { selector: '[data-testid="synth-preset-group"]' },
1206        interactionMilestone: {
1207          promptText: "Click Play or test switching instrument sound presets (Grand, E-Piano, Pad).",
1208          targetSelector: '[data-testid="synth-preset-group"]',
1209          triggerSelector: '[data-testid="playback-play-btn"]',
1210          successMessage: "Awesome! Playback & synth sound settings verified. 🎹"
1211        },
1212        durationMs: 3e3,
1213        goalSnapshot: SIMPLE_GOAL_SNAPSHOT
1214      },
1215      {
1216        id: "control-code-editor",
1217        instruction: "3. Code Editor Toggle: Switch between visual staff canvas and raw Humdrum score text syntax.",
1218        kidFriendlyInstruction: "3. Code Editor: Click the Code Editor button to see your music written as code!",
1219        mode: "both",
1220        action: { type: "click", selector: '[data-testid="toggle-code-editor-btn"]' },
1221        cursorTarget: { selector: '[data-testid="toggle-code-editor-btn"]' },
1222        interactionMilestone: {
1223          promptText: "Click the Code Editor button in the toolbar to view or hide the text syntax view.",
1224          targetSelector: '[data-testid="toggle-code-editor-btn"]',
1225          triggerSelector: '[data-testid="toggle-code-editor-btn"]',
1226          successMessage: "Splendid! Code editor toggle mastered. 💻"
1227        },
1228        durationMs: 3e3,
1229        goalSnapshot: SIMPLE_GOAL_SNAPSHOT
1230      },
1231      {
1232        id: "control-measure-voice",
1233        instruction: "4. Measure & Voice Management: Select Voice 1 (blue) or Voice 2 (orange) and add or remove staff measures.",
1234        kidFriendlyInstruction: "4. Measure & Voice: Switch between Voice 1 and Voice 2 to write polyphonic music!",
1235        mode: "both",
1236        action: { type: "click", selector: '[data-testid="voice-1-btn"]' },
1237        cursorTarget: { selector: '[data-testid="voice-1-btn"]' },
1238        interactionMilestone: {
1239          promptText: "Click Voice 1 or Voice 2 buttons to select your active polyphonic staff layer.",
1240          targetSelector: '[data-testid="voice-1-btn"]',
1241          triggerSelector: '[data-testid="voice-1-btn"]',
1242          successMessage: "Excellent! Voice & measure management verified. 🎶"
1243        },
1244        durationMs: 3e3,
1245        goalSnapshot: SIMPLE_GOAL_SNAPSHOT
1246      },
1247      {
1248        id: "control-export-options",
1249        instruction: "5. Saving & Exporting: Click the Export menu to download your sheet music as MIDI, MusicXML, or printable PDF!",
1250        kidFriendlyInstruction: "5. Saving & Exporting: Click Export to save your score as PDF, MIDI, or MusicXML!",
1251        mode: "both",
1252        action: { type: "click", selector: '[data-testid="export-menu-btn"]' },
1253        cursorTarget: { selector: '[data-testid="export-menu-btn"]' },
1254        interactionMilestone: {
1255          promptText: "Click the Export menu in the top toolbar to view MusicXML, MIDI, and PDF export options.",
1256          targetSelector: '[data-testid="export-menu-btn"]',
1257          triggerSelector: '[data-testid="export-menu-btn"]',
1258          successMessage: "Fantastic! You have mastered the Notation Editor workflow! 🌟"
1259        },
1260        durationMs: 3e3,
1261        goalSnapshot: SIMPLE_GOAL_SNAPSHOT
1262      }
1263    ]
1264  }
1265];
1266const translations = [
1267  [/\btriplets\b/gi, "groups of three fast notes"],
1268  [/\bvocal lyrics alignment\b/gi, "matching syllables to notes"],
1269  [/\btime signature\b/gi, "beat pattern"],
1270  [/\bkey signature\b/gi, "sharps or flats for your song"],
1271  [/\bbarline\b/gi, "measure divider"],
1272  [/\bstaff\b/gi, "line group"],
1273  [/\bstaves\b/gi, "line groups"],
1274  [/\bledger line\b/gi, "extra line above or below the staff"],
1275  [/\bhumdrum\b/gi, "sheet music"],
1276  [/\bsoprano\b/gi, "Upper Line"],
1277  [/\bbass\b/gi, "low notes"],
1278  [/\bclef\b/gi, "music symbol"]
1279];
1280function filterVocabulary(text, isSimpleMode) {
1281  if (!isSimpleMode || !text) return text;
1282  let filtered = text;
1283  for (const [pattern, replacement] of translations) {
1284    filtered = filtered.replace(pattern, replacement);
1285  }
1286  return filtered;
1287}
1288const typeIntoInput = (input, text) => {
1289  var _a;
1290  const nativeInputValueSetter = (_a = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")) == null ? void 0 : _a.set;
1291  if (nativeInputValueSetter) {
1292    nativeInputValueSetter.call(input, text);
1293  } else {
1294    input.value = text;
1295  }
1296  input.dispatchEvent(new Event("input", { bubbles: true }));
1297  input.dispatchEvent(new Event("change", { bubbles: true }));
1298};
1299const normalizeHumdrum = (str) => {
1300  if (!str) return "";
1301  return str.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("!")).map((line) => line.replace(/\s+/g, "	")).join("\n");
1302};
1303const useTutorialEngine = ({
1304  setHumdrumContent,
1305  humdrumContent,
1306  editorRef,
1307  mode: propMode,
1308  playNotePreview,
1309  onExit,
1310  tutorialStarted,
1311  setTutorialStarted
1312}) => {
1313  console.log(`[TUTORIAL ENGINE] Initializing. tutorialStarted=${tutorialStarted}, mode=${propMode}`);
1314  const getSessionValue = (key, defaultVal) => {
1315    if (typeof window !== "undefined") {
1316      return sessionStorage.getItem(key) ?? defaultVal;
1317    }
1318    return defaultVal;
1319  };
1320  const [lessonType, setLessonType] = reactExports.useState(
1321    () => getSessionValue("agy_tut_lesson_type", "advanced")
1322  );
1323  const activeScript = lessonType === "simple" ? simpleChapters : tutorialChapters;
1324  const [currentChapterIndex, setCurrentChapterIndex] = reactExports.useState(
1325    () => parseInt(getSessionValue("agy_tut_chapter", "0"), 10)
1326  );
1327  const [currentStepIndex, setCurrentStepIndex] = reactExports.useState(
1328    () => parseInt(getSessionValue("agy_tut_step", "0"), 10)
1329  );
1330  const [isPlaying, setIsPlaying] = reactExports.useState(() => {
1331    const stored = getSessionValue("agy_tut_playing", "");
1332    if (stored !== "") return stored === "true";
1333    return false;
1334  });
1335  const [speed, setSpeed] = reactExports.useState(() => {
1336    const stored = getSessionValue("agy_tut_speed", "");
1337    if (stored !== "") return parseFloat(stored);
1338    return 1;
1339  });
1340  const [useTts, setUseTts] = reactExports.useState(
1341    () => getSessionValue("agy_tut_tts", "true") === "true"
1342    // Voice not muted by default
1343  );
1344  const [isCompleted, setIsCompleted] = reactExports.useState(false);
1345  const [autoPlayMode, setAutoPlayMode] = reactExports.useState(() => {
1346    const stored = getSessionValue("agy_tut_autoplay", "");
1347    if (stored !== "") return stored;
1348    return "off";
1349  });
1350  const [stepByStepMode, setStepByStepMode] = reactExports.useState(
1351    () => getSessionValue("agy_tut_step_by_step", "false") === "true"
1352  );
1353  const [mode, setModeInternal] = reactExports.useState(() => {
1354    const stored = getSessionValue("agy_tut_mode", "");
1355    if (stored === "guided" || stored === "watch") return stored;
1356    if (propMode === "playback" || propMode === "watch") return "watch";
1357    return "guided";
1358  });
1359  const [isShowMeActive, setIsShowMeActive] = reactExports.useState(false);
1360  const [isStuckHintVisible, setIsStuckHintVisible] = reactExports.useState(false);
1361  const setMode = reactExports.useCallback((newMode) => {
1362    setModeInternal(newMode);
1363    if (newMode === "watch") {
1364      setIsPlaying(true);
1365    } else {
1366      setIsPlaying(false);
1367    }
1368    setIsStuckHintVisible(false);
1369  }, []);
1370  const [isWaitingForInteraction, setIsWaitingForInteraction] = reactExports.useState(false);
1371  const [completedMilestones, setCompletedMilestones] = reactExports.useState(() => /* @__PURE__ */ new Set());
1372  const [isSpeaking, setIsSpeaking] = reactExports.useState(false);
1373  const prevStartedRef = reactExports.useRef(tutorialStarted);
1374  reactExports.useEffect(() => {
1375    if (tutorialStarted && !prevStartedRef.current) {
1376      setCurrentChapterIndex(0);
1377      setCurrentStepIndex(0);
1378      setHumdrumContent(BLANK_SOLO_STAFF_HUMDRUM);
1379    }
1380    prevStartedRef.current = tutorialStarted;
1381  }, [tutorialStarted, setHumdrumContent]);
1382  reactExports.useEffect(() => {
1383    if (typeof window !== "undefined") {
1384      if (isCompleted) {
1385        sessionStorage.removeItem("agy_tut_chapter");
1386        sessionStorage.removeItem("agy_tut_step");
1387        sessionStorage.removeItem("agy_tut_playing");
1388        sessionStorage.removeItem("agy_tut_speed");
1389        sessionStorage.removeItem("agy_tut_tts");
1390        sessionStorage.removeItem("agy_tut_autoplay");
1391        sessionStorage.removeItem("agy_tut_started");
1392        sessionStorage.removeItem("agy_tut_lesson_type");
1393        sessionStorage.removeItem("agy_tut_step_by_step");
1394        sessionStorage.removeItem("agy_tut_mode");
1395      } else {
1396        sessionStorage.setItem("agy_tut_chapter", currentChapterIndex.toString());
1397        sessionStorage.setItem("agy_tut_step", currentStepIndex.toString());
1398        sessionStorage.setItem("agy_tut_playing", isPlaying.toString());
1399        sessionStorage.setItem("agy_tut_speed", speed.toString());
1400        sessionStorage.setItem("agy_tut_tts", useTts.toString());
1401        sessionStorage.setItem("agy_tut_autoplay", autoPlayMode);
1402        sessionStorage.setItem("agy_tut_started", tutorialStarted.toString());
1403        sessionStorage.setItem("agy_tut_lesson_type", lessonType);
1404        sessionStorage.setItem("agy_tut_step_by_step", stepByStepMode.toString());
1405        sessionStorage.setItem("agy_tut_mode", mode);
1406      }
1407    }
1408  }, [
1409    currentChapterIndex,
1410    currentStepIndex,
1411    isPlaying,
1412    speed,
1413    useTts,
1414    autoPlayMode,
1415    isCompleted,
1416    tutorialStarted,
1417    lessonType,
1418    stepByStepMode,
1419    mode
1420  ]);
1421  const handleExit = reactExports.useCallback(() => {
1422    if (typeof window !== "undefined") {
1423      sessionStorage.removeItem("agy_tut_chapter");
1424      sessionStorage.removeItem("agy_tut_step");
1425      sessionStorage.removeItem("agy_tut_playing");
1426      sessionStorage.removeItem("agy_tut_speed");
1427      sessionStorage.removeItem("agy_tut_tts");
1428      sessionStorage.removeItem("agy_tut_autoplay");
1429      sessionStorage.removeItem("agy_tut_started");
1430      sessionStorage.removeItem("agy_tut_lesson_type");
1431      sessionStorage.removeItem("agy_tut_step_by_step");
1432      sessionStorage.removeItem("agy_tut_mode");
1433    }
1434    if (onExit) onExit();
1435  }, [onExit]);
1436  const playbackTimerRef = reactExports.useRef(null);
1437  const isPlayingRef = reactExports.useRef(isPlaying);
1438  isPlayingRef.current = isPlaying;
1439  const currentChapter = activeScript[currentChapterIndex] || activeScript[0];
1440  const currentStep = currentChapter == null ? void 0 : currentChapter.steps[currentStepIndex];
1441  const getStepInstruction = reactExports.useCallback((step) => {
1442    if (!step) return "";
1443    const text = lessonType === "simple" && step.kidFriendlyInstruction ? step.kidFriendlyInstruction : step.instruction;
1444    return filterVocabulary(text, lessonType === "simple");
1445  }, [lessonType]);
1446  const speakInstruction = reactExports.useCallback((text) => {
1447    if (!useTts || typeof window === "undefined" || !window.speechSynthesis) {
1448      setIsSpeaking(false);
1449      return;
1450    }
1451    try {
1452      window.speechSynthesis.cancel();
1453      const filtered = filterVocabulary(text, lessonType === "simple");
1454      const utterance = new SpeechSynthesisUtterance(filtered);
1455      utterance.rate = 1;
1456      utterance.onstart = () => setIsSpeaking(true);
1457      utterance.onend = () => setIsSpeaking(false);
1458      utterance.onerror = () => setIsSpeaking(false);
1459      window.speechSynthesis.speak(utterance);
1460    } catch (err) {
1461      console.error("Speech synthesis error:", err);
1462      setIsSpeaking(false);
1463    }
1464  }, [useTts, lessonType]);
1465  const lastExecutedStepRef = reactExports.useRef(null);
1466  const executeStepAction = reactExports.useCallback((step) => {
1467    var _a;
1468    if (!step) return;
1469    const stepKey = `${currentChapterIndex}-${currentStepIndex}`;
1470    console.log("[TUTORIAL ENGINE] executeStepAction executing stepKey:", stepKey, "actionType:", step.action.type, "selector:", step.action.selector || "none");
1471    lastExecutedStepRef.current = stepKey;
1472    const act = step.action;
1473    const targetSel = act.selector || ((_a = step.cursorTarget) == null ? void 0 : _a.selector);
1474    if (targetSel) {
1475      try {
1476        const el = document.querySelector(targetSel);
1477        if (el) {
1478          el.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
1479        }
1480      } catch (e) {
1481      }
1482    } else {
1483      try {
1484        const el = document.querySelector(".selected-note");
1485        if (el) {
1486          el.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
1487        }
1488      } catch (e) {
1489      }
1490    }
1491    switch (act.type) {
1492      case "set-humdrum":
1493        setHumdrumContent(act.content);
1494        requestAnimationFrame(() => {
1495          if (editorRef == null ? void 0 : editorRef.forceRender) {
1496            editorRef.forceRender();
1497          }
1498          if (step.position && (editorRef == null ? void 0 : editorRef.setPlaybackPosition)) {
1499            editorRef.setPlaybackPosition(step.position);
1500          }
1501        });
1502        break;
1503      case "click": {
1504        const attemptClick = (retriesLeft = 10) => {
1505          const el = document.querySelector(act.selector);
1506          if (el) {
1507            if (act.selector === '[data-testid="wizard-next-btn"]' || step.id === "simple-setup-fill" || step.id === "setup-next-1" || step.id === "setup-next-2") {
1508              const titleInput = document.querySelector('[data-testid="wizard-title-input"]');
1509              const compInput = document.querySelector('[data-testid="wizard-composer-input"]');
1510              if (titleInput && !titleInput.value) {
1511                typeIntoInput(titleInput, lessonType === "simple" ? "Mary Had a Little Lamb" : "Widmung");
1512              }
1513              if (compInput && !compInput.value) {
1514                typeIntoInput(compInput, lessonType === "simple" ? "Traditional" : "Robert Schumann");
1515              }
1516              setTimeout(() => {
1517                const btn = document.querySelector('[data-testid="wizard-next-btn"]') || el;
1518                if (btn) btn.click();
1519              }, 100);
1520              return;
1521            } else if (act.selector === '[data-testid="wizard-title-input"]') {
1522              typeIntoInput(el, lessonType === "simple" ? "Mary Had a Little Lamb" : "Widmung");
1523            } else if (act.selector === '[data-testid="wizard-composer-input"]') {
1524              typeIntoInput(el, lessonType === "simple" ? "Traditional" : "Robert Schumann");
1525            } else if (act.selector === '[data-testid="wizard-key-Ab"]') {
1526              setTimeout(() => {
1527                const numInput = document.querySelector('[data-testid="wizard-time-num"]');
1528                const denSelect = document.querySelector('[data-testid="wizard-time-den"]');
1529                if (numInput) typeIntoInput(numInput, "3");
1530                if (denSelect) {
1531                  denSelect.value = "2";
1532                  denSelect.dispatchEvent(new Event("change", { bubbles: true }));
1533                }
1534              }, 100);
1535            }
1536            el.click();
1537          } else if (retriesLeft > 0) {
1538            setTimeout(() => attemptClick(retriesLeft - 1), 100);
1539          }
1540        };
1541        attemptClick();
1542        break;
1543      }
1544      case "wizard-fill":
1545        const snap = step.goalSnapshot || currentChapter.goalSnapshot;
1546        setHumdrumContent(snap);
1547        if (editorRef == null ? void 0 : editorRef.closeWizard) {
1548          editorRef.closeWizard();
1549        }
1550        if (editorRef == null ? void 0 : editorRef.setShowWelcome) {
1551          editorRef.setShowWelcome(false);
1552        }
1553        if (setTutorialStarted) {
1554          setTutorialStarted(true);
1555        }
1556        requestAnimationFrame(() => {
1557          if (editorRef == null ? void 0 : editorRef.forceRender) {
1558            editorRef.forceRender();
1559          }
1560          if (step.position && (editorRef == null ? void 0 : editorRef.setPlaybackPosition)) {
1561            editorRef.setPlaybackPosition(step.position);
1562          }
1563        });
1564        break;
1565      case "keypress":
1566        if (editorRef == null ? void 0 : editorRef.triggerKeyPress) {
1567          editorRef.triggerKeyPress(act.key, act);
1568        }
1569        break;
1570    }
1571    if (playNotePreview && step.instruction.toLowerCase().includes("note")) {
1572      playNotePreview([60]);
1573    }
1574  }, [setHumdrumContent, editorRef, playNotePreview, currentChapter, mode, currentChapterIndex, currentStepIndex, lessonType]);
1575  const handleNext = reactExports.useCallback(() => {
1576    if (isShowMeActive) {
1577      setIsShowMeActive(false);
1578      setMode("guided");
1579    }
1580    if (currentStepIndex < currentChapter.steps.length - 1) {
1581      const nextStepIdx = currentStepIndex + 1;
1582      const nextStep = currentChapter.steps[nextStepIdx];
1583      if (nextStep.interactionMilestone && mode !== "watch") {
1584        setIsWaitingForInteraction(true);
1585        setIsPlaying(false);
1586        setCurrentStepIndex(nextStepIdx);
1587        speakInstruction(getStepInstruction(nextStep));
1588        return;
1589      }
1590      setCurrentStepIndex(nextStepIdx);
1591      if (typeof window !== "undefined") {
1592        sessionStorage.setItem("agy_tut_chapter", currentChapterIndex.toString());
1593        sessionStorage.setItem("agy_tut_step", nextStepIdx.toString());
1594      }
1595      speakInstruction(getStepInstruction(nextStep));
1596    } else if (currentChapterIndex < activeScript.length - 1) {
1597      if (autoPlayMode === "chapter" && mode !== "watch") {
1598        setIsPlaying(false);
1599        speakInstruction("Chapter completed. Click next or play to continue.");
1600        return;
1601      }
1602      const nextChapterIdx = currentChapterIndex + 1;
1603      const nextStep = activeScript[nextChapterIdx].steps[0];
1604      if (nextStep.interactionMilestone && mode !== "watch") {
1605        setIsWaitingForInteraction(true);
1606        setIsPlaying(false);
1607        setCurrentChapterIndex(nextChapterIdx);
1608        setCurrentStepIndex(0);
1609        setHumdrumContent(currentChapter.goalSnapshot);
1610        if (typeof window !== "undefined") {
1611          sessionStorage.setItem("agy_tut_chapter", nextChapterIdx.toString());
1612          sessionStorage.setItem("agy_tut_step", "0");
1613        }
1614        speakInstruction(getStepInstruction(nextStep));
1615        return;
1616      }
1617      setCurrentChapterIndex(nextChapterIdx);
1618      setCurrentStepIndex(0);
1619      if (typeof window !== "undefined") {
1620        sessionStorage.setItem("agy_tut_chapter", nextChapterIdx.toString());
1621        sessionStorage.setItem("agy_tut_step", "0");
1622      }
1623      setHumdrumContent(currentChapter.goalSnapshot);
1624      speakInstruction(getStepInstruction(nextStep));
1625    } else {
1626      setIsPlaying(false);
1627      setIsCompleted(true);
1628      speakInstruction(lessonType === "simple" ? "Congratulations! You completed your song." : "Congratulations! You have completed the Schumann Wi
1628dmung tutorial.");
1629    }
1630  }, [
1631    currentChapterIndex,
1632    currentStepIndex,
1633    currentChapter,
1634    speakInstruction,
1635    setHumdrumContent,
1636    autoPlayMode,
1637    activeScript,
1638    getStepInstruction,
1639    lessonType,
1640    isShowMeActive,
1641    setMode,
1642    mode
1643  ]);
1644  const handlePrev = reactExports.useCallback(() => {
1645    setIsCompleted(false);
1646    setIsWaitingForInteraction(false);
1647    if (currentStepIndex > 0) {
1648      const prevStepIdx = currentStepIndex - 1;
1649      setCurrentStepIndex(prevStepIdx);
1650      const snap = prevStepIdx === 0 ? currentChapterIndex === 0 ? BLANK_SOLO_STAFF_HUMDRUM : activeScript[currentChapterIndex - 1].goalSnapshot : currentChapter.steps[prevStepIdx - 1].goalSnapshot || currentChapter.goalSnapshot;
1651      if (snap) setHumdrumContent(snap);
1652      speakInstruction(getStepInstruction(currentChapter.steps[prevStepIdx]));
1653    } else if (currentChapterIndex > 0) {
1654      const prevChapterIdx = currentChapterIndex - 1;
1655      const prevChapter = activeScript[prevChapterIdx];
1656      setCurrentChapterIndex(prevChapterIdx);
1657      const lastStepIdx = prevChapter.steps.length - 1;
1658      setCurrentStepIndex(lastStepIdx);
1659      const snap = lastStepIdx === 0 ? prevChapterIdx === 0 ? BLANK_SOLO_STAFF_HUMDRUM : activeScript[prevChapterIdx - 1].goalSnapshot : prevChapter.steps[lastStepIdx - 1].goalSnapshot || prevChapter.goalSnapshot;
1660      if (snap) setHumdrumContent(snap);
1661      speakInstruction(getStepInstruction(prevChapter.steps[lastStepIdx]));
1662    }
1663  }, [currentChapterIndex, currentStepIndex, currentChapter, speakInstruction, setHumdrumContent, activeScript, getStepInstruction]);
1664  const jumpToChapter = reactExports.useCallback((chapterIndex) => {
1665    setIsCompleted(false);
1666    setIsWaitingForInteraction(false);
1667    setCurrentChapterIndex(chapterIndex);
1668    setCurrentStepIndex(0);
1669    const snap = chapterIndex === 0 ? BLANK_SOLO_STAFF_HUMDRUM : activeScript[chapterIndex - 1].goalSnapshot;
1670    setHumdrumContent(snap);
1671    const targetStep = activeScript[chapterIndex].steps[0];
1672    if (targetStep.interactionMilestone) {
1673      setIsWaitingForInteraction(true);
1674      setIsPlaying(false);
1675    }
1676    speakInstruction(getStepInstruction(targetStep));
1677  }, [speakInstruction, setHumdrumContent, activeScript, getStepInstruction]);
1678  const getGlobalStepCount = () => {
1679    return activeScript.reduce((acc, chap) => acc + chap.steps.length, 0);
1680  };
1681  const getGlobalStepIndex = () => {
1682    let index = 0;
1683    for (let i = 0; i < currentChapterIndex; i++) {
1684      index += activeScript[i].steps.length;
1685    }
1686    return index + currentStepIndex;
1687  };
1688  const jumpToGlobalStep = reactExports.useCallback((globalIndex) => {
1689    setIsCompleted(false);
1690    setIsWaitingForInteraction(false);
1691    let accumulated = 0;
1692    for (let c = 0; c < activeScript.length; c++) {
1693      const stepsInChapter = activeScript[c].steps.length;
1694      if (globalIndex < accumulated + stepsInChapter) {
1695        const stepIdx = globalIndex - accumulated;
1696        setCurrentChapterIndex(c);
1697        setCurrentStepIndex(stepIdx);
1698        const prevSnap = c === 0 && stepIdx === 0 ? BLANK_SOLO_STAFF_HUMDRUM : stepIdx === 0 ? activeScript[c - 1].goalSnapshot : activeScript[c].goalSnapshot;
1699        if (prevSnap) {
1700          setHumdrumContent(prevSnap);
1701        }
1702        const targetStep = activeScript[c].steps[stepIdx];
1703        if (targetStep.interactionMilestone) {
1704          setIsWaitingForInteraction(true);
1705          setIsPlaying(false);
1706        }
1707        speakInstruction(getStepInstruction(targetStep));
1708        break;
1709      }
1710      accumulated += stepsInChapter;
1711    }
1712  }, [speakInstruction, setHumdrumContent, activeScript, getStepInstruction]);
1713  const handleNextRef = reactExports.useRef(handleNext);
1714  reactExports.useEffect(() => {
1715    handleNextRef.current = handleNext;
1716  }, [handleNext]);
1717  const executeStepActionRef = reactExports.useRef(executeStepAction);
1718  reactExports.useEffect(() => {
1719    executeStepActionRef.current = executeStepAction;
1720  }, [executeStepAction]);
1721  const scrollTargetIntoView = reactExports.useCallback((selector) => {
1722    try {
1723      const el = document.querySelector(selector);
1724      if (el) {
1725        el.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
1726      }
1727    } catch (err) {
1728      console.warn("[TUTORIAL ENGINE] Failed to scroll target into view:", selector, err);
1729    }
1730  }, []);
1731  reactExports.useEffect(() => {
1732    if (!tutorialStarted || isWaitingForInteraction) return;
1733    const handleKeyDown = (e) => {
1734      var _a, _b;
1735      if (((_a = document.activeElement) == null ? void 0 : _a.tagName) === "INPUT" || ((_b = document.activeElement) == null ? void 0 : _b.tagName) === "TEXTAREA") {
1736        return;
1737      }
1738      if (e.key === " ") {
1739        e.preventDefault();
1740        setIsPlaying((prev) => !prev);
1741      } else if (e.key === "ArrowLeft") {
1742        e.preventDefault();
1743        handlePrev();
1744      } else if (e.key === "ArrowRight") {
1745        e.preventDefault();
1746        handleNext();
1747      }
1748    };
1749    window.addEventListener("keydown", handleKeyDown);
1750    return () => {
1751      window.removeEventListener("keydown", handleKeyDown);
1752    };
1753  }, [tutorialStarted, isWaitingForInteraction, handleNext, handlePrev]);
1754  reactExports.useEffect(() => {
1755    if (playbackTimerRef.current) {
1756      clearTimeout(playbackTimerRef.current);
1757      playbackTimerRef.current = null;
1758    }
1759    if (tutorialStarted && isPlaying && currentStep && mode === "watch" && !isWaitingForInteraction && !stepByStepMode) {
1760      if (stepByStepMode && (currentStep.detailHtml || currentStep.durationMs > 3e3) && lastExecutedStepRef.current === `${currentChapterIndex}-${currentStepIndex}`) {
1761        setIsPlaying(false);
1762        return;
1763      }
1764      const delay = (currentStep.durationMs || 2e3) / speed;
1765      playbackTimerRef.current = setTimeout(() => {
1766        handleNextRef.current();
1767      }, delay);
1768    }
1769    return () => {
1770      if (playbackTimerRef.current) {
1771        clearTimeout(playbackTimerRef.current);
1772      }
1773    };
1774  }, [isPlaying, currentChapterIndex, currentStepIndex, speed, mode, tutorialStarted, isWaitingForInteraction, stepByStepMode, currentStep]);
1775  reactExports.useEffect(() => {
1776    if (tutorialStarted && isPlaying && currentStep && mode === "watch") {
1777      const stepKey = `${currentChapterIndex}-${currentStepIndex}`;
1778      console.log("[TUTORIAL ENGINE] playing useEffect fired. stepKey:", stepKey, "lastExecuted:", lastExecutedStepRef.current);
1779      if (lastExecutedStepRef.current !== stepKey) {
1780        console.log("[TUTORIAL ENGINE] stepKey does not match lastExecuted. Executing action...");
1781        lastExecutedStepRef.current = stepKey;
1782        executeStepActionRef.current(currentStep);
1783      }
1784    } else if (!isPlaying) {
1785      console.log("[TUTORIAL ENGINE] paused. Clearing lastExecutedStepRef");
1786      lastExecutedStepRef.current = null;
1787    }
1788  }, [isPlaying, currentStepIndex, currentChapterIndex, mode, tutorialStarted, currentStep]);
1789  reactExports.useEffect(() => {
1790    var _a, _b;
1791    if (tutorialStarted && currentStep) {
1792      speakInstruction(getStepInstruction(currentStep));
1793      const activeMeasureIndex = ((_a = currentStep.position) == null ? void 0 : _a.measure) || 1;
1794      if (editorRef == null ? void 0 : editorRef.scrollToMeasure) {
1795        editorRef.scrollToMeasure(activeMeasureIndex, { behavior: "smooth", align: "center" });
1796      }
1797      const targetSel = currentStep.action.selector || ((_b = currentStep.cursorTarget) == null ? void 0 : _b.selector);
1798      if (targetSel) {
1799        setTimeout(() => {
1800          scrollTargetIntoView(targetSel);
1801        }, 150);
1802      } else {
1803        setTimeout(() => {
1804          scrollTargetIntoView(".selected-note");
1805        }, 150);
1806      }
1807    }
1808  }, [currentChapterIndex, currentStepIndex, speakInstruction, tutorialStarted, currentStep, scrollTargetIntoView, getStepInstruction, editorRef]);
1809  reactExports.useEffect(() => {
1810    return () => {
1811      if (typeof window !== "undefined" && window.speechSynthesis) {
1812        try {
1813          window.speechSynthesis.cancel();
1814        } catch (e) {
1815          console.warn("Speech synthesis cleanup warning:", e);
1816        }
1817      }
1818    };
1819  }, []);
1820  reactExports.useEffect(() => {
1821    console.log(`[TUTORIAL ENGINE] isWaitingForInteraction: target=${(currentStep == null ? void 0 : currentStep.interactionMilestone) ? "yes" : "no"}`);
1822    if (tutorialStarted && mode === "guided" && (currentStep == null ? void 0 : currentStep.interactionMilestone)) {
1823      setIsWaitingForInteraction(true);
1824    } else {
1825      setIsWaitingForInteraction(false);
1826    }
1827  }, [tutorialStarted, mode, currentStep, currentStepIndex, currentChapterIndex]);
1828  reactExports.useEffect(() => {
1829    if (!tutorialStarted || isCompleted) {
1830      setIsStuckHintVisible(false);
1831      return;
1832    }
1833    setIsStuckHintVisible(true);
1834  }, [tutorialStarted, isCompleted]);
1835  const showMeThisStep = reactExports.useCallback(() => {
1836    setIsShowMeActive(true);
1837    if (currentStep) {
1838      executeStepActionRef.current(currentStep);
1839      setTimeout(() => {
1840        setIsShowMeActive(false);
1841        setModeInternal("guided");
1842        handleNext();
1843      }, 300);
1844    } else {
1845      setModeInternal("watch");
1846      setIsPlaying(true);
1847    }
1848  }, [currentStep, handleNext]);
1849  const skipStep = reactExports.useCallback(() => {
1850    if (currentStep) {
1851      executeStepActionRef.current(currentStep);
1852    }
1853    handleNext();
1854  }, [currentStep, handleNext]);
1855  reactExports.useEffect(() => {
1856    if (!tutorialStarted || isCompleted || mode !== "guided" || !(currentStep == null ? void 0 : currentStep.validation)) {
1857      return;
1858    }
1859    const validation = currentStep.validation;
1860    const interval = setInterval(() => {
1861      let isValSatisfied = false;
1862      if (validation.type === "element-exists") {
1863        isValSatisfied = document.querySelector(validation.value) !== null;
1864      } else if (validation.type === "wizard-completed") {
1865        isValSatisfied = !document.querySelector(".setup-wizard-modal");
1866      }
1867      if (isValSatisfied) {
1868        clearInterval(interval);
1869        console.log(`[TUTORIAL ENGINE] Validation satisfied for step ${currentStep.id}, advancing.`);
1870        handleNext();
1871      }
1872    }, 250);
1873    return () => clearInterval(interval);
1874  }, [tutorialStarted, isCompleted, mode, currentStep, handleNext]);
1875  reactExports.useEffect(() => {
1876    if (!tutorialStarted || isCompleted || mode !== "guided" || isWaitingForInteraction || (currentStep == null ? void 0 : currentStep.interactionMilestone)) {
1877      return;
1878    }
1879    const act = currentStep == null ? void 0 : currentStep.action;
1880    if ((act == null ? void 0 : act.type) !== "click" || !act.selector) {
1881      return;
1882    }
1883    const handleGlobalClick = (e) => {
1884      const targetEl = document.querySelector(act.selector);
1885      if (targetEl && (targetEl === e.target || targetEl.contains(e.target))) {
1886        setTimeout(() => {
1887          handleNext();
1888        }, 100);
1889      }
1890    };
1891    document.addEventListener("click", handleGlobalClick, true);
1892    return () => {
1893      document.removeEventListener("click", handleGlobalClick, true);
1894    };
1895  }, [tutorialStarted, isCompleted, mode, isWaitingForInteraction, currentStep, handleNext]);
1896  reactExports.useEffect(() => {
1897    if (!tutorialStarted || isCompleted || mode !== "guided" || isWaitingForInteraction || !currentStep || !humdrumContent) {
1898      return;
1899    }
1900    if (currentStepIndex === 0 && currentChapterIndex === 0) {
1901      return;
1902    }
1903    if (currentStep.action.type === "click" || currentStep.action.type === "wait") {
1904      return;
1905    }
1906    const targetSnapshot = currentStep.goalSnapshot || (currentStep.action.type === "set-humdrum" ? currentStep.action.content : void 0);
1907    if (!targetSnapshot) {
1908      return;
1909    }
1910    const normalizedCurrent = normalizeHumdrum(humdrumContent);
1911    const normalizedTarget = normalizeHumdrum(targetSnapshot);
1912    if (normalizedCurrent === normalizedTarget) {
1913      handleNext();
1914    }
1915  }, [tutorialStarted, isCompleted, mode, isWaitingForInteraction, currentStep, currentStepIndex, currentChapterIndex, humdrumContent, handleNext]);
1916  return {
1917    currentChapterIndex,
1918    currentStepIndex,
1919    currentChapter,
1920    currentStep,
1921    isPlaying,
1922    setIsPlaying,
1923    speed,
1924    setSpeed,
1925    useTts,
1926    setUseTts,
1927    isCompleted,
1928    handleNext,
1929    handlePrev,
1930    jumpToChapter,
1931    jumpToGlobalStep,
1932    getGlobalStepIndex,
1933    getGlobalStepCount,
1934    autoPlayMode,
1935    setAutoPlayMode,
1936    tutorialStarted,
1937    setTutorialStarted,
1938    onExit: handleExit,
1939    lessonType,
1940    setLessonType,
1941    stepByStepMode,
1942    setStepByStepMode,
1943    isWaitingForInteraction,
1944    setIsWaitingForInteraction,
1945    completedMilestones,
1946    mode,
1947    setMode,
1948    isStuckHintVisible,
1949    setIsStuckHintVisible,
1950    showMeThisStep,
1951    skipStep,
1952    isShowMeActive,
1953    isSpeaking
1954  };
1955};
1956const TutorialPanel = ({
1957  currentChapterIndex,
1958  currentStepIndex,
1959  isPlaying,
1960  setIsPlaying,
1961  speed,
1962  setSpeed,
1963  useTts,
1964  setUseTts,
1965  isCompleted,
1966  handleNext,
1967  handlePrev,
1968  jumpToChapter,
1969  jumpToGlobalStep,
1970  getGlobalStepIndex,
1971  getGlobalStepCount,
1972  onExit,
1973  theme = "dark",
1974  autoPlayMode,
1975  setAutoPlayMode,
1976  mode,
1977  setMode,
1978  isStuckHintVisible,
1979  showMeThisStep,
1980  skipStep,
1981  tutorialStarted,
1982  setTutorialStarted,
1983  lessonType,
1984  setLessonType,
1985  stepByStepMode,
1986  setStepByStepMode,
1987  completedMilestones,
1988  isSpeaking = false
1989}) => {
1990  const [activeTab, setActiveTab] = reactExports.useState("steps");
1991  const [isCollapsed, setIsCollapsed] = reactExports.useState(false);
1992  const [showAdvanced, setShowAdvanced] = reactExports.useState(false);
1993  const [isAnimatingToSide, setIsAnimatingToSide] = reactExports.useState(false);
1994  const [isPlaybackScrubberExpanded, setIsPlaybackScrubberExpanded] = reactExports.useState(false);
1995  const getStepInstruction = (step) => {
1996    if (!step) return "";
1997    const text = lessonType === "simple" && step.kidFriendlyInstruction ? step.kidFriendlyInstruction : step.instruction;
1998    return filterVocabulary(text, lessonType === "simple");
1999  };
2000  const startLesson = (type) => {
2001    setLessonType(type);
2002    setIsAnimatingToSide(true);
2003    setTimeout(() => {
2004      setTutorialStarted(true);
2005      setIsAnimatingToSide(false);
2006    }, 700);
2007  };
2008  const activeScript = lessonType === "simple" ? simpleChapters : tutorialChapters;
2009  const currentChapter = activeScript[currentChapterIndex] || activeScript[0];
2010  const currentStep = currentChapter == null ? void 0 : currentChapter.steps[currentStepIndex];
2011  const totalSteps = getGlobalStepCount();
2012  const globalStepIdx = getGlobalStepIndex();
2013  const progressPercent = totalSteps > 1 ? globalStepIdx / (totalSteps - 1) * 100 : 0;
2014  const getChapterTicks = () => {
2015    let acc = 0;
2016    return activeScript.map((ch, idx) => {
2017      const pos = totalSteps > 1 ? acc / (totalSteps - 1) * 100 : 0;
2018      acc += ch.steps.length;
2019      return { id: ch.id, title: ch.title, pos };
2020    });
2021  };
2022  const ticks = getChapterTicks();
2023  if (!tutorialStarted || isAnimatingToSide) {
2024    return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2025      /* @__PURE__ */ jsxRuntimeExports.jsx(
2026        "div",
2027        {
2028          className: `fixed inset-0 bg-black/75 backdrop-blur-[4px] z-[190] transition-opacity duration-700 ${isAnimatingToSide ? "opacity-0 pointer-events-none" : "opacity-100"}`
2029        }
2030      ),
2031      /* @__PURE__ */ jsxRuntimeExports.jsxs(
2032        "div",
2033        {
2034          className: isAnimatingToSide ? "fixed right-0 top-0 bottom-0 h-screen w-80 md:w-96 bg-[var(--daw-elevated)] border-l border-[var(--daw-border-strong)] shadow-2xl z-[200] transition-all duration-700 ease-in-out flex flex-col overflow-hidden" : "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[450px] max-w-[95vw] bg-[var(--daw-elevated)] border border-[var(--daw-border-strong)] rounded-2xl shadow-2xl p-6 z-[200] transition-all duration-700 ease-in-out flex flex-col space-y-4",
2035          children: [
2036            !isAnimatingToSide && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center pb-2.5 border-b border-[var(--daw-border-strong)]", children: [
2037              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm font-bold text-[var(--daw-text)] flex items-center gap-2", children: [
2038                /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { className: "w-4 h-4 text-blue-500" }),
2039                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Notation Editor Tutorial" })
2040              ] }),
2041              /* @__PURE__ */ jsxRuntimeExports.jsx(
2042                "button",
2043                {
2044                  onClick: onExit,
2045                  className: "text-xs font-semibold px-2.5 py-1 rounded bg-[var(--tutorial-exit-bg)] border border-[var(--tutorial-exit-border)] hover:bg-[var(--tutorial-exit-hover-bg)] text-[var(--tutorial-exit-text)] transition cursor-pointer",
2046                  children: "Exit"
2047                }
2048              )
2049            ] }),
2050            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `transition-opacity duration-300 flex-1 flex flex-col justify-center ${isAnimatingToSide ? "opacity-0" : "opacity-100"}`, children: [
2051              /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-extrabold text-lg text-[var(--daw-text)] text-center tracking-wide mt-2", children: "🎓 Choose Your Lesson" }),
2052              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-[var(--daw-text-secondary)] text-center leading-relaxed max-w-xs mx-auto mt-2 mb-6", children: "Start with the basics or jump into an advanced masterwork. You can switch between practicing (Guided) and watching (Watch) at any time." }),
2053              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
2054                /* @__PURE__ */ jsxRuntimeExports.jsxs(
2055                  "button",
2056                  {
2057                    onClick: () => startLesson("simple"),
2058                    className: "w-full text-left p-4 rounded-xl border border-[var(--tutorial-simple-border)] bg-[var(--tutorial-simple-bg)] hover:bg-[var(--tutorial-simple-hover-bg)] transition cursor-pointer flex flex-col justify-between space-y-2 group",
2059                    "data-testid": "choose-simple-lesson-btn",
2060                    children: [
2061                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
2062                        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-bold text-[var(--tutorial-simple-text)] uppercase tracking-widest flex items-center gap-1", children: [
2063                          /* @__PURE__ */ jsxRuntimeExports.jsx(Star, { className: "w-3.5 h-3.5 fill-current text-[var(--tutorial-simple-text)]" }),
2064                          " Simple Lesson"
2065                        ] }),
2066                        /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowRight, { className: "w-4 h-4 text-[var(--tutorial-simple-text)] transition transform group-hover:translate-x-1" })
2067                      ] }),
2068                      /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "font-extrabold text-sm text-[var(--daw-text)]", children: "Mary Had a Little Lamb" }),
2069                      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-[var(--daw-text-secondary)] leading-normal", children: "A beginner-friendly C Major introduction to building simple tunes. Replaces technical musical jargon with easy definitions and challenges." })
2070                    ]
2071                  }
2072                ),
2073                /* @__PURE__ */ jsxRuntimeExports.jsxs(
2074                  "button",
2075                  {
2076                    onClick: () => startLesson("advanced"),
2077                    className: "w-full text-left p-4 rounded-xl border border-[var(--tutorial-advanced-border)] bg-[var(--tutorial-advanced-bg)] hover:bg-[var(--tutorial-advanced-hover-bg)] transition cursor-pointer flex flex-col justify-between space-y-2 group",
2078                    "data-testid": "choose-advanced-lesson-btn",
2079                    children: [
2080                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
2081                        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-bold text-[var(--tutorial-advanced-text)] uppercase tracking-widest flex items-center gap-1", children: [
2082                          /* @__PURE__ */ jsxRuntimeExports.jsx(Trophy, { className: "w-3.5 h-3.5" }),
2083                          " Classic / Advanced Mode"
2084                        ] }),
2085                        /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowRight, { className: "w-4 h-4 text-[var(--tutorial-advanced-text)] transition transform group-hover:translate-x-1" })
2086                      ] }),
2087                      /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "font-extrabold text-sm text-[var(--daw-text)]", children: "Schumann's Widmung" }),
2088                      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-[var(--daw-text-secondary)] leading-normal", children: "Full 228-step transcription workflow of Robert Schumann's love song. Learn key modulation, ties, indents, and full engraving details." })
2089                    ]
2090                  }
2091                )
2092              ] })
2093            ] })
2094          ]
2095        }
2096      )
2097    ] });
2098  }
2099  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2100    /* @__PURE__ */ jsxRuntimeExports.jsxs(
2101      "div",
2102      {
2103        className: `relative h-full z-[150] flex transition-all duration-300 border-l border-[var(--daw-border-strong)] ${isCollapsed ? "w-10" : "w-80 md:w-96"}`,
2104        children: [
2105          /* @__PURE__ */ jsxRuntimeExports.jsx(
2106            "button",
2107            {
2108              onClick: () => setIsCollapsed(!isCollapsed),
2109              className: "w-10 bg-[var(--daw-surface)] border-l border-[var(--daw-border-strong)] flex items-center justify-center text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)] cursor-pointer h-16 self-center rounded-l-xl -ml-px shadow-2xl",
2110              children: isCollapsed ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: "w-5 h-5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-5 h-5" })
2111            }
2112          ),
2113          /* @__PURE__ */ jsxRuntimeExports.jsxs(
2114            "div",
2115            {
2116              className: `flex-1 flex flex-col min-h-0 border-l border-[var(--daw-border-strong)] shadow-2xl ${isCollapsed ? "hidden" : "flex"}`,
2117              style: { backgroundColor: "var(--daw-bg)", color: "var(--daw-text)" },
2118              children: [
2119                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 border-b border-[var(--daw-border-strong)] flex items-center justify-between", style: { backgroundColor: "var(--daw-header)" }, children: [
2120                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2.5", children: [
2121                    /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { className: "w-5 h-5 text-blue-500" }),
2122                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-sm tracking-wide text-[var(--daw-text)] uppercase", children: lessonType === "simple" ? "📘 Simple Lesson" : "Guided Tutorial" })
2123                  ] }),
2124                  /* @__PURE__ */ jsxRuntimeExports.jsx(
2125                    "button",
2126                    {
2127                      onClick: onExit,
2128                      className: "text-xs font-semibold px-2.5 py-1 rounded bg-[var(--tutorial-exit-bg,theme(colors.red.600))] border border-[var(--tutorial-exit-border,theme(colors.red.700))] hover:bg-[var(--tutorial-exit-hover-bg,theme(colors.red.500))] text-white transition cursor-pointer",
2129                      children: "Exit"
2130                    }
2131                  )
2132                ] }),
2133                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex p-1 border-b border-[var(--daw-border-strong)]", style: { backgroundColor: "var(--daw-elevated)" }, children: [
2134                  /* @__PURE__ */ jsxRuntimeExports.jsxs(
2135                    "button",
2136                    {
2137                      onClick: () => setActiveTab("steps"),
2138                      className: `flex-1 py-2 text-xs font-bold rounded-lg transition-all flex items-center justify-center space-x-2 ${activeTab === "steps" ? "bg-[var(--daw-surface)] text-[var(--daw-text)] shadow-md font-extrabold border border-[var(--daw-border)]" : "text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)]"}`,
2139                      children: [
2140                        /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { className: "w-3.5 h-3.5" }),
2141                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Steps" })
2142                      ]
2143                    }
2144                  ),
2145                  /* @__PURE__ */ jsxRuntimeExports.jsxs(
2146                    "button",
2147                    {
2148                      onClick: () => setActiveTab("original"),
2149                      className: `flex-1 py-2 text-xs font-bold rounded-lg transition-all flex items-center justify-center space-x-2 ${activeTab === "original" ? "bg-[var(--daw-surface)] text-[var(--daw-text)] shadow-md font-extrabold border border-[var(--daw-border)]" : "text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)]"}`,
2150                      children: [
2151                        /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { className: "w-3.5 h-3.5" }),
2152                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lessonType === "simple" ? "Helper Guide" : "Original Score" })
2153                      ]
2154                    }
2155                  )
2156                ] }),
2157                activeTab === "steps" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0 justify-between overflow-hidden", children: [
2158                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-5 space-y-5", children: [
2159                    /* @__PURE__ */ jsxRuntimeExports.jsxs(
2160                      "div",
2161                      {
2162                        className: "p-4 rounded-xl border relative overflow-hidden",
2163                        style: {
2164                          backgroundColor: "var(--daw-surface)",
2165                          borderColor: lessonType === "simple" ? "#10b98125" : "var(--daw-border-strong)"
2166                        },
2167                        children: [
2168                          lessonType === "simple" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute right-2 top-2 text-emerald-500/25 rotate-12", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Star, { className: "w-12 h-12 fill-current" }) }),
2169                          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-[10px] font-bold uppercase tracking-widest block mb-1 ${lessonType === "simple" ? "text-emerald-600 dark:text-emerald-400" : "text-blue-600 dark:text-blue-400"}`, children: [
2170                            "Chapter ",
2171                            currentChapterIndex + 1,
2172                            " of ",
2173                            activeScript.length
2174                          ] }),
2175                          /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-extrabold text-base text-[var(--daw-text)] mb-1", children: currentChapter.title }),
2176                          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-[var(--daw-text-secondary)] font-medium leading-relaxed", children: lessonType === "simple" ? filterVocabulary(currentChapter.description, true) : currentChapter.description }),
2177                          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3.5 pt-3 border-t border-[var(--daw-border)] flex justify-between items-center text-[10px] text-[var(--daw-text-secondary)] font-bold uppercase", children: [
2178                            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Skill Focus:" }),
2179                            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[var(--daw-text)]", children: lessonType === "simple" ? filterVocabulary(currentChapter.skillLearned, true) : currentChapter.skillLearned })
2180                          ] })
2181                        ]
2182                      }
2183                    ),
2184                    /* @__PURE__ */ jsxRuntimeExports.jsxs(
2185                      "div",
2186                      {
2187                        className: `p-4 rounded-xl border relative shadow-2xl transition-all duration-300 ${isSpeaking ? lessonType === "simple" ? theme === "light" || theme === "retro" ? "bg-emerald-50 border-emerald-500 ring-2 ring-emerald-500/20 scale-[1.02] shadow-[0_0_15px_rgba(16,185,129,0.2)] text-emerald-950" : "bg-emerald-950/25 border-emerald-450 ring-2 ring-emerald-500/20 scale-[1.02] shadow-[0_0_15px_rgba(16,185,129,0.3)] text-zinc-100" : theme === "light" || theme === "retro" ? "bg-indigo-50 border-indigo-500 ring-2 ring-indigo-500/20 scale-[1.02] shadow-[0_0_15px_rgba(99,102,241,0.2)] text-indigo-950" : "bg-[#1e1a38] border-indigo-400 ring-2 ring-indigo-500/20 scale-[1.02] shadow-[0_0_15px_rgba(99,102,241,0.3)] text-zinc-100" : lessonType === "simple" ? theme === "light" || theme === "retro" ? "bg-emerald-50/50 border-emerald-200 text-emerald-950" : "bg-emerald-950/15 border-emerald-500/30 text-zinc-100" : theme === "light" || theme === "retro" ? "bg-indigo-50/50 border-indigo-200 text-indigo-950" : "bg-[#161427] border-[#3b327b] text-zinc-100"}`,
2188                        children: [
2189                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[9px] font-bold uppercase tracking-wider block mb-2 ${lessonType === "simple" ? "text-emerald-600 dark:text-emerald-400" : "text-indigo-600 dark:text-indigo-400"}`, children: isCompleted ? "Lesson Complete!" : `Step ${currentStepIndex + 1} of ${currentChapter.steps.length}` }),
2190                          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs leading-relaxed font-bold text-[var(--daw-text)]", children: isCompleted ? lessonType === "simple" ? "Amazing! You finished Mary Had a Little Lamb! 🎉" : "Congratulations! You have completed the Schumann Widmung tutorial." : lessonType === "simple" && (currentStep == null ? void 0 : currentStep.kidFriendlyInstruction) ? filterVocabulary(currentStep.kidFriendlyInstruction, true) : currentStep == null ? void 0 : currentStep.instruction }),
2191                          isCompleted && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2192                            "button",
2193                            {
2194                              onClick: onExit,
2195                              className: "w-full py-2.5 bg-emerald-600 hover:bg-emerald-500 text-white rounded-lg text-xs font-bold transition shadow-md shadow-emerald-900/30 cursor-pointer text-center",
2196                              children: "Finish & Start Editing"
2197                            }
2198                          ) }),
2199                          !isCompleted && (currentStep == null ? void 0 : currentStep.detailHtml) && /* @__P
2199URE__ */ jsxRuntimeExports.jsx(
2200                            "div",
2201                            {
2202                              className: "mt-3 text-[var(--daw-text-secondary)] text-[11px] leading-relaxed",
2203                              dangerouslySetInnerHTML: {
2204                                __html: lessonType === "simple" ? filterVocabulary(currentStep.detailHtml, true) : currentStep.detailHtml
2205                              }
2206                            }
2207                          )
2208                        ]
2209                      }
2210                    ),
2211                    !isCompleted && isStuckHintVisible && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `p-3.5 rounded-xl border flex flex-col space-y-2 animate-fade-in ${theme === "light" || theme === "retro" ? "bg-blue-50 border-blue-200" : "bg-blue-950/10 border-blue-500/20"}`, children: [
2212                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start space-x-2", children: [
2213                        /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { className: "w-4 h-4 text-blue-400 shrink-0 mt-0.5" }),
2214                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
2215                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-blue-400 uppercase tracking-wider block mb-0.5", children: mode === "watch" ? "Watching Step" : "Stuck?" }),
2216                          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[var(--daw-text)] text-xs font-semibold leading-normal", children: mode === "watch" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2217                            "Watching this step... Click ",
2218                            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-[var(--daw-text-secondary)] font-bold", children: "Skip" }),
2219                            " to proceed, or switch to ",
2220                            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-blue-500 font-bold", children: "Guided Mode" }),
2221                            "."
2222                          ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2223                            "Click ",
2224                            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-blue-500 font-bold", children: "Show Me" }),
2225                            " to watch this step, or ",
2226                            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-[var(--daw-text-secondary)] font-bold", children: "Skip" }),
2227                            " to proceed."
2228                          ] }) })
2229                        ] })
2230                      ] }),
2231                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex space-x-2 pt-1", children: [
2232                        mode === "watch" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
2233                          "button",
2234                          {
2235                            onClick: () => setMode("guided"),
2236                            className: "px-3 py-1.5 bg-blue-600 hover:bg-blue-500 text-white rounded-lg text-[10px] font-bold transition cursor-pointer flex items-center gap-1.5 shadow-md shadow-blue-900/25 active:scale-95",
2237                            children: [
2238                              /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "w-3 h-3 fill-current" }),
2239                              " Guided Mode"
2240                            ]
2241                          }
2242                        ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
2243                          "button",
2244                          {
2245                            onClick: showMeThisStep,
2246                            className: "px-3 py-1.5 bg-blue-600 hover:bg-blue-500 text-white rounded-lg text-[10px] font-bold transition cursor-pointer flex items-center gap-1.5 shadow-md shadow-blue-900/25 active:scale-95",
2247                            children: [
2248                              /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "w-3 h-3 fill-current" }),
2249                              " Show Me"
2250                            ]
2251                          }
2252                        ),
2253                        /* @__PURE__ */ jsxRuntimeExports.jsx(
2254                          "button",
2255                          {
2256                            onClick: skipStep,
2257                            className: "px-3 py-1.5 bg-[var(--daw-surface)] hover:bg-[var(--daw-elevated)] text-[var(--daw-text)] rounded-lg text-[10px] font-bold border border-[var(--daw-border-strong)] transition cursor-pointer active:scale-95",
2258                            children: "Skip →"
2259                          }
2260                        )
2261                      ] })
2262                    ] }),
2263                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2.5 pt-2", children: [
2264                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-bold text-[var(--daw-text-secondary)] uppercase tracking-wider block", children: "Chapters Navigation" }),
2265                      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1.5 max-h-48 overflow-y-auto pr-1", children: activeScript.map((ch, idx) => {
2266                        const isActive = idx === currentChapterIndex;
2267                        const isPrevChapterCompleted = idx < currentChapterIndex;
2268                        const isLight = theme === "light" || theme === "retro";
2269                        let bg = "var(--daw-surface)";
2270                        let border = "1px solid var(--daw-border-strong)";
2271                        let color = "var(--daw-text-secondary)";
2272                        if (isActive) {
2273                          if (isLight) {
2274                            bg = lessonType === "simple" ? "rgba(16, 185, 129, 0.15)" : "rgba(59, 130, 246, 0.15)";
2275                            border = lessonType === "simple" ? "1px solid rgba(16, 185, 129, 0.6)" : "1px solid rgba(59, 130, 246, 0.6)";
2276                            color = lessonType === "simple" ? "#047857" : "#1d4ed8";
2277                          } else {
2278                            bg = lessonType === "simple" ? "rgba(16, 185, 129, 0.12)" : "rgba(59, 130, 246, 0.12)";
2279                            border = lessonType === "simple" ? "1px solid rgba(16, 185, 129, 0.4)" : "1px solid rgba(59, 130, 246, 0.4)";
2280                            color = lessonType === "simple" ? "#6ee7b7" : "#93c5fd";
2281                          }
2282                        } else if (isPrevChapterCompleted) {
2283                          if (isLight) {
2284                            bg = "rgba(16, 185, 129, 0.1)";
2285                            border = "1px solid rgba(16, 185, 129, 0.4)";
2286                            color = "#059669";
2287                          } else {
2288                            bg = "rgba(16, 185, 129, 0.08)";
2289                            border = "1px solid rgba(16, 185, 129, 0.25)";
2290                            color = "#34d399";
2291                          }
2292                        }
2293                        return /* @__PURE__ */ jsxRuntimeExports.jsxs(
2294                          "button",
2295                          {
2296                            onClick: () => jumpToChapter(idx),
2297                            className: "w-full flex items-center justify-between p-2.5 rounded-lg text-[11px] font-semibold transition cursor-pointer",
2298                            style: { backgroundColor: bg, border, color },
2299                            children: [
2300                              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
2301                                isPrevChapterCompleted ? lessonType === "simple" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Star, { className: "w-3.5 h-3.5 text-yellow-450 fill-current" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-3.5 h-3.5 text-emerald-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-3.5 h-3.5 rounded-full border text-[8px] flex items-center justify-center ${isActive ? lessonType === "simple" ? "border-emerald-500 text-emerald-555 font-bold" : "border-blue-500 text-blue-550 font-bold" : "border-[var(--daw-border-strong)] text-[var(--daw-text-secondary)]"}`, children: idx + 1 }),
2302                                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate max-w-[200px] font-bold", children: ch.title })
2303                              ] }),
2304                              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] opacity-75 uppercase font-bold", children: ch.skillLearned.split(" ")[0] })
2305                            ]
2306                          },
2307                          ch.id
2308                        );
2309                      }) })
2310                    ] })
2311                  ] }),
2312                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mx-2 mb-3 pb-0.5 shrink-0 relative z-10 border border-[var(--daw-border-strong)] bg-[var(--daw-elevated)] rounded-xl shadow-2xl flex flex-col overflow-hidden transition-all duration-300", children: [
2313                    /* @__PURE__ */ jsxRuntimeExports.jsxs(
2314                      "button",
2315                      {
2316                        onClick: () => setIsPlaybackScrubberExpanded(!isPlaybackScrubberExpanded),
2317                        className: "p-3 w-full flex items-center justify-between text-xs font-bold text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)] hover:bg-[var(--daw-surface)] transition cursor-pointer select-none text-left bg-transparent border-0 outline-none",
2318                        children: [
2319                          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
2320                            /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "w-3.5 h-3.5 fill-current text-blue-500" }),
2321                            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: isPlaybackScrubberExpanded ? "Hide Playback Controls" : "Show Playback Controls" })
2322                          ] }),
2323                          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
2324                            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[10px] text-[var(--daw-text-secondary)]", children: [
2325                              "Step ",
2326                              globalStepIdx + 1,
2327                              "/",
2328                              totalSteps
2329                            ] }),
2330                            isPlaybackScrubberExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-4 h-4 rotate-90 transition-transform duration-200" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-4 h-4 -rotate-90 transition-transform duration-200" })
2331                          ] })
2332                        ]
2333                      }
2334                    ),
2335                    isPlaybackScrubberExpanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 border-t border-[var(--daw-border-strong)] space-y-4", children: [
2336                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
2337                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[9px] font-bold text-[var(--daw-text-secondary)] uppercase select-none", children: [
2338                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Playback Scrubber" }),
2339                          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[var(--daw-text-secondary)]", children: [
2340                            "Step ",
2341                            globalStepIdx + 1,
2342                            "/",
2343                            totalSteps
2344                          ] })
2345                        ] }),
2346                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative pt-1 flex items-center", children: [
2347                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2348                            "input",
2349                            {
2350                              type: "range",
2351                              min: "0",
2352                              max: totalSteps - 1,
2353                              value: globalStepIdx,
2354                              onChange: (e) => jumpToGlobalStep(parseInt(e.target.value, 10)),
2355                              className: "w-full accent-emerald-505 h-1 bg-[var(--daw-inset)] rounded-lg cursor-pointer appearance-none relative z-10"
2356                            }
2357                          ),
2358                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-0 right-0 top-[9px] h-1 bg-[var(--daw-inset)] rounded-lg pointer-events-none" }),
2359                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2360                            "div",
2361                            {
2362                              className: `absolute left-0 top-[9px] h-1 rounded-lg pointer-events-none ${lessonType === "simple" ? "bg-emerald-500" : "bg-blue-500"}`,
2363                              style: { width: `${progressPercent}%` }
2364                            }
2365                          ),
2366                          ticks.map((tick) => {
2367                            var _a;
2368                            return /* @__PURE__ */ jsxRuntimeExports.jsx(
2369                              "div",
2370                              {
2371                                className: `absolute w-1 h-2 -translate-x-1/2 pointer-events-none border-x border-[var(--daw-border-strong)] ${globalStepIdx >= ((_a = ticks.find((t) => t.id === tick.id)) == null ? void 0 : _a.pos) ? "bg-emerald-400 border-emerald-500" : "bg-[var(--daw-inset)] border-[var(--daw-border-strong)]"}`,
2372                                style: { left: `${tick.pos}%` },
2373                                title: tick.title
2374                              },
2375                              tick.id
2376                            );
2377                          })
2378                        ] })
2379                      ] }),
2380                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
2381                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
2382                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2383                            "button",
2384                            {
2385                              onClick: () => handlePrev(),
2386                              className: "flex items-center justify-center w-9 h-9 rounded-lg bg-[var(--daw-surface)] border border-[var(--daw-border-strong)] text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)] cursor-pointer hover:bg-[var(--daw-elevated)] active:scale-95 transition",
2387                              title: "Previous Step (←)",
2388                              children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: "w-5 h-5" })
2389                            }
2390                          ),
2391                          isCompleted ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2392                            "button",
2393                            {
2394                              onClick: () => jumpToGlobalStep(0),
2395                              className: "flex items-center justify-center w-10 h-10 rounded-lg bg-blue-600 hover:bg-blue-500 text-white shadow transition cursor-pointer active:scale-95",
2396                              title: "Restart Lesson",
2397                              children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67" }) })
2398                            }
2399                          ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
2400                            "button",
2401                            {
2402                              onClick: () => setIsPlaying(!isPlaying),
2403                              "data-testid": "tutorial-play-btn",
2404                              className: `flex items-center justify-center w-10 h-10 rounded-lg text-white shadow transition cursor-pointer active:scale-95 ${isPlaying ? "bg-amber-600 hover:bg-amber-500 shadow-amber-600/30" : "bg-emerald-600 hover:bg-emerald-500 shadow-emerald-600/30"}`,
2405                              title: isPlaying ? "Pause Lesson (Space)" : "Play/Watch Lesson (Space)",
2406                              children: isPlaying ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { className: "w-5 h-5 fill-current" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "w-5 h-5 fill-current" })
2407                            }
2408                          ),
2409                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2410                            "button",
2411                            {
2412                              onClick: () => handleNext(),
2413                              className: "flex items-center justify-center w-9 h-9 rounded-lg bg-[var(--daw-surface)] border border-[var(--daw-border-strong)] text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)] cursor-pointer hover:bg-[var(--daw-elevated)] active:scale-95 transition",
2414                              title: "Next Step (→)",
2415                              children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-5 h-5" })
2416                            }
2417                          )
2418                        ] }),
2419                        /* @__PURE__ */ jsxRuntimeExports.jsx(
2420                          "button",
2421                          {
2422                            onClick: () => setUseTts(!useTts),
2423                            className: `flex items-center justify-center w-9 h-9 rounded-lg border transition cursor-pointer active:scale-95 ${useTts ? "bg-emerald-600/10 border-emerald-500/30 text-emerald-700 dark:text-emerald-400 hover:bg-emerald-600/20" : "bg-[var(--daw-surface)] border-[var(--daw-border-strong)] text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)]"}`,
2424                            title: useTts ? "Voice Narration is ON (Click to mute)" : "Voice Narration is MUTED (Click to unmute)",
2425                            children: useTts ? /* @__PURE__ */ jsxRuntimeExports.jsx(Volume2, { className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(VolumeX, { className: "w-4 h-4" })
2426                          }
2427                        ),
2428                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-[var(--daw-inset)] p-1 rounded-lg border border-[var(--daw-border-strong)]", children: [
2429                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2430                            "button",
2431                            {
2432                              onClick: () => setMode("guided"),
2433                              "data-testid": "mode-guided-btn",
2434                              className: `px-3 py-1 rounded text-[10px] font-bold transition-all cursor-pointer ${mode === "guided" ? "bg-blue-600 text-white shadow-md" : "text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)]"}`,
2435                              title: "Guided Practice: Follow targets at your own pace",
2436                              children: "🎯 Guided"
2437                            }
2438                          ),
2439                          /* @__PURE__ */ jsxRuntimeExports.jsx(
2440                            "button",
2441                            {
2442                              onClick: () => setMode("watch"),
2443                              "data-testid": "mode-watch-btn",
2444                              className: `px-3 py-1 rounded text-[10px] font-bold transition-all cursor-pointer ${mode === "watch" ? "bg-indigo-600 text-white shadow-md" : "text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)]"}`,
2445                              title: "Watch Mode: Sit back and watch with auto-play and narration",
2446                              children: "🎬 Watch"
2447                            }
2448                          )
2449                        ] })
2450                      ] }),
2451                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
2452                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[9px] font-bold text-[var(--daw-text-secondary)] uppercase select-none", children: [
2453                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Speed Limit" }),
2454                          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-emerald-400", children: [
2455                            speed,
2456                            "x"
2457                          ] })
2458                        ] }),
2459                        /* @__PURE__ */ jsxRuntimeExports.jsx(
2460                          "input",
2461                          {
2462                            type: "range",
2463                            min: "0",
2464                            max: "3",
2465                            value: speed === 0.5 ? 0 : speed === 1 ? 1 : speed === 2 ? 2 : 3,
2466                            onChange: (e) => {
2467                              const val = parseInt(e.target.value, 10);
2468                              const speeds = [0.5, 1, 2, 8];
2469                              setSpeed(speeds[val]);
2470                            },
2471                            className: "w-full accent-emerald-500 h-1 bg-[var(--daw-inset)] rounded-lg cursor-pointer"
2472                          }
2473                        ),
2474                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[8px] font-bold text-[var(--daw-text-secondary)] select-none", children: [
2475                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: speed === 0.5 ? "text-emerald-400 font-extrabold" : "", children: "Slow (0.5x)" }),
2476                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: speed === 1 ? "text-emerald-400 font-extrabold" : "", children: "Normal (1x)" }),
2477                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: speed === 2 ? "text-emerald-400 font-extrabold" : "", children: "Fast (2x)" }),
2478                          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: speed === 8 ? "text-emerald-400 font-extrabold" : "", children: "Showcase (8x)" })
2479                        ] })
2480                      ] }),
2481                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-[9px] text-[var(--daw-text-secondary)] font-bold border-t border-[var(--daw-border-strong)] pt-2 flex justify-center items-center gap-1 select-none", children: [
2482                        /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { className: "px-1 bg-[var(--daw-inset)] rounded border border-[var(--daw-border-strong)] text-[var(--daw-text)]", children: "Space" }),
2483                        " Play/Pause ·",
2484                        /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { className: "px-1 bg-[var(--daw-inset)] rounded border border-[var(--daw-border-strong)] text-[var(--daw-text)]", children: "←" }),
2485                        " / ",
2486                        /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { className: "px-1 bg-[var(--daw-inset)] rounded border border-[var(--daw-border-strong)] text-[var(--daw-text)]", children: "→" }),
2487                        " Step"
2488                      ] })
2489                    ] })
2490                  ] })
2491                ] }),
2492                activeTab === "original" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex flex-col p-5 overflow-y-auto space-y-4", children: lessonType === "simple" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2493                  /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "font-extrabold text-xs text-[var(--daw-text-secondary)] uppercase tracking-widest flex items-center gap-1", children: [
2494                    /* @__PURE__ */ jsxRuntimeExports.jsx(Star, { className: "w-3.5 h-3.5 fill-current text-yellow-450" }),
2495                    " Simple Song Guide"
2496                  ] }),
2497                  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] leading-relaxed text-[var(--daw-text-secondary)]", children: [
2498                    "Here is a visual map of the notes we are writing for ",
2499                    /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Mary Had a Little Lamb" }),
2500                    ". Tap the notes or look at the sheet to help you place your notes!"
2501                  ] }),
2502                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-emerald-200 dark:border-emerald-500/20 rounded-xl bg-emerald-50/40 dark:bg-emerald-950/10 p-4 space-y-3 shadow-sm dark:shadow-xl", children: [
2503                    /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-serif font-black text-sm text-center text-[var(--daw-text)] tracking-wide uppercase", children: "Mary Had a Little Lamb" }),
2504                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3.5 py-2 select-none", children: [
2505                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-[var(--daw-border)] w-full h-px relative py-1", children: [
2506                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-bold text-[var(--daw-text)] block mb-1", children: "Measure 1: Ma - ry had a" }),
2507                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-mono text-xs px-2 py-0.5 rounded font-bold border ${theme === "light" || theme === "retro" ? "bg-emerald-50 border-emerald-200 text-emerald-700" : "bg-zinc-900 border-zinc-800 text-emerald-400"}`, children: "E - D - C - D" }),
2508                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-[var(--daw-text-secondary)] block mt-1", children: "(Four black quarter notes)" })
2509                      ] }),
2510                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-[var(--daw-border)] w-full h-px relative py-1", children: [
2511                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-bold text-[var(--daw-text)] block mb-1", children: "Measure 2: lit - tle lamb" }),
2512                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-mono text-xs px-2 py-0.5 rounded font-bold border ${theme === "light" || theme === "retro" ? "bg-emerald-50 border-emerald-200 text-emerald-700" : "bg-zinc-900 border-zinc-800 text-emerald-400"}`, children: "E - E - E (holds)" }),
2513                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-[var(--daw-text-secondary)] block mt-1", children: "(Two quarter notes, one half note)" })
2514                      ] })
2515                    ] })
2516                  ] })
2517                ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2518                  /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "font-extrabold text-xs text-[var(--daw-text)] uppercase tracking-widest", children: "Breitkopf & Härtel 1887 Edition" }),
2519                  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] leading-relaxed text-[var(--daw-text-secondary)]", children: `This guided lesson transcribes Robert Schumann's "Widmung" arr. by Clara Schumann. Below is the original score sheet and a reference of the original layout goals (A-flat major, flat-cancellations, Breitkopf system indents).` }),
2520                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border border-[var(--daw-border-strong)] rounded-xl bg-[var(--daw-inset)] p-2 shadow-xl flex flex-col items-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2521                    "img",
2522                    {
2523                      src: "/assets/schumann_widmung_original.jpg",
2524                      alt: "Schumann/Clara Schumann Widmung Breitkopf 1887 Original Score",
2525                      className: "w-full h-auto rounded-lg object-contain border border-[var(--daw-border-strong)]"
2526                    }
2527                  ) }),
2528                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-[var(--daw-border-strong)] rounded-xl bg-[var(--daw-surface)] p-4 space-y-4 shadow-xl", children: [
2529                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-end border-b border-[var(--daw-border-strong)] pb-2", children: [
2530                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
2531                        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-serif font-black text-sm text-[var(--daw-text)] tracking-wide uppercase", children: "Widmung." }),
2532                        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[9px] italic text-[var(--daw-text-secondary)] font-medium", children: "Liederkreis von Friedrich Rückert, Op. 25" })
2533                      ] }),
2534                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [
2535                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-serif text-[var(--daw-text-secondary)] block", children: "ROBERT SCHUMANN" }),
2536                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] font-serif text-[var(--daw-text-secondary)] uppercase tracking-wider block", children: "Arr. Clara Schumann" })
2537                      ] })
2538                    ] }),
2539                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3.5 py-2 select-none", children: [
2540                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1 opacity-85", children: [
2541                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] font-bold text-[var(--daw-text-secondary)] uppercase tracking-wider block", children: "System 1: Indent (X = 350)" }),
2542                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-[var(--daw-border-strong)] w-full h-px relative", children: [
2543                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-8 right-0 border-t border-zinc-500/30 h-px top-1" }),
2544                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-8 right-0 border-t border-zinc-500/30 h-px top-2" }),
2545                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-8 right-0 border-t border-zinc-500/30 h-px top-3" }),
2546                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-8 right-0 border-t border-zinc-500/30 h-px top-4" }),
2547                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-10 text-[9px] font-serif text-blue-500/90 top-0.5", children: "♭♭♭♭" }),
2548                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-20 text-[9px] font-bold text-emerald-500/90 top-0.5", children: "3/2" })
2549                        ] })
2550                      ] }),
2551                      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1 opacity-85", children: [
2552                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] font-bold text-[var(--daw-text-secondary)] uppercase tracking-wider block", children: "System 4: Key Change (Measure 14)" }),
2553                        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-[var(--daw-border-strong)] w-full h-px relative", children: [
2554                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-0 right-0 border-t border-zinc-500/30 h-px top-1" }),
2555                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-0 right-0 border-t border-zinc-500/30 h-px top-2" }),
2556                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-0 right-0 border-t border-zinc-500/30 h-px top-3" }),
2557                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute right-24 text-[9px] font-serif text-amber-500/95 top-0.5", children: "♮♮♮♮" }),
2558                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute right-14 text-[9px] font-serif text-orange-550/95 top-0.5", children: "♯♯♯♯" }),
2559                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute right-4 text-[9px] font-bold text-[var(--daw-text-secondary)] top-0.5", children: "||" })
2560                        ] })
2561                      ] })
2562                    ] }),
2563                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pt-2 border-t border-[var(--daw-border-strong)] flex items-center justify-between text-[8px] text-[var(--daw-text-secondary)] font-bold uppercase tracking-wider", children: [
2564                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Leipzig Edition (1887)" }),
2565                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Opus 25 Nr. 1" })
2566                    ] })
2567                  ] })
2568                ] }) }),
2569                /* @__PURE__ */ jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: `
2570            @keyframes fadeIn {
2571              from { opacity: 0; transform: translateY(-4px); }
2572              to { opacity: 1; transform: translateY(0); }
2573            }
2574            .animate-fade-in {
2575              animation: fadeIn 0.2s ease-out forwards;
2576            }
2577          ` } })
2578              ]
2579            }
2580          )
2581        ]
2582      }
2583    ),
2584    isCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsxs(
2585      "div",
2586      {
2587        className: "fixed bottom-6 left-1/2 transform -translate-x-1/2 z-[200] flex items-center space-x-4 bg-[var(--daw-elevated)] border border-[var(--daw-border-strong)] px-5 py-3 rounded-full shadow-2xl backdrop-blur-md animate-fade-in",
2588        style: { minWidth: "420px", maxWidth: "650px" },
2589        children: [
2590          isCompleted ? /* @__PURE__ */ jsxRuntimeExports.jsx(
2591            "button",
2592            {
2593              onClick: () => jumpToGlobalStep(0),
2594              className: "flex items-center justify-center w-8 h-8 rounded-full text-white bg-blue-600 hover:bg-blue-500 shadow shadow-blue-600/20 transition cursor-pointer shrink-0",
2595              title: "Restart Tutorial",
2596              children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67" }) })
2597            }
2598          ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
2599            "button",
2600            {
2601              onClick: () => {
2602                if (mode === "guided") {
2603                  setMode("watch");
2604                  setIsPlaying(true);
2605                } else {
2606                  setIsPlaying(!isPlaying);
2607                }
2608              },
2609              className: `flex items-center justify-center w-8 h-8 rounded-full text-white shadow transition cursor-pointer shrink-0 ${mode === "guided" ? "bg-blue-600 hover:bg-blue-500 shadow-blue-600/20" : isPlaying ? "bg-amber-600 hover:bg-amber-500 shadow-amber-600/20" : "bg-emerald-600 hover:bg-emerald-500 shadow-emerald-600/20"}`,
2610              title: mode === "guided" ? "Switch to Watch Mode & Play" : isPlaying ? "Pause Playback" : "Start Playback",
2611              children: mode === "guided" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "w-3.5 h-3.5 fill-current" }) : isPlaying ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "w-3.5 h-3.5 fill-current" })
2612            }
2613          ),
2614          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
2615            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[9px] font-bold uppercase tracking-widest block mb-0.5 select-none ${isCompleted ? "text-emerald-600 dark:text-emerald-400" : mode === "guided" ? "text-emerald-600 dark:text-emerald-400" : "text-amber-600 dark:text-amber-400"}`, children: isCompleted ? "Lesson Complete!" : mode === "guided" ? `🎯 Guided Lesson (${globalStepIdx + 1}/${totalSteps})` : `🎬 Watch Mode (${globalStepIdx + 1}/${totalSteps})` }),
2616            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[var(--daw-text)] text-xs font-semibold truncate", title: isCompleted ? "Finished!" : getStepInstruction(currentStep), children: isCompleted ? "Congratulations! 🎉" : getStepInstruction(currentStep) })
2617          ] }),
2618          /* @__PURE__ */ jsxRuntimeExports.jsx(
2619            "button",
2620            {
2621              onClick: () => setIsCollapsed(false),
2622              className: "text-xs text-[var(--daw-text-secondary)] hover:text-[var(--daw-text)] font-bold bg-[var(--daw-surface)] border border-[var(--daw-border-strong)] px-3 py-1.5 rounded-full transition cursor-pointer shrink-0 select-none",
2623              children: "Details"
2624            }
2625          ),
2626          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-4 border-l border-[var(--daw-border-strong)] shrink-0" }),
2627          /* @__PURE__ */ jsxRuntimeExports.jsx(
2628            "button",
2629            {
2630              onClick: onExit,
2631              className: "text-xs text-red-400 hover:text-red-300 font-bold bg-red-950/20 border border-red-900/40 px-3 py-1.5 rounded-full transition cursor-pointer shrink-0 select-none",
2632              children: isCompleted ? "Start Editing" : "Exit"
2633            }
2634          )
2635        ]
2636      }
2637    )
2638  ] });
2639};
2640const VirtualCursor = ({
2641  targetSelector,
2642  clickTriggered = false,
2643  clickType = "left",
2644  speedMultiplier = 1
2645}) => {
2646  const [position, setPosition] = reactExports.useState({ x: -100, y: -100 });
2647  const [isVisible, setIsVisible] = reactExports.useState(false);
2648  const [ripples, setRipples] = reactExports.useState([]);
2649  const cursorRef = reactExports.useRef(null);
2650  const rippleIdRef = reactExports.useRef(0);
2651  reactExports.useEffect(() => {
2652    if (!targetSelector) {
2653      setIsVisible(false);
2654      return;
2655    }
2656    const updatePosition = () => {
2657      try {
2658        const el = document.querySelector(targetSelector);
2659        if (el) {
2660          const rect = el.getBoundingClientRect();
2661          const centerX = rect.left + rect.width / 2;
2662          const centerY = rect.top + rect.height / 2;
2663          setPosition({ x: centerX, y: centerY });
2664          setIsVisible(true);
2665        } else {
2666          setIsVisible(false);
2667        }
2668      } catch (err) {
2669        setIsVisible(false);
2670      }
2671    };
2672    updatePosition();
2673    const interval = setInterval(updatePosition, 100);
2674    window.addEventListener("resize", updatePosition);
2675    window.addEventListener("scroll", updatePosition, true);
2676    const mutationObserver = new MutationObserver(() => updatePosition());
2677    mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true });
2678    const resizeObserver = new ResizeObserver(() => updatePosition());
2679    resizeObserver.observe(document.body);
2680    return () => {
2681      clearInterval(interval);
2682      window.removeEventListener("resize", updatePosition);
2683      window.removeEventListener("scroll", updatePosition, true);
2684      mutationObserver.disconnect();
2685      resizeObserver.disconnect();
2686    };
2687  }, [targetSelector]);
2688  reactExports.useEffect(() => {
2689    if (clickTriggered && isVisible) {
2690      const id = ++rippleIdRef.current;
2691      setRipples((prev) => [...prev, { id, x: position.x, y: position.y, type: clickType }]);
2692      const duration = Math.max(150, 800 / speedMultiplier);
2693      const timer = setTimeout(() => {
2694        setRipples((prev) => prev.filter((r) => r.id !== id));
2695      }, duration);
2696      return () => clearTimeout(timer);
2697    }
2698  }, [clickTriggered, position, isVisible, clickType, speedMultiplier]);
2699  if (!isVisible) return null;
2700  const rippleDuration = Math.max(0.15, 0.8 / speedMultiplier);
2701  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2702    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 pointer-events-none z-[9999]", children: ripples.map((ripple) => /* @__PURE__ */ jsxRuntimeExports.jsx(
2703      "div",
2704      {
2705        className: `absolute rounded-full border-2 transform -translate-x-1/2 -translate-y-1/2 animate-ping ${ripple.type === "left" ? "border-emerald-500 bg-emerald-500/10" : "border-orange-500 bg-orange-500/10"}`,
2706        style: {
2707          left: ripple.x,
2708          top: ripple.y,
2709          width: "40px",
2710          height: "40px",
2711          animationDuration: `${rippleDuration}s`
2712        }
2713      },
2714      ripple.id
2715    )) }),
2716    /* @__PURE__ */ jsxRuntimeExports.jsx(
2717      "div",
2718      {
2719        ref: cursorRef,
2720        className: "fixed pointer-events-none z-[10000] drop-shadow-[0_4px_8px_rgba(0,0,0,0.5)] select-none",
2721        style: {
2722          left: position.x,
2723          top: position.y,
2724          transform: clickTriggered ? "scale(0.85)" : "scale(1)",
2725          transition: `left ${350 / speedMultiplier}ms cubic-bezier(0.25, 1, 0.5, 1), top ${350 / speedMultiplier}ms cubic-bezier(0.25, 1, 0.5, 1), transform 150ms ease`
2726        },
2727        children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
2728          "svg",
2729          {
2730            width: "24",
2731            height: "24",
2732            viewBox: "0 0 24 24",
2733            fill: "none",
2734            xmlns: "http://www.w3.org/2000/svg",
2735            children: [
2736              /* @__PURE__ */ jsxRuntimeExports.jsx(
2737                "path",
2738                {
2739                  d: "M5.65376 12.3825L19.5602 4.90848C20.3541 4.48192 21.2337 5.25301 20.9163 6.10103L15.3674 20.9234C15.084 21.6806 14.0534 21.7822 13.626 21.0991L10.3628 15.8845L5.35127 13.9142C4.6984 13.6575 4.8703 12.8036 5.65376 12.3825Z",
2740                  fill: "white",
2741                  stroke: "black",
2742                  strokeWidth: "1.5",
2743                  strokeLinejoin: "round"
2744                }
2745              ),
2746              /* @__PURE__ */ jsxRuntimeExports.jsx(
2747                "circle",
2748                {
2749                  cx: "7",
2750                  cy: "13",
2751                  r: "2",
2752                  fill: clickType === "left" ? "#10b981" : "#f97316"
2753                }
2754              )
2755            ]
2756          }
2757        )
2758      }
2759    )
2760  ] });
2761};
2762const TutorialHints = ({
2763  targetSelector,
2764  isActive = false,
2765  speedMultiplier = 1
2766}) => {
2767  const [bounds, setBounds] = reactExports.useState(null);
2768  reactExports.useEffect(() => {
2769    if (!isActive || !targetSelector) {
2770      setBounds(null);
2771      return;
2772    }
2773    const updateBounds = () => {
2774      try {
2775        const el = document.querySelector(targetSelector);
2776        if (el) {
2777          const rect = el.getBoundingClientRect();
2778          if (rect.width > 0 && rect.height > 0) {
2779            setBounds(rect);
2780          } else {
2781            setBounds(null);
2782          }
2783        } else {
2784          setBounds(null);
2785        }
2786      } catch (err) {
2787        setBounds(null);
2788      }
2789    };
2790    updateBounds();
2791    const interval = setInterval(updateBounds, 100);
2792    window.addEventListener("resize", updateBounds);
2793    window.addEventListener("scroll", updateBounds, true);
2794    const mutationObserver = new MutationObserver(() => updateBounds());
2795    mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true });
2796    const resizeObserver = new ResizeObserver(() => updateBounds());
2797    resizeObserver.observe(document.body);
2798    return () => {
2799      clearInterval(interval);
2800      window.removeEventListener("resize", updateBounds);
2801      window.removeEventListener("scroll", updateBounds, true);
2802      mutationObserver.disconnect();
2803      resizeObserver.disconnect();
2804    };
2805  }, [targetSelector, isActive]);
2806  if (!isActive || !bounds) return null;
2807  const pingDuration = Math.max(0.25, 1.5 / speedMultiplier);
2808  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2809    /* @__PURE__ */ jsxRuntimeExports.jsx(
2810      "div",
2811      {
2812        className: "fixed inset-0 pointer-events-auto z-[140] bg-zinc-950/60 mix-blend-multiply transition-opacity duration-300",
2813        style: {
2814          clipPath: `polygon(
2815            0% 0%, 
2816            0% 100%, 
2817            ${bounds.left}px 100%, 
2818            ${bounds.left}px ${bounds.top}px, 
2819            ${bounds.right}px ${bounds.top}px, 
2820            ${bounds.right}px ${bounds.bottom}px, 
2821            ${bounds.left}px ${bounds.bottom}px, 
2822            ${bounds.left}px 100%, 
2823            100% 100%, 
2824            100% 0%
2825          )`
2826        }
2827      }
2828    ),
2829    /* @__PURE__ */ jsxRuntimeExports.jsx(
2830      "div",
2831      {
2832        className: "fixed z-[145] pointer-events-none border-2 border-blue-500 rounded-lg shadow-[0_0_15px_rgba(59,130,246,0.5)] animate-pulse",
2833        style: {
2834          left: bounds.left - 4,
2835          top: bounds.top - 4,
2836          width: bounds.width + 8,
2837          height: bounds.height + 8,
2838          transition: `all ${Math.max(50, 200 / speedMultiplier)}ms ease-out`
2839        },
2840        children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2841          "div",
2842          {
2843            className: "absolute inset-0 border border-blue-400 rounded-lg animate-ping opacity-60",
2844            style: { animationDuration: `${pingDuration}s` }
2845          }
2846        )
2847      }
2848    )
2849  ] });
2850};
2851const InteractionOverlay = ({
2852  isActive,
2853  targetSelector,
2854  triggerSelector,
2855  promptText,
2856  successMessage,
2857  onComplete
2858}) => {
2859  const [bounds, setBounds] = reactExports.useState(null);
2860  const [triggerBounds, setTriggerBounds] = reactExports.useState(null);
2861  const [showSuccess, setShowSuccess] = reactExports.useState(false);
2862  const [dragPosition, setDragPosition] = reactExports.useState(null);
2863  const [isDragging, setIsDragging] = reactExports.useState(false);
2864  const dragStartRef = reactExports.useRef(null);
2865  const bannerRef = reactExports.useRef(null);
2866  reactExports.useEffect(() => {
2867    setDragPosition(null);
2868    setIsDragging(false);
2869  }, [promptText, targetSelector, triggerSelector]);
2870  const [isFallback, setIsFallback] = reactExports.useState(false);
2871  reactExports.useEffect(() => {
2872    setShowSuccess(false);
2873    if (!isActive) {
2874      setBounds(null);
2875      setTriggerBounds(null);
2876      setIsFallback(false);
2877      return;
2878    }
2879    const getFallbackBounds = () => {
2880      const width = 240;
2881      const height = 120;
2882      const left = Math.max(10, (window.innerWidth - width) / 2);
2883      const top = Math.max(10, (window.innerHeight - height) / 2);
2884      return new DOMRect(left, top, width, height);
2885    };
2886    const updateBounds = () => {
2887      try {
2888        let el = targetSelector ? document.querySelector(targetSelector) : null;
2889        let isMissing = false;
2890        if (el) {
2891          const rect = el.getBoundingClientRect();
2892          if (rect.width > 0 && rect.height > 0) {
2893            setBounds(rect);
2894            setIsFallback(false);
2895          } else {
2896            isMissing = true;
2897          }
2898        } else {
2899          isMissing = true;
2900        }
2901        if (isMissing) {
2902          if (targetSelector) {
2903            setBounds(getFallbackBounds());
2904            setIsFallback(true);
2905          } else {
2906            setBounds(null);
2907            setIsFallback(false);
2908          }
2909        }
2910        if (triggerSelector) {
2911          const triggerEl = document.querySelector(triggerSelector);
2912          if (triggerEl) {
2913            const trRect = triggerEl.getBoundingClientRect();
2914            if (trRect.width > 0 && trRect.height > 0) {
2915              setTriggerBounds(trRect);
2916            } else {
2917              setTriggerBounds(null);
2918            }
2919          } else {
2920            setTriggerBounds(null);
2921          }
2922        } else {
2923          setTriggerBounds(null);
2924        }
2925      } catch (err) {
2926        if (targetSelector) {
2927          setBounds(getFallbackBounds());
2928          setIsFallback(true);
2929        } else {
2930          setBounds(null);
2931        }
2932        setTriggerBounds(null);
2933      }
2934    };
2935    updateBounds();
2936    const interval = setInterval(updateBounds, 100);
2937    window.addEventListener("resize", updateBounds);
2938    window.addEventListener("scroll", updateBounds, true);
2939    const mutationObserver = new MutationObserver(() => updateBounds());
2940    mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true });
2941    const resizeObserver = new ResizeObserver(() => updateBounds());
2942    resizeObserver.observe(document.body);
2943    return () => {
2944      clearInterval(interval);
2945      window.removeEventListener("resize", updateBounds);
2946      window.removeEventListener("scroll", updateBounds, true);
2947      mutationObserver.disconnect();
2948      resizeObserver.disconnect();
2949    };
2950  }, [targetSelector, triggerSelector, isActive]);
2951  const handlePointerDown = (e) => {
2952    var _a, _b;
2953    if (!bannerRef.current) return;
2954    const rect = bannerRef.current.getBoundingClientRect();
2955    dragStartRef.current = {
2956      mouseX: e.clientX,
2957      mouseY: e.clientY,
2958      elemX: rect.left,
2959      elemY: rect.top
2960    };
2961    setIsDragging(true);
2962    (_b = (_a = e.target).setPointerCapture) == null ? void 0 : _b.call(_a, e.pointerId);
2963  };
2964  const handlePointerMove = (e) => {
2965    if (!isDragging || !dragStartRef.current || !bannerRef.current) return;
2966    const deltaX = e.clientX - dragStartRef.current.mouseX;
2967    const deltaY = e.clientY - dragStartRef.current.mouseY;
2968    const bannerRect = bannerRef.current.getBoundingClientRect();
2969    const width = bannerRect.width || 380;
2970    const height = bannerRect.height || 80;
2971    const newX = Math.max(10, Math.min(window.innerWidth - width - 10, dragStartRef.current.elemX + deltaX));
2972    const newY = Math.max(10, Math.min(window.innerHeight - height - 10, dragStartRef.current.elemY + deltaY));
2973    setDragPosition({ x: newX, y: newY });
2974  };
2975  const handlePointerUp = (e) => {
2976    var _a, _b;
2977    if (isDragging) {
2978      setIsDragging(false);
2979      try {
2980        (_b = (_a = e.target).releasePointerCapture) == null ? void 0 : _b.call(_a, e.pointerId);
2981      } catch (err) {
2982      }
2983    }
2984  };
2985  const handleSuccess = reactExports.useCallback(() => {
2986    setShowSuccess(true);
2987    try {
2988      const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
2989      const osc1 = audioCtx.createOscillator();
2990      const osc2 = audioCtx.createOscillator();
2991      const gainNode = audioCtx.createGain();
2992      osc1.connect(gainNode);
2993      osc2.connect(gainNode);
2994      gainNode.connect(audioCtx.destination);
2995      osc1.type = "triangle";
2996      osc2.type = "sine";
2997      const now = audioCtx.currentTime;
2998      osc1.frequency.setValueAtTime(523.25, now);
2999      osc1.frequency.setValueAtTime(659.25, now + 0.1);
3000      osc1.frequency.setValueAtTime(783.99, now + 0.2);
3001      osc1.frequency.setValueAtTime(1046.5, now + 0.3);
3002      osc2.frequency.setValueAtTime(1046.5, now);
3003      osc2.frequency.setValueAtTime(1318.51, now + 0.1);
3004      gainNode.gain.setValueAtTime(0, now);
3005      gainNode.gain.linearRampToValueAtTime(0.15, now + 0.05);
3006      gainNode.gain.exponentialRampToValueAtTime(1e-3, now + 0.8);
3007      osc1.start(now);
3008      osc2.start(now);
3009      osc1.stop(now + 0.8);
3010      osc2.stop(now + 0.8);
3011    } catch (e) {
3012      console.warn("Audio chime playback failed:", e);
3013    }
3014    setTimeout(() => {
3015      setShowSuccess(false);
3016      onComplete();
3017    }, 1500);
3018  }, [onComplete]);
3019  const activeTrigger = triggerSelector || targetSelector;
3020  reactExports.useEffect(() => {
3021    if (!isActive || !activeTrigger || showSuccess) return;
3022    const handleGlobalClick = (e) => {
3023      const targetEl = document.querySelector(activeTrigger);
3024      if (targetEl && (targetEl === e.target || targetEl.contains(e.target))) {
3025        handleSuccess();
3026      }
3027    };
3028    document.addEventListener("click", handleGlobalClick, true);
3029    return () => {
3030      document.removeEventListener("click", handleGlobalClick, true);
3031    };
3032  }, [isActive, activeTrigger, showSuccess, handleSuccess]);
3033  if (!isActive) return null;
3034  if (showSuccess) {
3035    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 bg-black/60 backdrop-blur-sm z-[250] flex flex-col items-center justify-center animate-fade-in pointer-events-auto", children: [
3036      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[var(--daw-elevated)] border border-[var(--daw-border-strong)] rounded-2xl p-8 flex flex-col items-center max-w-sm text-center shadow-2xl space-y-4 animate-scale-up", children: [
3037        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 rounded-full bg-emerald-950/50 border-2 border-emerald-500 flex items-center justify-center text-emerald-450 animate-bounce", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "w-9 h-9" }) }),
3038        /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-emerald-500", children: "Success!" }),
3039        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[var(--daw-text)] text-sm font-semibold", children: successMessage })
3040      ] }),
3041      /* @__PURE__ */ jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: `
3042          @keyframes scaleUp {
3043            from { transform: scale(0.9); opacity: 0; }
3044            to { transform: scale(1); opacity: 1; }
3045          }
3046          .animate-scale-up {
3047            animation: scaleUp 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
3048          }
3049        ` } })
3050    ] });
3051  }
3052  if (!bounds) return null;
3053  const isTriggerInBottomHalf = triggerBounds ? triggerBounds.top > window.innerHeight / 2 : false;
3054  const isTargetInTopHalf = bounds.top < 150;
3055  let positionStyle = {};
3056  let positionClass = "";
3057  if (dragPosition) {
3058    positionStyle = {
3059      left: `${dragPosition.x}px`,
3060      top: `${dragPosition.y}px`,
3061      transform: "none"
3062    };
3063  } else {
3064    if (isTriggerInBottomHalf || bounds.top >= 150) {
3065      positionClass = "top-6 left-1/2 transform -translate-x-1/2";
3066    } else if (isTargetInTopHalf) {
3067      positionClass = "bottom-6 left-1/2 transform -translate-x-1/2";
3068    } else {
3069      positionClass = "top-6 left-1/2 transform -translate-x-1/2";
3070    }
3071  }
3072  const handleOverlayPointerDown = (e) => {
3073    var _a, _b;
3074    const x = e.clientX;
3075    const y = e.clientY;
3076    const isTarget = bounds && x >= bounds.left - 4 && x <= bounds.right + 4 && y >= bounds.top - 4 && y <= bounds.bottom + 4;
3077    const isTrigger = triggerBounds && x >= triggerBounds.left - 4 && x <= triggerBounds.right + 4 && y >= triggerBounds.top - 4 && y <= triggerBounds.bottom + 4;
3078    if (isTarget || isTrigger) {
3079      const overlayEl = e.currentTarget;
3080      overlayEl.style.pointerEvents = "none";
3081      const targetEl = document.elementFromPoint(x, y);
3082      if (targetEl) {
3083        (_a = targetEl.focus) == null ? void 0 : _a.call(targetEl);
3084        (_b = targetEl.click) == null ? void 0 : _b.call(targetEl);
3085      }
3086      setTimeout(() => {
3087        if (overlayEl) overlayEl.style.pointerEvents = "auto";
3088      }, 100);
3089    }
3090  };
3091  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3092    /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "fixed inset-0 w-0 h-0 pointer-events-none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("mask", { id: "interaction-spotlight-mask", maskUnits: "userSpaceOnUse", x: "0", y: "0", width: "100%", height: "100%", children: [
3093      /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "0", y: "0", width: "100%", height: "100%", fill: "white" }),
3094      bounds && /* @__PURE__ */ jsxRuntimeExports.jsx(
3095        "rect",
3096        {
3097          x: bounds.left - 4,
3098          y: bounds.top - 4,
3099          width: bounds.width + 8,
3100          height: bounds.height + 8,
3101          rx: "8",
3102          fill: "black"
3103        }
3104      ),
3105      triggerBounds && /* @__PURE__ */ jsxRuntimeExports.jsx(
3106        "rect",
3107        {
3108          x: triggerBounds.left - 4,
3109          y: triggerBounds.top - 4,
3110          width: triggerBounds.width + 8,
3111          height: triggerBounds.height + 8,
3112          rx: "8",
3113          fill: "black"
3114        }
3115      )
3116    ] }) }) }),
3117    /* @__PURE__ */ jsxRuntimeExports.jsx(
3118      "div",
3119      {
3120        onPointerDown: handleOverlayPointerDown,
3121        className: "fixed inset-0 pointer-events-auto z-[140] bg-black/75 transition-opacity duration-300 select-none",
3122        style: {
3123          maskImage: "url(#interaction-spotlight-mask)",
3124          WebkitMaskImage: "url(#interaction-spotlight-mask)",
3125          clipPath: bounds ? `polygon(
3126            0% 0%, 
3127            0% 100%, 
3128            ${bounds.left}px 100%, 
3129            ${bounds.left}px ${bounds.top}px, 
3130            ${bounds.right}px ${bounds.top}px, 
3131            ${bounds.right}px ${bounds.bottom}px, 
3132            ${bounds.left}px ${bounds.bottom}px, 
3133            ${bounds.left}px 100%, 
3134            100% 100%, 
3135            100% 0%
3136          )` : void 0
3137        }
3138      }
3139    ),
3140    /* @__PURE__ */ jsxRuntimeExports.jsx(
3141      "div",
3142      {
3143        className: "fixed z-[145] pointer-events-none border-2 border-emerald-500 rounded-lg shadow-[0_0_20px_rgba(16,185,129,0.5)] animate-pulse",
3144        style: {
3145          left: bounds.left - 4,
3146          top: bounds.top - 4,
3147          width: bounds.width + 8,
3148          height: bounds.height + 8,
3149          transition: "all 200ms ease-out"
3150        },
3151        children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 border-2 border-emerald-400 rounded-lg animate-ping opacity-60", style: { animationDuration: "1.2s" } })
3152      }
3153    ),
3154    triggerBounds && /* @__PURE__ */ jsxRuntimeExports.jsx(
3155      "div",
3156      {
3157        className: "fixed z-[146] pointer-events-none border-2 border-blue-500 rounded-lg shadow-[0_0_20px_rgba(59,130,246,0.6)] animate-pulse",
3158        style: {
3159          left: triggerBounds.left - 4,
3160          top: triggerBounds.top - 4,
3161          width: triggerBounds.width + 8,
3162          height: triggerBounds.height + 8,
3163          transition: "all 200ms ease-out"
3164        },
3165        children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 border-2 border-blue-400 rounded-lg animate-ping opacity-75", style: { animationDuration: "1s" } })
3166      }
3167    ),
3168    /* @__PURE__ */ jsxRuntimeExports.jsx(
3169      "div",
3170      {
3171        ref: bannerRef,
3172        className: `fixed z-[148] w-[90%] max-w-md animate-fade-in pointer-events-auto select-none ${positionClass}`,
3173        style: positionStyle,
3174        children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[var(--daw-elevated)] border border-[var(--daw-border-strong)] rounded-xl shadow-2xl overflow-hidden backdrop-blur-md", children: [
3175          /* @__PURE__ */ jsxRuntimeExports.jsxs(
3176            "div",
3177            {
3178              onPointerDown: handlePointerDown,
3179              onPointerMove: handlePointerMove,
3180              onPointerUp: handlePointerUp,
3181              className: `px-3 py-1.5 bg-[var(--daw-surface)] border-b border-[var(--daw-border-strong)] flex items-center justify-between text-[10px] font-bold text-emerald-400 uppercase tracking-widest ${isDragging ? "cursor-grabbing" : "cursor-grab"}`,
3182              title: "Click and drag to move this prompt box",
3183              children: [
3184                /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [
3185                  /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { className: "w-3.5 h-3.5 animate-pulse text-emerald-400" }),
3186                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Interactive Challenge" })
3187                ] }),
3188                /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-[var(--daw-text-secondary)] font-normal text-[9px] lowercase opacity-80", children: [
3189                  /* @__PURE__ */ jsxRuntimeExports.jsx(GripHorizontal, { className: "w-3.5 h-3.5" }),
3190                  " drag to move"
3191                ] })
3192              ]
3193            }
3194          ),
3195          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3.5 flex items-center space-x-3", children: [
3196            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 rounded-lg bg-emerald-950/50 border border-emerald-500/20 text-emerald-400 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { className: "w-5 h-5 animate-pulse" }) }),
3197            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[var(--daw-text)] text-xs font-bold leading-relaxed", children: promptText }) })
3198          ] })
3199        ] })
3200      }
3201    )
3202  ] });
3203};
3204const StaffTargetIndicator = ({
3205  targetSelector,
3206  pitchLabel = "C4 (Middle C)",
3207  isActive
3208}) => {
3209  const [rect, setRect] = reactExports.useState(null);
3210  reactExports.useEffect(() => {
3211    if (!isActive) {
3212      setRect(null);
3213      return;
3214    }
3215    const updateBounds = () => {
3216      let el = null;
3217      if (targetSelector) {
3218        try {
3219          el = document.querySelector(targetSelector);
3220        } catch (e) {
3221        }
3222      }
3223      if (!el) {
3224        el = document.querySelector(".selected-note, .notehead, svg .note") || document.querySelector(".daw-desk");
3225      }
3226      if (el) {
3227        const r = el.getBoundingClientRect();
3228        setRect({
3229          left: r.left,
3230          top: r.top,
3231          width: r.width || 40,
3232          height: r.height || 24
3233        });
3234      }
3235    };
3236    updateBounds();
3237    const interval = setInterval(updateBounds, 150);
3238    window.addEventListener("resize", updateBounds);
3239    window.addEventListener("scroll", updateBounds, true);
3240    return () => {
3241      clearInterval(interval);
3242      window.removeEventListener("resize", updateBounds);
3243      window.removeEventListener("scroll", updateBounds, true);
3244    };
3245  }, [targetSelector, isActive]);
3246  if (!isActive || !rect) return null;
3247  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 pointer-events-none z-[9995]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
3248    "div",
3249    {
3250      className: "absolute transition-all duration-300 rounded-md border-2 border-emerald-400 bg-emerald-500/20 shadow-[0_0_20px_rgba(16,185,129,0.6)] animate-pulse flex items-center justify-end pr-2",
3251      style: {
3252        left: `${Math.max(10, rect.left - 20)}px`,
3253        top: `${rect.top - 4}px`,
3254        width: `${Math.max(120, rect.width + 40)}px`,
3255        height: `${Math.max(28, rect.height + 8)}px`
3256      },
3257      children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-extrabold uppercase tracking-wider text-emerald-300 bg-emerald-950/80 px-2 py-0.5 rounded border border-emerald-500/50 shadow", children: [
3258        "🎯 ",
3259        pitchLabel
3260      ] })
3261    }
3262  ) });
3263};
3264const TutorialManager = ({
3265  setHumdrumContent,
3266  humdrumContent,
3267  editorRef,
3268  mode,
3269  playNotePreview,
3270  onExit,
3271  theme = "dark",
3272  tutorialStarted,
3273  setTutorialStarted
3274}) => {
3275  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3276  console.log(`[TutorialManager] Rendering! tutorialStarted=${tutorialStarted}`);
3277  const engine = useTutorialEngine({
3278    setHumdrumContent,
3279    humdrumContent,
3280    editorRef,
3281    mode,
3282    playNotePreview,
3283    onExit,
3284    tutorialStarted,
3285    setTutorialStarted
3286  });
3287  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3288    /* @__PURE__ */ jsxRuntimeExports.jsx(
3289      TutorialPanel,
3290      {
3291        currentChapterIndex: engine.currentChapterIndex,
3292        currentStepIndex: engine.currentStepIndex,
3293        isPlaying: engine.isPlaying,
3294        setIsPlaying: engine.setIsPlaying,
3295        speed: engine.speed,
3296        setSpeed: engine.setSpeed,
3297        useTts: engine.useTts,
3298        setUseTts: engine.setUseTts,
3299        isCompleted: engine.isCompleted,
3300        handleNext: engine.handleNext,
3301        handlePrev: engine.handlePrev,
3302        jumpToChapter: engine.jumpToChapter,
3303        jumpToGlobalStep: engine.jumpToGlobalStep,
3304        getGlobalStepIndex: engine.getGlobalStepIndex,
3305        getGlobalStepCount: engine.getGlobalStepCount,
3306        onExit: engine.onExit,
3307        theme,
3308        autoPlayMode: engine.autoPlayMode,
3309        setAutoPlayMode: engine.setAutoPlayMode,
3310        mode: engine.mode,
3311        setMode: engine.setMode,
3312        isStuckHintVisible: engine.isStuckHintVisible,
3313        showMeThisStep: engine.showMeThisStep,
3314        skipStep: engine.skipStep,
3315        tutorialStarted,
3316        setTutorialStarted,
3317        lessonType: engine.lessonType,
3318        setLessonType: engine.setLessonType,
3319        stepByStepMode: engine.stepByStepMode,
3320        setStepByStepMode: engine.setStepByStepMode,
3321        completedMilestones: engine.completedMilestones,
3322        isSpeaking: engine.isSpeaking
3323      }
3324    ),
3325    (engine.mode === "watch" || engine.isShowMeActive) && !engine.isWaitingForInteraction && /* @__P
3325URE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3326      /* @__PURE__ */ jsxRuntimeExports.jsx(
3327        VirtualCursor,
3328        {
3329          targetSelector: (_b = (_a = engine.currentStep) == null ? void 0 : _a.cursorTarget) == null ? void 0 : _b.selector,
3330          clickTriggered: engine.isPlaying,
3331          clickType: ((_d = (_c = engine.currentStep) == null ? void 0 : _c.action) == null ? void 0 : _d.type) === "click" && engine.currentStep.action.clickType ? engine.currentStep.action.clickType : "left",
3332          speedMultiplier: engine.speed
3333        }
3334      ),
3335      /* @__PURE__ */ jsxRuntimeExports.jsx(
3336        StaffTargetIndicator,
3337        {
3338          targetSelector: (_f = (_e = engine.currentStep) == null ? void 0 : _e.cursorTarget) == null ? void 0 : _f.selector,
3339          pitchLabel: ((_g = engine.currentStep) == null ? void 0 : _g.instruction) || "Pitch Target",
3340          isActive: true
3341        }
3342      )
3343    ] }),
3344    engine.mode === "guided" && !engine.isShowMeActive && !engine.isWaitingForInteraction && /* @__P
3344URE__ */ jsxRuntimeExports.jsx(
3345      TutorialHints,
3346      {
3347        targetSelector: (_i = (_h = engine.currentStep) == null ? void 0 : _h.cursorTarget) == null ? void 0 : _i.selector,
3348        isActive: true,
3349        speedMultiplier: engine.speed
3350      }
3351    ),
3352    engine.isWaitingForInteraction && ((_j = engine.currentStep) == null ? void 0 : _j.interactionMilestone) && /* @__PURE__ */ jsxRuntimeExports.jsx(
3353      InteractionOverlay,
3354      {
3355        isActive: true,
3356        targetSelector: engine.currentStep.interactionMilestone.targetSelector,
3357        triggerSelector: engine.currentStep.interactionMilestone.triggerSelector,
3358        promptText: engine.currentStep.interactionMilestone.promptText,
3359        successMessage: engine.currentStep.interactionMilestone.successMessage,
3360        onComplete: () => {
3361          engine.setIsWaitingForInteraction(false);
3362          engine.handleNext();
3363        }
3364      }
3365    )
3366  ] });
3367};
3368export {
3369  TutorialManager,
3370  TutorialManager as default
3371};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.