torchlit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,577 @@
1
+ import { css, LitElement, html } from "lit";
2
+ import { property, state, customElement } from "lit/decorators.js";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __decorateClass = (decorators, target, key, kind) => {
6
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
7
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
8
+ if (decorator = decorators[i])
9
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
10
+ if (kind && result) __defProp(target, key, result);
11
+ return result;
12
+ };
13
+ let TorchlitOverlay = class extends LitElement {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.snapshot = null;
17
+ this.visible = false;
18
+ this.handleResize = () => {
19
+ if (this.snapshot && this.service) {
20
+ this.snapshot = this.service.getSnapshot();
21
+ }
22
+ };
23
+ this.handleKeydown = (e) => {
24
+ if (!this.snapshot || !this.service) return;
25
+ if (e.key === "Escape") {
26
+ e.preventDefault();
27
+ this.service.skipTour();
28
+ } else if (e.key === "ArrowRight" || e.key === "Enter") {
29
+ e.preventDefault();
30
+ this.service.nextStep();
31
+ } else if (e.key === "ArrowLeft") {
32
+ e.preventDefault();
33
+ this.service.prevStep();
34
+ }
35
+ };
36
+ this.handleBackdropClick = () => {
37
+ this.service?.skipTour();
38
+ };
39
+ }
40
+ /* ── Lifecycle ──────────────────────────────────── */
41
+ connectedCallback() {
42
+ super.connectedCallback();
43
+ if (this.service) {
44
+ this.attachService();
45
+ }
46
+ window.addEventListener("resize", this.handleResize);
47
+ window.addEventListener("keydown", this.handleKeydown);
48
+ }
49
+ disconnectedCallback() {
50
+ super.disconnectedCallback();
51
+ this.unsubscribe?.();
52
+ window.removeEventListener("resize", this.handleResize);
53
+ window.removeEventListener("keydown", this.handleKeydown);
54
+ }
55
+ updated(changed) {
56
+ if (changed.has("service") && this.service) {
57
+ this.unsubscribe?.();
58
+ this.attachService();
59
+ }
60
+ }
61
+ attachService() {
62
+ this.unsubscribe = this.service.subscribe((snap) => this.handleTourChange(snap));
63
+ }
64
+ /* ── Tour state handler ─────────────────────────── */
65
+ async handleTourChange(snapshot) {
66
+ if (!snapshot) {
67
+ this.visible = false;
68
+ setTimeout(() => {
69
+ this.snapshot = null;
70
+ }, 300);
71
+ return;
72
+ }
73
+ if (snapshot.step.beforeShow) {
74
+ try {
75
+ await snapshot.step.beforeShow();
76
+ } catch (err) {
77
+ console.error("[torchlit] beforeShow hook failed:", err);
78
+ }
79
+ }
80
+ if (snapshot.step.route) {
81
+ this.dispatchEvent(new CustomEvent("tour-route-change", {
82
+ detail: { route: snapshot.step.route },
83
+ bubbles: true,
84
+ composed: true
85
+ }));
86
+ await new Promise((r) => setTimeout(r, 350));
87
+ this.snapshot = this.service.getSnapshot();
88
+ } else {
89
+ this.snapshot = snapshot;
90
+ }
91
+ this.scrollTargetIntoView();
92
+ requestAnimationFrame(() => {
93
+ this.visible = true;
94
+ });
95
+ }
96
+ scrollTargetIntoView() {
97
+ if (this.snapshot?.targetElement) {
98
+ this.snapshot.targetElement.scrollIntoView({
99
+ behavior: "smooth",
100
+ block: "center",
101
+ inline: "nearest"
102
+ });
103
+ setTimeout(() => {
104
+ if (this.service) {
105
+ this.snapshot = this.service.getSnapshot();
106
+ }
107
+ }, 400);
108
+ }
109
+ }
110
+ /* ── Tooltip positioning ────────────────────────── */
111
+ getTooltipPosition(rect, placement) {
112
+ const PADDING = this.service?.spotlightPadding ?? 10;
113
+ const GAP = 16;
114
+ const TOOLTIP_W = 320;
115
+ switch (placement) {
116
+ case "right":
117
+ return {
118
+ top: rect.top + rect.height / 2 - 80,
119
+ left: rect.right + PADDING + GAP
120
+ };
121
+ case "left":
122
+ return {
123
+ top: rect.top + rect.height / 2 - 80,
124
+ left: rect.left - PADDING - GAP - TOOLTIP_W
125
+ };
126
+ case "bottom":
127
+ return {
128
+ top: rect.bottom + PADDING + GAP,
129
+ left: rect.left + rect.width / 2 - TOOLTIP_W / 2
130
+ };
131
+ case "top":
132
+ return {
133
+ top: rect.top - PADDING - GAP - 180,
134
+ left: rect.left + rect.width / 2 - TOOLTIP_W / 2
135
+ };
136
+ default:
137
+ return { top: rect.bottom + GAP, left: rect.left };
138
+ }
139
+ }
140
+ clampToViewport(pos) {
141
+ const MARGIN = 16;
142
+ const TOOLTIP_W = 320;
143
+ return {
144
+ top: Math.max(MARGIN, Math.min(pos.top, window.innerHeight - 250)),
145
+ left: Math.max(MARGIN, Math.min(pos.left, window.innerWidth - TOOLTIP_W - MARGIN))
146
+ };
147
+ }
148
+ getArrowClass(placement) {
149
+ switch (placement) {
150
+ case "right":
151
+ return "arrow-right";
152
+ case "left":
153
+ return "arrow-left";
154
+ case "bottom":
155
+ return "arrow-bottom";
156
+ case "top":
157
+ return "arrow-top";
158
+ default:
159
+ return "arrow-bottom";
160
+ }
161
+ }
162
+ /* ── Render ─────────────────────────────────────── */
163
+ render() {
164
+ if (!this.snapshot) return html``;
165
+ const { step, stepIndex, totalSteps, targetRect } = this.snapshot;
166
+ if (!targetRect) {
167
+ return this.renderCenteredStep(step, stepIndex, totalSteps);
168
+ }
169
+ const PADDING = this.service?.spotlightPadding ?? 10;
170
+ const spotlightStyle = `
171
+ top: ${targetRect.top - PADDING}px;
172
+ left: ${targetRect.left - PADDING}px;
173
+ width: ${targetRect.width + PADDING * 2}px;
174
+ height: ${targetRect.height + PADDING * 2}px;
175
+ `;
176
+ const tooltipPos = this.clampToViewport(
177
+ this.getTooltipPosition(targetRect, step.placement)
178
+ );
179
+ const tooltipStyle = `top: ${tooltipPos.top}px; left: ${tooltipPos.left}px;`;
180
+ return html`
181
+ <div
182
+ class="tour-backdrop ${this.visible ? "visible" : ""}"
183
+ part="backdrop"
184
+ @click=${this.handleBackdropClick}
185
+ ></div>
186
+
187
+ <div class="tour-spotlight" part="spotlight" style=${spotlightStyle}></div>
188
+
189
+ <div class="tour-tooltip ${this.visible ? "visible" : ""}" part="tooltip" style=${tooltipStyle}>
190
+ <div class="tour-arrow ${this.getArrowClass(step.placement)}"></div>
191
+
192
+ <div class="tour-step-badge">
193
+ <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.5">
194
+ <circle cx="12" cy="12" r="10"></circle>
195
+ <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
196
+ <line x1="12" y1="17" x2="12.01" y2="17"></line>
197
+ </svg>
198
+ Step ${stepIndex + 1} of ${totalSteps}
199
+ </div>
200
+
201
+ <h3 class="tour-title">${step.title}</h3>
202
+ <p class="tour-message">${step.message}</p>
203
+
204
+ ${this.renderProgressDots(stepIndex, totalSteps)}
205
+
206
+ <div class="tour-footer">
207
+ <button class="tour-skip" @click=${() => this.service.skipTour()}>
208
+ Skip tour
209
+ </button>
210
+ <div class="tour-nav">
211
+ ${stepIndex > 0 ? html`
212
+ <button class="tour-btn" @click=${() => this.service.prevStep()}>
213
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
214
+ <polyline points="15 18 9 12 15 6"></polyline>
215
+ </svg>
216
+ Back
217
+ </button>
218
+ ` : ""}
219
+ <button class="tour-btn primary" @click=${() => this.service.nextStep()}>
220
+ ${stepIndex === totalSteps - 1 ? "Finish" : "Next"}
221
+ ${stepIndex < totalSteps - 1 ? html`
222
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
223
+ <polyline points="9 18 15 12 9 6"></polyline>
224
+ </svg>
225
+ ` : html`
226
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
227
+ <polyline points="20 6 9 17 4 12"></polyline>
228
+ </svg>
229
+ `}
230
+ </button>
231
+ </div>
232
+ </div>
233
+ </div>
234
+ `;
235
+ }
236
+ renderProgressDots(current, total) {
237
+ if (total <= 1) return html``;
238
+ return html`
239
+ <div class="tour-progress">
240
+ ${Array.from({ length: total }, (_, i) => html`
241
+ <div class="tour-dot ${i === current ? "active" : i < current ? "completed" : ""}"></div>
242
+ `)}
243
+ </div>
244
+ `;
245
+ }
246
+ renderCenteredStep(step, stepIndex, totalSteps) {
247
+ return html`
248
+ <div
249
+ class="tour-backdrop ${this.visible ? "visible" : ""}"
250
+ part="backdrop"
251
+ @click=${this.handleBackdropClick}
252
+ ></div>
253
+
254
+ <div class="tour-center-card ${this.visible ? "visible" : ""}" part="center-card">
255
+ <div class="tour-center-icon">
256
+ <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
257
+ <circle cx="12" cy="12" r="10"></circle>
258
+ <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
259
+ <line x1="12" y1="17" x2="12.01" y2="17"></line>
260
+ </svg>
261
+ </div>
262
+
263
+ <h3 class="tour-title">${step.title}</h3>
264
+ <p class="tour-message">${step.message}</p>
265
+
266
+ ${this.renderProgressDots(stepIndex, totalSteps)}
267
+
268
+ <div class="tour-footer">
269
+ <button class="tour-skip" @click=${() => this.service.skipTour()}>
270
+ Skip tour
271
+ </button>
272
+ <div class="tour-nav">
273
+ ${stepIndex > 0 ? html`
274
+ <button class="tour-btn" @click=${() => this.service.prevStep()}>Back</button>
275
+ ` : ""}
276
+ <button class="tour-btn primary" @click=${() => this.service.nextStep()}>
277
+ ${stepIndex === totalSteps - 1 ? "Let's go!" : "Next"}
278
+ ${stepIndex < totalSteps - 1 ? html`
279
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
280
+ <polyline points="9 18 15 12 9 6"></polyline>
281
+ </svg>
282
+ ` : ""}
283
+ </button>
284
+ </div>
285
+ </div>
286
+ </div>
287
+ `;
288
+ }
289
+ };
290
+ TorchlitOverlay.styles = css`
291
+ :host {
292
+ display: block;
293
+ }
294
+
295
+ /* ── Backdrop ──────────────────────────────────── */
296
+
297
+ .tour-backdrop {
298
+ position: fixed;
299
+ inset: 0;
300
+ z-index: 9998;
301
+ pointer-events: auto;
302
+ opacity: 0;
303
+ transition: opacity 0.3s ease;
304
+ }
305
+
306
+ .tour-backdrop.visible {
307
+ opacity: 1;
308
+ }
309
+
310
+ /* ── Spotlight (box-shadow cutout) ─────────────── */
311
+
312
+ .tour-spotlight {
313
+ position: fixed;
314
+ z-index: 9999;
315
+ border-radius: var(--tour-spotlight-radius, var(--radius-lg, 0.75rem));
316
+ box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.55);
317
+ transition: top 0.35s cubic-bezier(0.4, 0, 0.2, 1),
318
+ left 0.35s cubic-bezier(0.4, 0, 0.2, 1),
319
+ width 0.35s cubic-bezier(0.4, 0, 0.2, 1),
320
+ height 0.35s cubic-bezier(0.4, 0, 0.2, 1);
321
+ pointer-events: none;
322
+ }
323
+
324
+ /* Subtle pulsing ring around spotlight */
325
+ .tour-spotlight::after {
326
+ content: '';
327
+ position: absolute;
328
+ inset: -4px;
329
+ border-radius: inherit;
330
+ border: 2px solid var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));
331
+ opacity: 0.5;
332
+ animation: spotlightPulse 2s ease-in-out infinite;
333
+ }
334
+
335
+ @keyframes spotlightPulse {
336
+ 0%, 100% { opacity: 0.3; transform: scale(1); }
337
+ 50% { opacity: 0.7; transform: scale(1.01); }
338
+ }
339
+
340
+ /* ── Tooltip ───────────────────────────────────── */
341
+
342
+ .tour-tooltip {
343
+ position: fixed;
344
+ z-index: 10000;
345
+ width: 320px;
346
+ background: var(--tour-card, var(--card, #fff));
347
+ border: 1px solid var(--tour-border, var(--border, #e5e5e5));
348
+ border-radius: var(--tour-tooltip-radius, var(--radius-lg, 0.75rem));
349
+ box-shadow: 0 20px 40px -8px rgba(0, 0, 0, 0.2),
350
+ 0 8px 16px -4px rgba(0, 0, 0, 0.1);
351
+ padding: 1.25rem;
352
+ pointer-events: auto;
353
+ opacity: 0;
354
+ transform: translateY(8px) scale(0.96);
355
+ transition: opacity 0.25s ease, transform 0.25s ease,
356
+ top 0.35s cubic-bezier(0.4, 0, 0.2, 1),
357
+ left 0.35s cubic-bezier(0.4, 0, 0.2, 1);
358
+ }
359
+
360
+ .tour-tooltip.visible {
361
+ opacity: 1;
362
+ transform: translateY(0) scale(1);
363
+ }
364
+
365
+ /* Arrow */
366
+ .tour-arrow {
367
+ position: absolute;
368
+ width: 12px;
369
+ height: 12px;
370
+ background: var(--tour-card, var(--card, #fff));
371
+ border: 1px solid var(--tour-border, var(--border, #e5e5e5));
372
+ transform: rotate(45deg);
373
+ }
374
+
375
+ .tour-arrow.arrow-top {
376
+ bottom: -7px;
377
+ left: 50%;
378
+ margin-left: -6px;
379
+ border-top: none;
380
+ border-left: none;
381
+ }
382
+
383
+ .tour-arrow.arrow-bottom {
384
+ top: -7px;
385
+ left: 50%;
386
+ margin-left: -6px;
387
+ border-bottom: none;
388
+ border-right: none;
389
+ }
390
+
391
+ .tour-arrow.arrow-left {
392
+ right: -7px;
393
+ top: 50%;
394
+ margin-top: -6px;
395
+ border-bottom: none;
396
+ border-left: none;
397
+ }
398
+
399
+ .tour-arrow.arrow-right {
400
+ left: -7px;
401
+ top: 50%;
402
+ margin-top: -6px;
403
+ border-top: none;
404
+ border-right: none;
405
+ }
406
+
407
+ /* ── Tooltip content ──────────────────────────── */
408
+
409
+ .tour-step-badge {
410
+ display: inline-flex;
411
+ align-items: center;
412
+ gap: 0.25rem;
413
+ font-size: 0.6875rem;
414
+ font-weight: 600;
415
+ text-transform: uppercase;
416
+ letter-spacing: 0.05em;
417
+ color: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));
418
+ margin-bottom: 0.5rem;
419
+ }
420
+
421
+ .tour-title {
422
+ margin: 0 0 0.375rem;
423
+ font-size: 1rem;
424
+ font-weight: 600;
425
+ color: var(--tour-foreground, var(--foreground, #1a1a1a));
426
+ line-height: 1.3;
427
+ }
428
+
429
+ .tour-message {
430
+ margin: 0 0 1rem;
431
+ font-size: 0.8125rem;
432
+ color: var(--tour-muted-foreground, var(--muted-foreground, #737373));
433
+ line-height: 1.55;
434
+ }
435
+
436
+ /* ── Progress dots ────────────────────────────── */
437
+
438
+ .tour-progress {
439
+ display: flex;
440
+ align-items: center;
441
+ gap: 0.375rem;
442
+ margin-bottom: 1rem;
443
+ }
444
+
445
+ .tour-dot {
446
+ width: 6px;
447
+ height: 6px;
448
+ border-radius: 50%;
449
+ background: var(--tour-muted, var(--muted, #e5e5e5));
450
+ transition: background 0.2s, transform 0.2s;
451
+ }
452
+
453
+ .tour-dot.active {
454
+ background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));
455
+ transform: scale(1.3);
456
+ }
457
+
458
+ .tour-dot.completed {
459
+ background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));
460
+ opacity: 0.5;
461
+ }
462
+
463
+ /* ── Footer buttons ───────────────────────────── */
464
+
465
+ .tour-footer {
466
+ display: flex;
467
+ align-items: center;
468
+ justify-content: space-between;
469
+ }
470
+
471
+ .tour-skip {
472
+ font-size: 0.75rem;
473
+ color: var(--tour-muted-foreground, var(--muted-foreground, #737373));
474
+ background: none;
475
+ border: none;
476
+ cursor: pointer;
477
+ padding: 0.25rem 0;
478
+ transition: color 0.15s;
479
+ }
480
+
481
+ .tour-skip:hover {
482
+ color: var(--tour-foreground, var(--foreground, #1a1a1a));
483
+ }
484
+
485
+ .tour-nav {
486
+ display: flex;
487
+ gap: 0.5rem;
488
+ }
489
+
490
+ .tour-btn {
491
+ display: inline-flex;
492
+ align-items: center;
493
+ gap: 0.375rem;
494
+ padding: 0.4rem 0.875rem;
495
+ font-size: 0.8125rem;
496
+ font-weight: 500;
497
+ border-radius: var(--tour-btn-radius, var(--radius-md, 0.5rem));
498
+ border: 1px solid var(--tour-border, var(--border, #e5e5e5));
499
+ background: var(--tour-background, var(--background, #fff));
500
+ color: var(--tour-foreground, var(--foreground, #1a1a1a));
501
+ cursor: pointer;
502
+ transition: all 0.15s;
503
+ }
504
+
505
+ .tour-btn:hover {
506
+ background: var(--tour-muted, var(--muted, #f5f5f5));
507
+ }
508
+
509
+ .tour-btn.primary {
510
+ background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));
511
+ color: var(--tour-primary-foreground, var(--primary-foreground, #fff));
512
+ border-color: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));
513
+ }
514
+
515
+ .tour-btn.primary:hover {
516
+ opacity: 0.9;
517
+ }
518
+
519
+ .tour-btn svg {
520
+ width: 14px;
521
+ height: 14px;
522
+ }
523
+
524
+ /* ── Welcome / no-target step ─────────────────── */
525
+
526
+ .tour-center-card {
527
+ position: fixed;
528
+ z-index: 10000;
529
+ top: 50%;
530
+ left: 50%;
531
+ transform: translate(-50%, -50%) scale(0.96);
532
+ width: 400px;
533
+ max-width: calc(100vw - 2rem);
534
+ background: var(--tour-card, var(--card, #fff));
535
+ border: 1px solid var(--tour-border, var(--border, #e5e5e5));
536
+ border-radius: var(--tour-card-radius, var(--radius-xl, 1rem));
537
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
538
+ padding: 2rem;
539
+ text-align: center;
540
+ pointer-events: auto;
541
+ opacity: 0;
542
+ transition: opacity 0.3s ease, transform 0.3s ease;
543
+ }
544
+
545
+ .tour-center-card.visible {
546
+ opacity: 1;
547
+ transform: translate(-50%, -50%) scale(1);
548
+ }
549
+
550
+ .tour-center-icon {
551
+ width: 48px;
552
+ height: 48px;
553
+ margin: 0 auto 1rem;
554
+ background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));
555
+ border-radius: 50%;
556
+ display: flex;
557
+ align-items: center;
558
+ justify-content: center;
559
+ color: var(--tour-primary-foreground, var(--primary-foreground, #fff));
560
+ }
561
+ `;
562
+ __decorateClass([
563
+ property({ attribute: false })
564
+ ], TorchlitOverlay.prototype, "service", 2);
565
+ __decorateClass([
566
+ state()
567
+ ], TorchlitOverlay.prototype, "snapshot", 2);
568
+ __decorateClass([
569
+ state()
570
+ ], TorchlitOverlay.prototype, "visible", 2);
571
+ TorchlitOverlay = __decorateClass([
572
+ customElement("torchlit-overlay")
573
+ ], TorchlitOverlay);
574
+ export {
575
+ TorchlitOverlay
576
+ };
577
+ //# sourceMappingURL=tour-overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tour-overlay.js","sources":["../src/tour-overlay.ts"],"sourcesContent":["import { LitElement, html, css } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport type { TourService } from './tour-service.js';\nimport type { TourSnapshot, TourPlacement } from './types.js';\n\n/**\n * `<torchlit-overlay>` — Full-screen overlay that renders a spotlight cutout\n * around the current tour target, a tooltip with title / message / progress,\n * and navigation controls.\n *\n * Wire it to a `TourService` instance via the `service` property:\n *\n * ```html\n * <torchlit-overlay></torchlit-overlay>\n * ```\n * ```js\n * document.querySelector('torchlit-overlay').service = myTourService;\n * ```\n *\n * @fires tour-route-change - When a step has a `route` property, dispatched\n * with `{ route: string }` so the host app can switch views.\n *\n * @csspart backdrop - The semi-transparent overlay behind the spotlight.\n * @csspart spotlight - The cutout highlight around the target element.\n * @csspart tooltip - The floating tooltip card.\n * @csspart center-card - The centered card shown when there is no target.\n */\n@customElement('torchlit-overlay')\nexport class TorchlitOverlay extends LitElement {\n /* ── Styles ─────────────────────────────────────── */\n\n static override styles = css`\n :host {\n display: block;\n }\n\n /* ── Backdrop ──────────────────────────────────── */\n\n .tour-backdrop {\n position: fixed;\n inset: 0;\n z-index: 9998;\n pointer-events: auto;\n opacity: 0;\n transition: opacity 0.3s ease;\n }\n\n .tour-backdrop.visible {\n opacity: 1;\n }\n\n /* ── Spotlight (box-shadow cutout) ─────────────── */\n\n .tour-spotlight {\n position: fixed;\n z-index: 9999;\n border-radius: var(--tour-spotlight-radius, var(--radius-lg, 0.75rem));\n box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.55);\n transition: top 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n left 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n width 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n height 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n pointer-events: none;\n }\n\n /* Subtle pulsing ring around spotlight */\n .tour-spotlight::after {\n content: '';\n position: absolute;\n inset: -4px;\n border-radius: inherit;\n border: 2px solid var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));\n opacity: 0.5;\n animation: spotlightPulse 2s ease-in-out infinite;\n }\n\n @keyframes spotlightPulse {\n 0%, 100% { opacity: 0.3; transform: scale(1); }\n 50% { opacity: 0.7; transform: scale(1.01); }\n }\n\n /* ── Tooltip ───────────────────────────────────── */\n\n .tour-tooltip {\n position: fixed;\n z-index: 10000;\n width: 320px;\n background: var(--tour-card, var(--card, #fff));\n border: 1px solid var(--tour-border, var(--border, #e5e5e5));\n border-radius: var(--tour-tooltip-radius, var(--radius-lg, 0.75rem));\n box-shadow: 0 20px 40px -8px rgba(0, 0, 0, 0.2),\n 0 8px 16px -4px rgba(0, 0, 0, 0.1);\n padding: 1.25rem;\n pointer-events: auto;\n opacity: 0;\n transform: translateY(8px) scale(0.96);\n transition: opacity 0.25s ease, transform 0.25s ease,\n top 0.35s cubic-bezier(0.4, 0, 0.2, 1),\n left 0.35s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .tour-tooltip.visible {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n\n /* Arrow */\n .tour-arrow {\n position: absolute;\n width: 12px;\n height: 12px;\n background: var(--tour-card, var(--card, #fff));\n border: 1px solid var(--tour-border, var(--border, #e5e5e5));\n transform: rotate(45deg);\n }\n\n .tour-arrow.arrow-top {\n bottom: -7px;\n left: 50%;\n margin-left: -6px;\n border-top: none;\n border-left: none;\n }\n\n .tour-arrow.arrow-bottom {\n top: -7px;\n left: 50%;\n margin-left: -6px;\n border-bottom: none;\n border-right: none;\n }\n\n .tour-arrow.arrow-left {\n right: -7px;\n top: 50%;\n margin-top: -6px;\n border-bottom: none;\n border-left: none;\n }\n\n .tour-arrow.arrow-right {\n left: -7px;\n top: 50%;\n margin-top: -6px;\n border-top: none;\n border-right: none;\n }\n\n /* ── Tooltip content ──────────────────────────── */\n\n .tour-step-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));\n margin-bottom: 0.5rem;\n }\n\n .tour-title {\n margin: 0 0 0.375rem;\n font-size: 1rem;\n font-weight: 600;\n color: var(--tour-foreground, var(--foreground, #1a1a1a));\n line-height: 1.3;\n }\n\n .tour-message {\n margin: 0 0 1rem;\n font-size: 0.8125rem;\n color: var(--tour-muted-foreground, var(--muted-foreground, #737373));\n line-height: 1.55;\n }\n\n /* ── Progress dots ────────────────────────────── */\n\n .tour-progress {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n margin-bottom: 1rem;\n }\n\n .tour-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--tour-muted, var(--muted, #e5e5e5));\n transition: background 0.2s, transform 0.2s;\n }\n\n .tour-dot.active {\n background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));\n transform: scale(1.3);\n }\n\n .tour-dot.completed {\n background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));\n opacity: 0.5;\n }\n\n /* ── Footer buttons ───────────────────────────── */\n\n .tour-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .tour-skip {\n font-size: 0.75rem;\n color: var(--tour-muted-foreground, var(--muted-foreground, #737373));\n background: none;\n border: none;\n cursor: pointer;\n padding: 0.25rem 0;\n transition: color 0.15s;\n }\n\n .tour-skip:hover {\n color: var(--tour-foreground, var(--foreground, #1a1a1a));\n }\n\n .tour-nav {\n display: flex;\n gap: 0.5rem;\n }\n\n .tour-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.4rem 0.875rem;\n font-size: 0.8125rem;\n font-weight: 500;\n border-radius: var(--tour-btn-radius, var(--radius-md, 0.5rem));\n border: 1px solid var(--tour-border, var(--border, #e5e5e5));\n background: var(--tour-background, var(--background, #fff));\n color: var(--tour-foreground, var(--foreground, #1a1a1a));\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .tour-btn:hover {\n background: var(--tour-muted, var(--muted, #f5f5f5));\n }\n\n .tour-btn.primary {\n background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));\n color: var(--tour-primary-foreground, var(--primary-foreground, #fff));\n border-color: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));\n }\n\n .tour-btn.primary:hover {\n opacity: 0.9;\n }\n\n .tour-btn svg {\n width: 14px;\n height: 14px;\n }\n\n /* ── Welcome / no-target step ─────────────────── */\n\n .tour-center-card {\n position: fixed;\n z-index: 10000;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0.96);\n width: 400px;\n max-width: calc(100vw - 2rem);\n background: var(--tour-card, var(--card, #fff));\n border: 1px solid var(--tour-border, var(--border, #e5e5e5));\n border-radius: var(--tour-card-radius, var(--radius-xl, 1rem));\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n padding: 2rem;\n text-align: center;\n pointer-events: auto;\n opacity: 0;\n transition: opacity 0.3s ease, transform 0.3s ease;\n }\n\n .tour-center-card.visible {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n\n .tour-center-icon {\n width: 48px;\n height: 48px;\n margin: 0 auto 1rem;\n background: var(--tour-primary, var(--primary, oklch(0.65 0.17 220)));\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--tour-primary-foreground, var(--primary-foreground, #fff));\n }\n `;\n\n /* ── Properties ──────────────────────────────────── */\n\n /**\n * The `TourService` instance this overlay subscribes to.\n * Must be set before the overlay will render anything.\n */\n @property({ attribute: false })\n service!: TourService;\n\n @state() private snapshot: TourSnapshot | null = null;\n @state() private visible = false;\n\n private unsubscribe?: () => void;\n\n /* ── Lifecycle ──────────────────────────────────── */\n\n override connectedCallback() {\n super.connectedCallback();\n if (this.service) {\n this.attachService();\n }\n window.addEventListener('resize', this.handleResize);\n window.addEventListener('keydown', this.handleKeydown);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.unsubscribe?.();\n window.removeEventListener('resize', this.handleResize);\n window.removeEventListener('keydown', this.handleKeydown);\n }\n\n override updated(changed: Map<string, unknown>) {\n if (changed.has('service') && this.service) {\n this.unsubscribe?.();\n this.attachService();\n }\n }\n\n private attachService() {\n this.unsubscribe = this.service.subscribe(snap => this.handleTourChange(snap));\n }\n\n /* ── Tour state handler ─────────────────────────── */\n\n private async handleTourChange(snapshot: TourSnapshot | null) {\n if (!snapshot) {\n // Tour ended — fade out\n this.visible = false;\n setTimeout(() => { this.snapshot = null; }, 300);\n return;\n }\n\n // Run beforeShow hook if present\n if (snapshot.step.beforeShow) {\n try {\n await snapshot.step.beforeShow();\n } catch (err) {\n console.error('[torchlit] beforeShow hook failed:', err);\n }\n }\n\n // Emit route-change event if the step has a route\n if (snapshot.step.route) {\n this.dispatchEvent(new CustomEvent('tour-route-change', {\n detail: { route: snapshot.step.route },\n bubbles: true,\n composed: true,\n }));\n // Give the view transition time to render, then re-resolve the target\n await new Promise(r => setTimeout(r, 350));\n this.snapshot = this.service.getSnapshot();\n } else {\n this.snapshot = snapshot;\n }\n\n this.scrollTargetIntoView();\n requestAnimationFrame(() => { this.visible = true; });\n }\n\n private scrollTargetIntoView() {\n if (this.snapshot?.targetElement) {\n this.snapshot.targetElement.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n inline: 'nearest',\n });\n // Recalculate rect after scroll settles\n setTimeout(() => {\n if (this.service) {\n this.snapshot = this.service.getSnapshot();\n }\n }, 400);\n }\n }\n\n /* ── Event handlers ─────────────────────────────── */\n\n private handleResize = () => {\n if (this.snapshot && this.service) {\n this.snapshot = this.service.getSnapshot();\n }\n };\n\n private handleKeydown = (e: KeyboardEvent) => {\n if (!this.snapshot || !this.service) return;\n if (e.key === 'Escape') {\n e.preventDefault();\n this.service.skipTour();\n } else if (e.key === 'ArrowRight' || e.key === 'Enter') {\n e.preventDefault();\n this.service.nextStep();\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n this.service.prevStep();\n }\n };\n\n private handleBackdropClick = () => {\n this.service?.skipTour();\n };\n\n /* ── Tooltip positioning ────────────────────────── */\n\n private getTooltipPosition(rect: DOMRect, placement: TourPlacement): { top: number; left: number } {\n const PADDING = this.service?.spotlightPadding ?? 10;\n const GAP = 16;\n const TOOLTIP_W = 320;\n\n switch (placement) {\n case 'right':\n return {\n top: rect.top + rect.height / 2 - 80,\n left: rect.right + PADDING + GAP,\n };\n case 'left':\n return {\n top: rect.top + rect.height / 2 - 80,\n left: rect.left - PADDING - GAP - TOOLTIP_W,\n };\n case 'bottom':\n return {\n top: rect.bottom + PADDING + GAP,\n left: rect.left + rect.width / 2 - TOOLTIP_W / 2,\n };\n case 'top':\n return {\n top: rect.top - PADDING - GAP - 180,\n left: rect.left + rect.width / 2 - TOOLTIP_W / 2,\n };\n default:\n return { top: rect.bottom + GAP, left: rect.left };\n }\n }\n\n private clampToViewport(pos: { top: number; left: number }): { top: number; left: number } {\n const MARGIN = 16;\n const TOOLTIP_W = 320;\n return {\n top: Math.max(MARGIN, Math.min(pos.top, window.innerHeight - 250)),\n left: Math.max(MARGIN, Math.min(pos.left, window.innerWidth - TOOLTIP_W - MARGIN)),\n };\n }\n\n private getArrowClass(placement: TourPlacement): string {\n switch (placement) {\n case 'right': return 'arrow-right';\n case 'left': return 'arrow-left';\n case 'bottom': return 'arrow-bottom';\n case 'top': return 'arrow-top';\n default: return 'arrow-bottom';\n }\n }\n\n /* ── Render ─────────────────────────────────────── */\n\n override render() {\n if (!this.snapshot) return html``;\n\n const { step, stepIndex, totalSteps, targetRect } = this.snapshot;\n\n // No target found — show centered card\n if (!targetRect) {\n return this.renderCenteredStep(step, stepIndex, totalSteps);\n }\n\n const PADDING = this.service?.spotlightPadding ?? 10;\n const spotlightStyle = `\n top: ${targetRect.top - PADDING}px;\n left: ${targetRect.left - PADDING}px;\n width: ${targetRect.width + PADDING * 2}px;\n height: ${targetRect.height + PADDING * 2}px;\n `;\n\n const tooltipPos = this.clampToViewport(\n this.getTooltipPosition(targetRect, step.placement),\n );\n const tooltipStyle = `top: ${tooltipPos.top}px; left: ${tooltipPos.left}px;`;\n\n return html`\n <div\n class=\"tour-backdrop ${this.visible ? 'visible' : ''}\"\n part=\"backdrop\"\n @click=${this.handleBackdropClick}\n ></div>\n\n <div class=\"tour-spotlight\" part=\"spotlight\" style=${spotlightStyle}></div>\n\n <div class=\"tour-tooltip ${this.visible ? 'visible' : ''}\" part=\"tooltip\" style=${tooltipStyle}>\n <div class=\"tour-arrow ${this.getArrowClass(step.placement)}\"></div>\n\n <div class=\"tour-step-badge\">\n <svg viewBox=\"0 0 24 24\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"></path>\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line>\n </svg>\n Step ${stepIndex + 1} of ${totalSteps}\n </div>\n\n <h3 class=\"tour-title\">${step.title}</h3>\n <p class=\"tour-message\">${step.message}</p>\n\n ${this.renderProgressDots(stepIndex, totalSteps)}\n\n <div class=\"tour-footer\">\n <button class=\"tour-skip\" @click=${() => this.service.skipTour()}>\n Skip tour\n </button>\n <div class=\"tour-nav\">\n ${stepIndex > 0 ? html`\n <button class=\"tour-btn\" @click=${() => this.service.prevStep()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"15 18 9 12 15 6\"></polyline>\n </svg>\n Back\n </button>\n ` : ''}\n <button class=\"tour-btn primary\" @click=${() => this.service.nextStep()}>\n ${stepIndex === totalSteps - 1 ? 'Finish' : 'Next'}\n ${stepIndex < totalSteps - 1 ? html`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"9 18 15 12 9 6\"></polyline>\n </svg>\n ` : html`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n `}\n </button>\n </div>\n </div>\n </div>\n `;\n }\n\n private renderProgressDots(current: number, total: number) {\n if (total <= 1) return html``;\n return html`\n <div class=\"tour-progress\">\n ${Array.from({ length: total }, (_, i) => html`\n <div class=\"tour-dot ${i === current ? 'active' : i < current ? 'completed' : ''}\"></div>\n `)}\n </div>\n `;\n }\n\n private renderCenteredStep(step: { title: string; message: string }, stepIndex: number, totalSteps: number) {\n return html`\n <div\n class=\"tour-backdrop ${this.visible ? 'visible' : ''}\"\n part=\"backdrop\"\n @click=${this.handleBackdropClick}\n ></div>\n\n <div class=\"tour-center-card ${this.visible ? 'visible' : ''}\" part=\"center-card\">\n <div class=\"tour-center-icon\">\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\"></path>\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"></line>\n </svg>\n </div>\n\n <h3 class=\"tour-title\">${step.title}</h3>\n <p class=\"tour-message\">${step.message}</p>\n\n ${this.renderProgressDots(stepIndex, totalSteps)}\n\n <div class=\"tour-footer\">\n <button class=\"tour-skip\" @click=${() => this.service.skipTour()}>\n Skip tour\n </button>\n <div class=\"tour-nav\">\n ${stepIndex > 0 ? html`\n <button class=\"tour-btn\" @click=${() => this.service.prevStep()}>Back</button>\n ` : ''}\n <button class=\"tour-btn primary\" @click=${() => this.service.nextStep()}>\n ${stepIndex === totalSteps - 1 ? \"Let's go!\" : 'Next'}\n ${stepIndex < totalSteps - 1 ? html`\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"9 18 15 12 9 6\"></polyline>\n </svg>\n ` : ''}\n </button>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'torchlit-overlay': TorchlitOverlay;\n }\n}\n"],"names":[],"mappings":"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"}