clio-design-system 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.
package/dist/index.js ADDED
@@ -0,0 +1,2096 @@
1
+ // src/components/Button/Button.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ var SIZE = {
4
+ sm: { padY: "6px", padX: "14px", font: "var(--font-size-sm)" },
5
+ md: { padY: "9px", padX: "18px", font: "var(--font-size-base)" }
6
+ };
7
+ function Button({
8
+ variant = "secondary",
9
+ size = "md",
10
+ active = false,
11
+ disabled = false,
12
+ icon = null,
13
+ children,
14
+ onClick,
15
+ title,
16
+ ...rest
17
+ }) {
18
+ const s = SIZE[size] ?? SIZE.md;
19
+ const base = {
20
+ fontFamily: "var(--font-family-mono)",
21
+ fontSize: s.font,
22
+ letterSpacing: "var(--letter-spacing-mono-label)",
23
+ padding: `${s.padY} ${s.padX}`,
24
+ borderRadius: "var(--radius-pill)",
25
+ border: "none",
26
+ display: "inline-flex",
27
+ alignItems: "center",
28
+ gap: "7px",
29
+ cursor: disabled ? "default" : "pointer",
30
+ opacity: disabled ? 0.4 : 1,
31
+ transition: "background var(--duration-fast) ease, color var(--duration-fast) ease"
32
+ };
33
+ let style = { ...base };
34
+ if (variant === "primary") {
35
+ style = { ...style, background: "var(--color-accent)", color: "#FFFFFF" };
36
+ } else if (variant === "dark") {
37
+ style = { ...style, background: "var(--color-ink-900)", color: "var(--color-cream-50)" };
38
+ } else if (variant === "secondary") {
39
+ style = {
40
+ ...style,
41
+ background: "var(--color-surface)",
42
+ color: "var(--color-text-secondary)",
43
+ border: "1px solid var(--border-medium)"
44
+ };
45
+ } else if (variant === "ghost") {
46
+ style = { ...style, background: "transparent", color: "var(--color-text-muted)", padding: "2px 4px" };
47
+ } else if (variant === "nav") {
48
+ style = {
49
+ ...style,
50
+ background: active ? "var(--color-ink-900)" : "transparent",
51
+ color: active ? "var(--color-cream-50)" : "var(--color-text-muted)"
52
+ };
53
+ }
54
+ return /* @__PURE__ */ jsxs("button", { type: "button", title, disabled, onClick, ...rest, style, children: [
55
+ icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { fontSize: "13px", lineHeight: 1 }, children: icon }) : null,
56
+ children
57
+ ] });
58
+ }
59
+
60
+ // src/internal/useHover.ts
61
+ import { useState } from "react";
62
+ function useHover(options = {}) {
63
+ const [hovered, setHovered] = useState(false);
64
+ const [focused, setFocused] = useState(false);
65
+ return {
66
+ hovered,
67
+ focused,
68
+ active: hovered || focused,
69
+ interactionHandlers: {
70
+ onMouseEnter: (e) => {
71
+ setHovered(true);
72
+ options.onMouseEnter?.(e);
73
+ },
74
+ onMouseLeave: (e) => {
75
+ setHovered(false);
76
+ options.onMouseLeave?.(e);
77
+ },
78
+ onFocus: (e) => {
79
+ setFocused(true);
80
+ options.onFocus?.(e);
81
+ },
82
+ onBlur: (e) => {
83
+ setFocused(false);
84
+ options.onBlur?.(e);
85
+ }
86
+ }
87
+ };
88
+ }
89
+
90
+ // src/components/IconButton/IconButton.tsx
91
+ import { jsx as jsx2 } from "react/jsx-runtime";
92
+ function IconButton({
93
+ size = 26,
94
+ children,
95
+ onClick,
96
+ title,
97
+ bordered = false,
98
+ hoverColor = "var(--color-text-secondary)",
99
+ disabled = false,
100
+ radius = "var(--radius-md)",
101
+ onMouseEnter,
102
+ onMouseLeave,
103
+ onFocus,
104
+ onBlur,
105
+ ...rest
106
+ }) {
107
+ const { active, interactionHandlers } = useHover({ onMouseEnter, onMouseLeave, onFocus, onBlur });
108
+ return /* @__PURE__ */ jsx2(
109
+ "button",
110
+ {
111
+ type: "button",
112
+ title,
113
+ "aria-label": title,
114
+ onClick,
115
+ disabled,
116
+ ...rest,
117
+ ...interactionHandlers,
118
+ style: {
119
+ width: size,
120
+ height: size,
121
+ border: bordered ? "1px solid var(--border-medium)" : "none",
122
+ background: active ? "rgba(17,17,17,0.08)" : bordered ? "var(--color-surface)" : "transparent",
123
+ borderRadius: radius,
124
+ color: active ? hoverColor : "var(--color-text-muted)",
125
+ display: "flex",
126
+ alignItems: "center",
127
+ justifyContent: "center",
128
+ fontSize: "15px",
129
+ lineHeight: 1,
130
+ padding: 0,
131
+ cursor: disabled ? "default" : "pointer",
132
+ opacity: disabled ? 0.4 : 1,
133
+ transition: "background var(--duration-fast) ease, color var(--duration-fast) ease"
134
+ },
135
+ children
136
+ }
137
+ );
138
+ }
139
+
140
+ // src/components/TagChip/TagChip.tsx
141
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
142
+ function TagChip({
143
+ label,
144
+ color = "var(--color-ink-500)",
145
+ active = false,
146
+ onClick,
147
+ removable = false,
148
+ onRemove,
149
+ size = "md",
150
+ ...rest
151
+ }) {
152
+ const tint = active ? color : `color-mix(in srgb, ${color} 14%, transparent)`;
153
+ const textColor = active ? "#FFFFFF" : color;
154
+ const font = size === "sm" ? "9px" : "10.5px";
155
+ return /* @__PURE__ */ jsxs2(
156
+ "span",
157
+ {
158
+ style: {
159
+ display: "inline-flex",
160
+ alignItems: "center",
161
+ gap: 5,
162
+ borderRadius: "var(--radius-pill)",
163
+ padding: removable ? "3px 6px 3px 9px" : "3px 10px",
164
+ fontFamily: "var(--font-family-mono)",
165
+ fontSize: font,
166
+ background: tint,
167
+ color: textColor,
168
+ whiteSpace: "nowrap"
169
+ },
170
+ children: [
171
+ /* @__PURE__ */ jsxs2(
172
+ "button",
173
+ {
174
+ type: "button",
175
+ onClick,
176
+ ...rest,
177
+ style: { border: "none", background: "none", padding: 0, font: "inherit", color: "inherit", cursor: "pointer" },
178
+ children: [
179
+ "#",
180
+ label
181
+ ]
182
+ }
183
+ ),
184
+ removable && /* @__PURE__ */ jsx3(
185
+ "button",
186
+ {
187
+ type: "button",
188
+ onClick: (e) => {
189
+ e.stopPropagation();
190
+ onRemove?.();
191
+ },
192
+ "aria-label": `Remove ${label} tag`,
193
+ style: {
194
+ border: "none",
195
+ background: "none",
196
+ padding: "0 1px",
197
+ opacity: 0.7,
198
+ fontSize: "12px",
199
+ lineHeight: 1,
200
+ color: "inherit",
201
+ cursor: "pointer"
202
+ },
203
+ children: "\xD7"
204
+ }
205
+ )
206
+ ]
207
+ }
208
+ );
209
+ }
210
+
211
+ // src/components/Badge/Badge.tsx
212
+ import { jsx as jsx4 } from "react/jsx-runtime";
213
+ function Badge({ variant = "mono", children, color, tint }) {
214
+ if (variant === "topic") {
215
+ return /* @__PURE__ */ jsx4(
216
+ "span",
217
+ {
218
+ style: {
219
+ fontFamily: "var(--font-family-mono)",
220
+ fontSize: "var(--font-size-sm)",
221
+ letterSpacing: "0.06em",
222
+ fontWeight: 500,
223
+ color: color || "var(--color-accent)",
224
+ background: tint || "color-mix(in srgb, var(--color-accent) 10%, transparent)",
225
+ padding: "3px 9px",
226
+ borderRadius: "var(--radius-xs)",
227
+ whiteSpace: "nowrap",
228
+ display: "inline-block"
229
+ },
230
+ children
231
+ }
232
+ );
233
+ }
234
+ if (variant === "eyebrow") {
235
+ return /* @__PURE__ */ jsx4(
236
+ "span",
237
+ {
238
+ style: {
239
+ fontFamily: "var(--font-family-mono)",
240
+ fontSize: "var(--font-size-xs)",
241
+ letterSpacing: "var(--letter-spacing-mono-wide)",
242
+ color: color || "var(--color-accent)",
243
+ whiteSpace: "nowrap"
244
+ },
245
+ children
246
+ }
247
+ );
248
+ }
249
+ if (variant === "count") {
250
+ return /* @__PURE__ */ jsx4(
251
+ "span",
252
+ {
253
+ style: {
254
+ minWidth: 17,
255
+ height: 17,
256
+ padding: "0 4px",
257
+ boxSizing: "border-box",
258
+ borderRadius: "var(--radius-full)",
259
+ display: "inline-flex",
260
+ alignItems: "center",
261
+ justifyContent: "center",
262
+ fontSize: "9.5px",
263
+ background: tint || "color-mix(in srgb, var(--color-accent) 14%, transparent)",
264
+ color: color || "var(--color-accent)"
265
+ },
266
+ children
267
+ }
268
+ );
269
+ }
270
+ return /* @__PURE__ */ jsx4(
271
+ "span",
272
+ {
273
+ style: {
274
+ fontFamily: "var(--font-family-mono)",
275
+ fontSize: "var(--font-size-xs)",
276
+ letterSpacing: "0.1em",
277
+ color: "var(--color-text-muted)",
278
+ background: "var(--border-hairline)",
279
+ padding: "2px 8px",
280
+ borderRadius: "var(--radius-xs)"
281
+ },
282
+ children
283
+ }
284
+ );
285
+ }
286
+
287
+ // src/components/SolvedStatusButton/SolvedStatusButton.tsx
288
+ import { jsx as jsx5 } from "react/jsx-runtime";
289
+ function SolvedStatusButton({ solved = false, onClick, ...rest }) {
290
+ return /* @__PURE__ */ jsx5(
291
+ "button",
292
+ {
293
+ type: "button",
294
+ onClick,
295
+ ...rest,
296
+ style: {
297
+ border: `1px solid ${solved ? "color-mix(in srgb, var(--color-success) 35%, transparent)" : "var(--border-medium)"}`,
298
+ background: solved ? "var(--color-success-tint)" : "transparent",
299
+ color: solved ? "var(--color-success)" : "var(--color-text-muted)",
300
+ borderRadius: "var(--radius-sm)",
301
+ padding: "3px 10px",
302
+ fontFamily: "var(--font-family-mono)",
303
+ fontSize: "var(--font-size-xs)",
304
+ letterSpacing: "0.06em"
305
+ },
306
+ children: solved ? "\u2713 SOLVED" : "MARK SOLVED"
307
+ }
308
+ );
309
+ }
310
+
311
+ // src/components/TextInput/TextInput.tsx
312
+ import { jsx as jsx6 } from "react/jsx-runtime";
313
+ function TextInput({
314
+ value,
315
+ onChange,
316
+ placeholder,
317
+ mono = false,
318
+ autoFocus = false,
319
+ style,
320
+ "aria-label": ariaLabel,
321
+ type = "text",
322
+ ...rest
323
+ }) {
324
+ return /* @__PURE__ */ jsx6(
325
+ "input",
326
+ {
327
+ type,
328
+ value,
329
+ onChange,
330
+ placeholder,
331
+ autoFocus,
332
+ "aria-label": ariaLabel,
333
+ ...rest,
334
+ style: {
335
+ border: "1px solid var(--border-medium)",
336
+ borderRadius: "var(--radius-md)",
337
+ background: "var(--color-surface)",
338
+ fontFamily: mono ? "var(--font-family-mono)" : "inherit",
339
+ fontSize: mono ? "var(--font-size-base)" : "var(--font-size-lg)",
340
+ color: "var(--color-text-primary)",
341
+ padding: "7px 11px",
342
+ boxSizing: "border-box",
343
+ ...style
344
+ }
345
+ }
346
+ );
347
+ }
348
+
349
+ // src/components/TextArea/TextArea.tsx
350
+ import { jsx as jsx7 } from "react/jsx-runtime";
351
+ function TextArea({
352
+ value,
353
+ onChange,
354
+ placeholder,
355
+ rows = 6,
356
+ mono = true,
357
+ "aria-label": ariaLabel,
358
+ ...rest
359
+ }) {
360
+ return /* @__PURE__ */ jsx7(
361
+ "textarea",
362
+ {
363
+ value,
364
+ onChange,
365
+ placeholder,
366
+ rows,
367
+ "aria-label": ariaLabel,
368
+ ...rest,
369
+ style: {
370
+ width: "100%",
371
+ boxSizing: "border-box",
372
+ resize: "vertical",
373
+ border: "1px solid var(--border-medium)",
374
+ borderRadius: "var(--radius-xl)",
375
+ background: "var(--color-surface)",
376
+ padding: "12px 14px",
377
+ fontFamily: mono ? "var(--font-family-mono)" : "inherit",
378
+ fontSize: mono ? "var(--font-size-md)" : "var(--font-size-lg)",
379
+ lineHeight: 1.55,
380
+ color: "var(--color-text-body)"
381
+ }
382
+ }
383
+ );
384
+ }
385
+
386
+ // src/components/Avatar/Avatar.tsx
387
+ import { jsx as jsx8 } from "react/jsx-runtime";
388
+ function Avatar({ initial = "M", size = 28, dark = false, style, ...rest }) {
389
+ return /* @__PURE__ */ jsx8(
390
+ "div",
391
+ {
392
+ ...rest,
393
+ style: {
394
+ width: size,
395
+ height: size,
396
+ borderRadius: "50%",
397
+ background: dark ? "var(--color-surface-inverse)" : "var(--color-stone-100)",
398
+ color: dark ? "var(--color-text-on-inverse)" : "var(--color-text-secondary)",
399
+ display: "flex",
400
+ alignItems: "center",
401
+ justifyContent: "center",
402
+ fontSize: size * 0.43,
403
+ fontWeight: 600,
404
+ fontFamily: "var(--font-family-sans)",
405
+ ...style
406
+ },
407
+ children: initial
408
+ }
409
+ );
410
+ }
411
+
412
+ // src/components/ColorSwatch/ColorSwatch.tsx
413
+ import { forwardRef } from "react";
414
+ import { jsx as jsx9 } from "react/jsx-runtime";
415
+ var ColorSwatch = forwardRef(function ColorSwatch2({ color, active = false, onClick, size = 17, title = "Recolor", ...rest }, ref) {
416
+ return /* @__PURE__ */ jsx9(
417
+ "button",
418
+ {
419
+ ref,
420
+ type: "button",
421
+ onClick,
422
+ title,
423
+ "aria-label": title,
424
+ ...rest,
425
+ style: {
426
+ width: size,
427
+ height: size,
428
+ borderRadius: "50%",
429
+ background: color,
430
+ padding: 0,
431
+ border: `2px solid ${active ? "var(--color-ink-900)" : "transparent"}`
432
+ }
433
+ }
434
+ );
435
+ });
436
+
437
+ // src/components/DragHandle/DragHandle.tsx
438
+ import { jsx as jsx10 } from "react/jsx-runtime";
439
+ function DragHandle({ onDragStart, title = "Drag to reorder", style, ...rest }) {
440
+ return /* @__PURE__ */ jsx10(
441
+ "span",
442
+ {
443
+ draggable: true,
444
+ onDragStart,
445
+ title,
446
+ "aria-hidden": "true",
447
+ ...rest,
448
+ style: {
449
+ cursor: "grab",
450
+ width: 16,
451
+ height: 22,
452
+ display: "flex",
453
+ alignItems: "center",
454
+ justifyContent: "center",
455
+ color: "var(--color-ink-300)",
456
+ fontSize: 19,
457
+ letterSpacing: "-2px",
458
+ lineHeight: 1,
459
+ userSelect: "none",
460
+ ...style
461
+ },
462
+ children: "\u22EE\u22EE"
463
+ }
464
+ );
465
+ }
466
+
467
+ // src/components/NavTabs/NavTabs.tsx
468
+ import { useRef } from "react";
469
+ import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
470
+ var TAB_ORDER = ["notes", "practice", "review"];
471
+ var TAB_LABEL = { notes: "LEARN", practice: "PRACTICE", review: "REVIEW" };
472
+ function Tab({ id, active, badge, onSelect, onKeyDown, buttonRef }) {
473
+ return /* @__PURE__ */ jsxs3(
474
+ "button",
475
+ {
476
+ ref: buttonRef,
477
+ type: "button",
478
+ role: "tab",
479
+ "aria-selected": active,
480
+ tabIndex: active ? 0 : -1,
481
+ onClick: () => onSelect(id),
482
+ onKeyDown: (e) => onKeyDown(e, id),
483
+ style: {
484
+ display: "flex",
485
+ alignItems: "center",
486
+ gap: 7,
487
+ border: "none",
488
+ fontFamily: "var(--font-family-mono)",
489
+ fontSize: "var(--font-size-sm)",
490
+ letterSpacing: "var(--letter-spacing-mono-label)",
491
+ padding: "7px 18px",
492
+ borderRadius: "var(--radius-pill)",
493
+ background: active ? "var(--color-ink-900)" : "transparent",
494
+ color: active ? "var(--color-cream-50)" : "var(--color-text-muted)",
495
+ transition: "background var(--duration-fast) ease, color var(--duration-fast) ease"
496
+ },
497
+ children: [
498
+ TAB_LABEL[id],
499
+ badge != null && badge > 0 && /* @__PURE__ */ jsx11(Badge, { variant: "count", color: "inherit", tint: "rgba(255,255,255,0.22)", children: badge })
500
+ ]
501
+ }
502
+ );
503
+ }
504
+ function NavTabs({ active = "notes", onChange, reviewCount = 0, ...rest }) {
505
+ const buttonRefs = useRef({});
506
+ const select = (id) => onChange?.(id);
507
+ const focusTab = (id) => {
508
+ buttonRefs.current[id]?.focus();
509
+ };
510
+ const handleKeyDown = (event, id) => {
511
+ const currentIndex = TAB_ORDER.indexOf(id);
512
+ let nextIndex = null;
513
+ if (event.key === "ArrowRight") {
514
+ nextIndex = (currentIndex + 1) % TAB_ORDER.length;
515
+ } else if (event.key === "ArrowLeft") {
516
+ nextIndex = (currentIndex - 1 + TAB_ORDER.length) % TAB_ORDER.length;
517
+ } else if (event.key === "Home") {
518
+ nextIndex = 0;
519
+ } else if (event.key === "End") {
520
+ nextIndex = TAB_ORDER.length - 1;
521
+ }
522
+ if (nextIndex !== null) {
523
+ event.preventDefault();
524
+ const nextId = TAB_ORDER[nextIndex];
525
+ select(nextId);
526
+ focusTab(nextId);
527
+ }
528
+ };
529
+ return /* @__PURE__ */ jsx11("div", { role: "tablist", "aria-label": "Sections", ...rest, style: { display: "flex", alignItems: "center", gap: 6, ...rest.style }, children: TAB_ORDER.map((id) => /* @__PURE__ */ jsx11(
530
+ Tab,
531
+ {
532
+ id,
533
+ active: active === id,
534
+ badge: id === "review" ? reviewCount : void 0,
535
+ onSelect: select,
536
+ onKeyDown: handleKeyDown,
537
+ buttonRef: (el) => {
538
+ buttonRefs.current[id] = el;
539
+ }
540
+ },
541
+ id
542
+ )) });
543
+ }
544
+
545
+ // src/components/Sidebar/Sidebar.tsx
546
+ import { useId } from "react";
547
+ import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
548
+ function Sidebar({
549
+ collapsed = false,
550
+ onToggle,
551
+ label,
552
+ width = 222,
553
+ children,
554
+ borderSide = "right",
555
+ style,
556
+ ...rest
557
+ }) {
558
+ const contentId = useId();
559
+ return /* @__PURE__ */ jsxs4(
560
+ "div",
561
+ {
562
+ ...rest,
563
+ style: {
564
+ display: "flex",
565
+ flexShrink: 0,
566
+ borderRight: borderSide === "right" ? "1px solid var(--border-hairline)" : "none",
567
+ ...style
568
+ },
569
+ children: [
570
+ /* @__PURE__ */ jsx12("div", { style: { width: 26, flexShrink: 0, display: "flex", flexDirection: "column", alignItems: "center", paddingTop: 16 }, children: /* @__PURE__ */ jsx12(
571
+ IconButton,
572
+ {
573
+ title: collapsed ? "Expand" : "Collapse",
574
+ onClick: onToggle,
575
+ size: 22,
576
+ radius: "var(--radius-sm)",
577
+ "aria-expanded": !collapsed,
578
+ "aria-controls": contentId,
579
+ children: /* @__PURE__ */ jsx12(
580
+ "span",
581
+ {
582
+ "aria-hidden": "true",
583
+ style: {
584
+ display: "flex",
585
+ fontSize: 12,
586
+ transform: `rotate(${collapsed ? 180 : 0}deg)`,
587
+ transition: "transform var(--duration-standard) var(--ease-standard)"
588
+ },
589
+ children: "\u2039"
590
+ }
591
+ )
592
+ }
593
+ ) }),
594
+ /* @__PURE__ */ jsx12(
595
+ "div",
596
+ {
597
+ id: contentId,
598
+ inert: collapsed,
599
+ style: {
600
+ width: collapsed ? 0 : width,
601
+ opacity: collapsed ? 0 : 1,
602
+ overflow: "hidden",
603
+ transition: "width var(--duration-standard) var(--ease-standard), opacity var(--duration-fast) ease"
604
+ },
605
+ children: /* @__PURE__ */ jsxs4("div", { style: { width, minHeight: "100%", boxSizing: "border-box", padding: "16px 10px 16px 0", display: "flex", flexDirection: "column", gap: 3 }, children: [
606
+ label && /* @__PURE__ */ jsx12(
607
+ "div",
608
+ {
609
+ style: {
610
+ fontFamily: "var(--font-family-mono)",
611
+ fontSize: "var(--font-size-xs)",
612
+ letterSpacing: "var(--letter-spacing-mono-wider)",
613
+ color: "var(--color-text-muted)",
614
+ padding: "4px 12px 10px"
615
+ },
616
+ children: label
617
+ }
618
+ ),
619
+ children
620
+ ] })
621
+ }
622
+ )
623
+ ]
624
+ }
625
+ );
626
+ }
627
+
628
+ // src/components/TopicRow/TopicRow.tsx
629
+ import { jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
630
+ function TopicRow({
631
+ name,
632
+ color,
633
+ notesLabel,
634
+ selected = false,
635
+ onClick,
636
+ onMenuClick,
637
+ draggable = true,
638
+ onDragStart,
639
+ dense = false,
640
+ style,
641
+ ...rest
642
+ }) {
643
+ return /* @__PURE__ */ jsxs5(
644
+ "div",
645
+ {
646
+ ...rest,
647
+ style: {
648
+ display: "flex",
649
+ alignItems: "flex-start",
650
+ gap: 8,
651
+ padding: dense ? "12px 8px" : "9px 32px 9px 8px",
652
+ borderRadius: "var(--radius-row)",
653
+ background: selected ? "var(--color-surface-sunken)" : "transparent",
654
+ position: "relative",
655
+ ...style
656
+ },
657
+ children: [
658
+ draggable && !dense && /* @__PURE__ */ jsx13(DragHandle, { onDragStart }),
659
+ /* @__PURE__ */ jsxs5(
660
+ "button",
661
+ {
662
+ type: "button",
663
+ onClick,
664
+ style: {
665
+ display: "flex",
666
+ alignItems: "flex-start",
667
+ gap: 8,
668
+ flex: 1,
669
+ minWidth: 0,
670
+ border: "none",
671
+ background: "none",
672
+ padding: 0,
673
+ textAlign: "left",
674
+ font: "inherit",
675
+ cursor: "pointer"
676
+ },
677
+ children: [
678
+ /* @__PURE__ */ jsx13("span", { style: { width: 7, height: 7, borderRadius: "50%", flexShrink: 0, background: color, marginTop: 6 } }),
679
+ /* @__PURE__ */ jsxs5("span", { style: { display: "flex", flexDirection: "column", gap: 5, flex: 1, minWidth: 0 }, children: [
680
+ /* @__PURE__ */ jsx13(
681
+ "span",
682
+ {
683
+ style: {
684
+ fontSize: "var(--font-size-base)",
685
+ fontWeight: selected ? 600 : 500,
686
+ color: selected ? "var(--color-text-primary)" : "var(--color-text-secondary)"
687
+ },
688
+ children: name
689
+ }
690
+ ),
691
+ /* @__PURE__ */ jsx13(
692
+ "span",
693
+ {
694
+ style: {
695
+ fontFamily: "var(--font-family-mono)",
696
+ fontSize: "var(--font-size-2xs)",
697
+ color: "var(--color-text-faint)",
698
+ paddingLeft: dense ? 0 : 15
699
+ },
700
+ children: notesLabel
701
+ }
702
+ )
703
+ ] })
704
+ ]
705
+ }
706
+ ),
707
+ onMenuClick && /* @__PURE__ */ jsx13("div", { style: { position: "absolute", top: 8, right: 6 }, children: /* @__PURE__ */ jsx13(
708
+ IconButton,
709
+ {
710
+ title: "Topic options",
711
+ onClick: (e) => {
712
+ e.stopPropagation();
713
+ onMenuClick(e);
714
+ },
715
+ size: 22,
716
+ radius: "var(--radius-sm)",
717
+ children: "\u22EF"
718
+ }
719
+ ) })
720
+ ]
721
+ }
722
+ );
723
+ }
724
+
725
+ // src/components/NoteRow/NoteRow.tsx
726
+ import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
727
+ function NoteRow({
728
+ title,
729
+ meta,
730
+ selected = false,
731
+ showTopic = false,
732
+ topicColor,
733
+ topicName,
734
+ tags = [],
735
+ onClick,
736
+ onMenuClick,
737
+ draggable = true,
738
+ onDragStart,
739
+ style,
740
+ ...rest
741
+ }) {
742
+ return /* @__PURE__ */ jsxs6(
743
+ "div",
744
+ {
745
+ ...rest,
746
+ style: {
747
+ display: "flex",
748
+ alignItems: "flex-start",
749
+ gap: 8,
750
+ padding: "9px 32px 9px 8px",
751
+ borderRadius: "var(--radius-row)",
752
+ background: selected ? "var(--color-surface-sunken)" : "transparent",
753
+ position: "relative",
754
+ ...style
755
+ },
756
+ children: [
757
+ draggable && /* @__PURE__ */ jsx14(DragHandle, { onDragStart, style: { marginTop: 1 } }),
758
+ /* @__PURE__ */ jsxs6(
759
+ "button",
760
+ {
761
+ type: "button",
762
+ onClick,
763
+ style: {
764
+ display: "flex",
765
+ flexDirection: "column",
766
+ gap: 4,
767
+ flex: 1,
768
+ minWidth: 0,
769
+ border: "none",
770
+ background: "none",
771
+ padding: 0,
772
+ textAlign: "left",
773
+ font: "inherit",
774
+ cursor: "pointer"
775
+ },
776
+ children: [
777
+ showTopic && /* @__PURE__ */ jsxs6("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
778
+ /* @__PURE__ */ jsx14("span", { style: { width: 6, height: 6, borderRadius: "50%", background: topicColor } }),
779
+ /* @__PURE__ */ jsx14(
780
+ "span",
781
+ {
782
+ style: {
783
+ fontFamily: "var(--font-family-mono)",
784
+ fontSize: "9px",
785
+ letterSpacing: "0.08em",
786
+ color: "var(--color-text-faint)",
787
+ textTransform: "uppercase"
788
+ },
789
+ children: topicName
790
+ }
791
+ )
792
+ ] }),
793
+ /* @__PURE__ */ jsx14(
794
+ "span",
795
+ {
796
+ style: {
797
+ fontSize: "var(--font-size-base)",
798
+ lineHeight: 1.4,
799
+ fontWeight: selected ? 600 : 500,
800
+ color: selected ? "var(--color-text-primary)" : "var(--color-text-secondary)"
801
+ },
802
+ children: title
803
+ }
804
+ ),
805
+ /* @__PURE__ */ jsx14("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-2xs)", color: "var(--color-text-faint)" }, children: meta }),
806
+ tags.length > 0 && !selected && /* @__PURE__ */ jsx14("span", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginTop: 1 }, children: tags.map((t, i) => /* @__PURE__ */ jsxs6(
807
+ "span",
808
+ {
809
+ style: {
810
+ fontFamily: "var(--font-family-mono)",
811
+ fontSize: "9px",
812
+ color: t.color,
813
+ background: `color-mix(in srgb, ${t.color} 14%, transparent)`,
814
+ padding: "1px 7px",
815
+ borderRadius: "var(--radius-pill)"
816
+ },
817
+ children: [
818
+ "#",
819
+ t.label
820
+ ]
821
+ },
822
+ `${t.label}-${i}`
823
+ )) })
824
+ ]
825
+ }
826
+ ),
827
+ onMenuClick && /* @__PURE__ */ jsx14("div", { style: { position: "absolute", top: 7, right: 4 }, children: /* @__PURE__ */ jsx14(
828
+ IconButton,
829
+ {
830
+ title: "Concept options",
831
+ onClick: (e) => {
832
+ e.stopPropagation();
833
+ onMenuClick(e);
834
+ },
835
+ size: 22,
836
+ radius: "var(--radius-sm)",
837
+ children: "\u22EF"
838
+ }
839
+ ) })
840
+ ]
841
+ }
842
+ );
843
+ }
844
+
845
+ // src/components/ContextMenu/ContextMenu.tsx
846
+ import { useEffect, useRef as useRef2, useState as useState2 } from "react";
847
+ import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
848
+ function ContextMenu({
849
+ items = [],
850
+ swatches,
851
+ width = 176,
852
+ style,
853
+ onClose,
854
+ "aria-label": ariaLabel,
855
+ ...rest
856
+ }) {
857
+ const nonDividerCount = items.filter((it) => !it.divider).length;
858
+ const itemFocusIndex = items.map((it, i) => it.divider ? -1 : items.slice(0, i).filter((x) => !x.divider).length);
859
+ const swatchFocusIndex = (swatches ?? []).map((_, i) => nonDividerCount + i);
860
+ const focusableCount = nonDividerCount + (swatches?.length ?? 0);
861
+ const controlRefs = useRef2([]);
862
+ const [activeIndex, setActiveIndex] = useState2(0);
863
+ useEffect(() => {
864
+ controlRefs.current[0]?.focus();
865
+ }, []);
866
+ const focusIndex = (index) => {
867
+ const clamped = (index + focusableCount) % focusableCount;
868
+ controlRefs.current[clamped]?.focus();
869
+ };
870
+ const handleKeyDown = (event) => {
871
+ if (event.key === "Escape") {
872
+ onClose?.();
873
+ return;
874
+ }
875
+ if (focusableCount === 0) return;
876
+ if (event.key === "ArrowDown") {
877
+ event.preventDefault();
878
+ focusIndex(activeIndex + 1);
879
+ } else if (event.key === "ArrowUp") {
880
+ event.preventDefault();
881
+ focusIndex(activeIndex - 1);
882
+ } else if (event.key === "Home") {
883
+ event.preventDefault();
884
+ focusIndex(0);
885
+ } else if (event.key === "End") {
886
+ event.preventDefault();
887
+ focusIndex(focusableCount - 1);
888
+ }
889
+ };
890
+ return /* @__PURE__ */ jsxs7(
891
+ "div",
892
+ {
893
+ role: "menu",
894
+ tabIndex: -1,
895
+ "aria-label": ariaLabel,
896
+ onClick: (e) => e.stopPropagation(),
897
+ onKeyDown: handleKeyDown,
898
+ ...rest,
899
+ style: {
900
+ width,
901
+ background: "var(--color-surface)",
902
+ border: "1px solid var(--border-medium)",
903
+ borderRadius: "var(--radius-xl)",
904
+ boxShadow: "var(--shadow-md)",
905
+ padding: 6,
906
+ display: "flex",
907
+ flexDirection: "column",
908
+ gap: 1,
909
+ ...style
910
+ },
911
+ children: [
912
+ items.map((it, i) => {
913
+ if (it.divider) {
914
+ return /* @__PURE__ */ jsx15("div", { role: "separator", "aria-orientation": "horizontal", style: { height: 1, background: "var(--border-subtle)", margin: "2px 4px" } }, i);
915
+ }
916
+ const index = itemFocusIndex[i];
917
+ return /* @__PURE__ */ jsxs7(
918
+ "button",
919
+ {
920
+ role: "menuitem",
921
+ ref: (el) => {
922
+ controlRefs.current[index] = el;
923
+ },
924
+ tabIndex: activeIndex === index ? 0 : -1,
925
+ onFocus: () => setActiveIndex(index),
926
+ onClick: it.onClick,
927
+ style: {
928
+ textAlign: "left",
929
+ border: "none",
930
+ background: "none",
931
+ borderRadius: "var(--radius-sm)",
932
+ padding: "7px 9px",
933
+ fontFamily: "inherit",
934
+ fontSize: "var(--font-size-base)",
935
+ color: it.danger ? "var(--color-danger)" : "var(--color-text-secondary)"
936
+ },
937
+ children: [
938
+ it.icon && /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", style: { marginRight: 7 }, children: it.icon }),
939
+ it.label
940
+ ]
941
+ },
942
+ i
943
+ );
944
+ }),
945
+ swatches && /* @__PURE__ */ jsx15("div", { role: "group", "aria-label": "Color", style: { display: "flex", gap: 5, padding: "7px 9px 4px" }, children: swatches.map((sw, i) => {
946
+ const index = swatchFocusIndex[i];
947
+ return /* @__PURE__ */ jsx15(
948
+ ColorSwatch,
949
+ {
950
+ ref: (el) => {
951
+ controlRefs.current[index] = el;
952
+ },
953
+ tabIndex: activeIndex === index ? 0 : -1,
954
+ onFocus: () => setActiveIndex(index),
955
+ color: sw.color,
956
+ active: sw.active,
957
+ onClick: sw.pick,
958
+ role: "menuitemradio",
959
+ "aria-checked": !!sw.active
960
+ },
961
+ i
962
+ );
963
+ }) })
964
+ ]
965
+ }
966
+ );
967
+ }
968
+
969
+ // src/internal/useDialog.ts
970
+ import { useEffect as useEffect2, useRef as useRef3 } from "react";
971
+ var FOCUSABLE_SELECTOR = [
972
+ "a[href]",
973
+ "button:not([disabled])",
974
+ "input:not([disabled])",
975
+ "select:not([disabled])",
976
+ "textarea:not([disabled])",
977
+ '[tabindex]:not([tabindex="-1"])'
978
+ ].join(",");
979
+ function useDialog({ open, onClose }) {
980
+ const containerRef = useRef3(null);
981
+ const previouslyFocusedRef = useRef3(null);
982
+ useEffect2(() => {
983
+ if (!open) return;
984
+ previouslyFocusedRef.current = document.activeElement;
985
+ const container = containerRef.current;
986
+ const focusables = container?.querySelectorAll(FOCUSABLE_SELECTOR);
987
+ (focusables?.[0] ?? container)?.focus();
988
+ return () => {
989
+ previouslyFocusedRef.current?.focus?.();
990
+ };
991
+ }, [open]);
992
+ useEffect2(() => {
993
+ if (!open) return;
994
+ const handleKeyDown = (event) => {
995
+ if (event.key === "Escape") {
996
+ if (containerRef.current?.contains(document.activeElement)) {
997
+ onClose?.();
998
+ }
999
+ return;
1000
+ }
1001
+ if (event.key !== "Tab") return;
1002
+ const container = containerRef.current;
1003
+ if (!container) return;
1004
+ const focusables = Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
1005
+ if (focusables.length === 0) {
1006
+ event.preventDefault();
1007
+ return;
1008
+ }
1009
+ const first = focusables[0];
1010
+ const last = focusables[focusables.length - 1];
1011
+ if (event.shiftKey && document.activeElement === first) {
1012
+ event.preventDefault();
1013
+ last.focus();
1014
+ } else if (!event.shiftKey && document.activeElement === last) {
1015
+ event.preventDefault();
1016
+ first.focus();
1017
+ }
1018
+ };
1019
+ document.addEventListener("keydown", handleKeyDown);
1020
+ return () => document.removeEventListener("keydown", handleKeyDown);
1021
+ }, [open, onClose]);
1022
+ return containerRef;
1023
+ }
1024
+
1025
+ // src/components/BottomSheet/BottomSheet.tsx
1026
+ import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
1027
+ function BottomSheet({
1028
+ open,
1029
+ onClose,
1030
+ children,
1031
+ maxHeight = "70%",
1032
+ style,
1033
+ "aria-label": ariaLabel,
1034
+ ...rest
1035
+ }) {
1036
+ const dialogRef = useDialog({ open, onClose });
1037
+ if (!open) return null;
1038
+ return (
1039
+ // Escape (handled by useDialog) is the keyboard-equivalent way to
1040
+ // dismiss the sheet; clicking the backdrop is a mouse-only convenience,
1041
+ // not the only way to close it.
1042
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
1043
+ /* @__PURE__ */ jsx16(
1044
+ "div",
1045
+ {
1046
+ onClick: onClose,
1047
+ style: { position: "absolute", inset: 0, zIndex: 60, background: "rgba(24,23,20,0.4)", display: "flex", alignItems: "flex-end" },
1048
+ children: /* @__PURE__ */ jsxs8(
1049
+ "div",
1050
+ {
1051
+ ref: dialogRef,
1052
+ role: "dialog",
1053
+ "aria-modal": "true",
1054
+ "aria-label": ariaLabel,
1055
+ tabIndex: -1,
1056
+ onClick: (e) => e.stopPropagation(),
1057
+ ...rest,
1058
+ style: {
1059
+ width: "100%",
1060
+ boxSizing: "border-box",
1061
+ background: "var(--color-background)",
1062
+ borderRadius: "var(--radius-surface) var(--radius-surface) 0 0",
1063
+ padding: "18px 18px 26px",
1064
+ display: "flex",
1065
+ flexDirection: "column",
1066
+ gap: 12,
1067
+ maxHeight,
1068
+ overflowY: "auto",
1069
+ boxShadow: "var(--shadow-sheet)",
1070
+ ...style
1071
+ },
1072
+ children: [
1073
+ /* @__PURE__ */ jsx16("div", { "aria-hidden": "true", style: { width: 36, height: 4, borderRadius: 2, background: "rgba(17,17,17,0.15)", margin: "0 auto 4px" } }),
1074
+ children
1075
+ ]
1076
+ }
1077
+ )
1078
+ }
1079
+ )
1080
+ );
1081
+ }
1082
+
1083
+ // src/components/ImportExportModal/ImportExportModal.tsx
1084
+ import { useEffect as useEffect3, useRef as useRef4 } from "react";
1085
+ import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
1086
+ var TAB_ORDER2 = ["import", "export"];
1087
+ var TAB_LABEL2 = { import: "IMPORT", export: "EXPORT" };
1088
+ function ImportExportModal({ open, tab = "import", onTabChange, onClose, children, ...rest }) {
1089
+ const dialogRef = useDialog({ open, onClose });
1090
+ const tabRefs = useRef4({});
1091
+ useEffect3(() => {
1092
+ if (!open) return;
1093
+ const original = document.body.style.overflow;
1094
+ document.body.style.overflow = "hidden";
1095
+ return () => {
1096
+ document.body.style.overflow = original;
1097
+ };
1098
+ }, [open]);
1099
+ if (!open) return null;
1100
+ const selectTab = (id) => onTabChange?.(id);
1101
+ const handleTabKeyDown = (event, id) => {
1102
+ const currentIndex = TAB_ORDER2.indexOf(id);
1103
+ let nextIndex = null;
1104
+ if (event.key === "ArrowRight") nextIndex = (currentIndex + 1) % TAB_ORDER2.length;
1105
+ else if (event.key === "ArrowLeft") nextIndex = (currentIndex - 1 + TAB_ORDER2.length) % TAB_ORDER2.length;
1106
+ else if (event.key === "Home") nextIndex = 0;
1107
+ else if (event.key === "End") nextIndex = TAB_ORDER2.length - 1;
1108
+ if (nextIndex !== null) {
1109
+ event.preventDefault();
1110
+ const nextId = TAB_ORDER2[nextIndex];
1111
+ selectTab(nextId);
1112
+ tabRefs.current[nextId]?.focus();
1113
+ }
1114
+ };
1115
+ return (
1116
+ // Escape (handled by useDialog) is the keyboard-equivalent way to
1117
+ // dismiss the modal; clicking the backdrop is a mouse-only convenience,
1118
+ // not the only way to close it.
1119
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
1120
+ /* @__PURE__ */ jsx17(
1121
+ "div",
1122
+ {
1123
+ onClick: onClose,
1124
+ style: { position: "fixed", inset: 0, zIndex: 100, background: "rgba(24,23,20,0.42)", display: "flex", alignItems: "center", justifyContent: "center", padding: 24 },
1125
+ children: /* @__PURE__ */ jsxs9(
1126
+ "div",
1127
+ {
1128
+ ref: dialogRef,
1129
+ role: "dialog",
1130
+ "aria-modal": "true",
1131
+ "aria-label": "Import or export notes",
1132
+ tabIndex: -1,
1133
+ onClick: (e) => e.stopPropagation(),
1134
+ ...rest,
1135
+ style: {
1136
+ width: 640,
1137
+ maxWidth: "100%",
1138
+ maxHeight: "86vh",
1139
+ background: "var(--color-background)",
1140
+ borderRadius: "var(--radius-surface)",
1141
+ boxShadow: "var(--shadow-lg)",
1142
+ padding: "20px 24px 22px",
1143
+ boxSizing: "border-box",
1144
+ display: "flex",
1145
+ flexDirection: "column",
1146
+ gap: 14,
1147
+ overflowY: "auto"
1148
+ },
1149
+ children: [
1150
+ /* @__PURE__ */ jsxs9("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1151
+ /* @__PURE__ */ jsx17(
1152
+ "div",
1153
+ {
1154
+ role: "tablist",
1155
+ "aria-label": "Import or export",
1156
+ style: { display: "flex", alignItems: "center", gap: 4, background: "var(--color-stone-100)", borderRadius: "var(--radius-pill)", padding: 3 },
1157
+ children: TAB_ORDER2.map((id) => /* @__PURE__ */ jsx17(
1158
+ "button",
1159
+ {
1160
+ ref: (el) => {
1161
+ tabRefs.current[id] = el;
1162
+ },
1163
+ type: "button",
1164
+ role: "tab",
1165
+ "aria-selected": tab === id,
1166
+ tabIndex: tab === id ? 0 : -1,
1167
+ onClick: () => selectTab(id),
1168
+ onKeyDown: (e) => handleTabKeyDown(e, id),
1169
+ style: {
1170
+ border: "none",
1171
+ borderRadius: 17,
1172
+ padding: "6px 16px",
1173
+ fontFamily: "var(--font-family-mono)",
1174
+ fontSize: "var(--font-size-sm)",
1175
+ letterSpacing: "0.1em",
1176
+ background: tab === id ? "var(--color-ink-900)" : "transparent",
1177
+ color: tab === id ? "var(--color-cream-50)" : "var(--color-text-muted)"
1178
+ },
1179
+ children: TAB_LABEL2[id]
1180
+ },
1181
+ id
1182
+ ))
1183
+ }
1184
+ ),
1185
+ /* @__PURE__ */ jsx17(IconButton, { title: "Close", onClick: onClose, children: "\xD7" })
1186
+ ] }),
1187
+ children
1188
+ ]
1189
+ }
1190
+ )
1191
+ }
1192
+ )
1193
+ );
1194
+ }
1195
+ function ExportRow({ title, sub, onCopy, copyLabel = "COPY", onDownload }) {
1196
+ return /* @__PURE__ */ jsxs9("div", { style: { display: "flex", alignItems: "center", gap: 12, background: "var(--color-surface)", border: "1px solid var(--border-default)", borderRadius: "var(--radius-xl)", padding: "12px 16px" }, children: [
1197
+ /* @__PURE__ */ jsxs9("div", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 2 }, children: [
1198
+ /* @__PURE__ */ jsx17("span", { style: { fontSize: "var(--font-size-base)", fontWeight: 600, color: "var(--color-text-primary)" }, children: title }),
1199
+ /* @__PURE__ */ jsx17("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-sm)", color: "var(--color-text-faint)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: sub })
1200
+ ] }),
1201
+ /* @__PURE__ */ jsx17(
1202
+ "button",
1203
+ {
1204
+ type: "button",
1205
+ onClick: onCopy,
1206
+ style: { border: "1px solid var(--border-medium)", background: "var(--color-surface)", color: "var(--color-text-secondary)", fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "0.08em", padding: "7px 14px", borderRadius: "var(--radius-md)" },
1207
+ children: copyLabel
1208
+ }
1209
+ ),
1210
+ /* @__PURE__ */ jsx17(
1211
+ "button",
1212
+ {
1213
+ type: "button",
1214
+ onClick: onDownload,
1215
+ style: { border: "none", background: "var(--color-ink-900)", color: "var(--color-cream-50)", fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "0.08em", padding: "8px 14px", borderRadius: "var(--radius-md)" },
1216
+ children: "DOWNLOAD"
1217
+ }
1218
+ )
1219
+ ] });
1220
+ }
1221
+
1222
+ // src/components/TocRail/TocRail.tsx
1223
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
1224
+ function TocRail({
1225
+ items,
1226
+ hovered,
1227
+ onHoverIn,
1228
+ onHoverOut,
1229
+ "aria-label": ariaLabel = "Page outline",
1230
+ style,
1231
+ ...rest
1232
+ }) {
1233
+ return /* @__PURE__ */ jsx18(
1234
+ "nav",
1235
+ {
1236
+ "aria-label": ariaLabel,
1237
+ onMouseEnter: onHoverIn,
1238
+ onMouseLeave: onHoverOut,
1239
+ onFocus: onHoverIn,
1240
+ onBlur: (e) => {
1241
+ if (!e.currentTarget.contains(e.relatedTarget)) onHoverOut?.();
1242
+ },
1243
+ ...rest,
1244
+ style: { padding: "6px 4px", ...style },
1245
+ children: /* @__PURE__ */ jsx18("ol", { role: "list", style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 10 }, children: items.map((t, i) => /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsxs10(
1246
+ "button",
1247
+ {
1248
+ onClick: t.go,
1249
+ "aria-current": t.active ? "true" : void 0,
1250
+ style: {
1251
+ display: "flex",
1252
+ alignItems: "center",
1253
+ gap: 8,
1254
+ border: "none",
1255
+ background: "none",
1256
+ padding: "2px 4px",
1257
+ fontFamily: "var(--font-family-mono)",
1258
+ fontSize: "var(--font-size-sm)",
1259
+ textAlign: "left"
1260
+ },
1261
+ children: [
1262
+ /* @__PURE__ */ jsx18(
1263
+ "span",
1264
+ {
1265
+ "aria-hidden": "true",
1266
+ style: {
1267
+ width: 7,
1268
+ height: 7,
1269
+ borderRadius: "50%",
1270
+ flexShrink: 0,
1271
+ background: t.active ? "var(--color-accent)" : "rgba(17,17,17,0.22)",
1272
+ transform: t.active ? "scale(1.4)" : "scale(1)"
1273
+ }
1274
+ }
1275
+ ),
1276
+ /* @__PURE__ */ jsx18(
1277
+ "span",
1278
+ {
1279
+ style: {
1280
+ width: hovered ? 82 : 0,
1281
+ overflow: "hidden",
1282
+ whiteSpace: "nowrap",
1283
+ color: t.active ? "var(--color-accent)" : "var(--color-text-muted)",
1284
+ fontWeight: t.active ? 600 : 500,
1285
+ transition: "width var(--duration-standard) var(--ease-standard)"
1286
+ },
1287
+ children: t.label
1288
+ }
1289
+ )
1290
+ ]
1291
+ }
1292
+ ) }, i)) })
1293
+ }
1294
+ );
1295
+ }
1296
+
1297
+ // src/components/TocFab/TocFab.tsx
1298
+ import { jsx as jsx19 } from "react/jsx-runtime";
1299
+ function TocFab({ onClick, "aria-label": ariaLabel = "Open outline", style, ...rest }) {
1300
+ return /* @__PURE__ */ jsx19(
1301
+ "button",
1302
+ {
1303
+ type: "button",
1304
+ onClick,
1305
+ "aria-label": ariaLabel,
1306
+ ...rest,
1307
+ style: {
1308
+ position: "absolute",
1309
+ right: 16,
1310
+ bottom: 16,
1311
+ width: 46,
1312
+ height: 46,
1313
+ borderRadius: "50%",
1314
+ border: "none",
1315
+ background: "var(--color-surface-inverse)",
1316
+ color: "var(--color-text-on-inverse)",
1317
+ fontSize: 17,
1318
+ boxShadow: "var(--shadow-fab)",
1319
+ display: "flex",
1320
+ alignItems: "center",
1321
+ justifyContent: "center",
1322
+ zIndex: 20,
1323
+ ...style
1324
+ },
1325
+ children: /* @__PURE__ */ jsx19("span", { "aria-hidden": "true", children: "\u2630" })
1326
+ }
1327
+ );
1328
+ }
1329
+
1330
+ // src/components/TocSheetList/TocSheetList.tsx
1331
+ import { useId as useId2 } from "react";
1332
+ import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
1333
+ function TocSheetList({ items }) {
1334
+ const headingId = useId2();
1335
+ return /* @__PURE__ */ jsxs11("nav", { "aria-labelledby": headingId, children: [
1336
+ /* @__PURE__ */ jsx20(
1337
+ "div",
1338
+ {
1339
+ id: headingId,
1340
+ style: {
1341
+ fontFamily: "var(--font-family-mono)",
1342
+ fontSize: "var(--font-size-xs)",
1343
+ letterSpacing: "var(--letter-spacing-mono-wide)",
1344
+ color: "var(--color-text-muted)",
1345
+ marginBottom: 6
1346
+ },
1347
+ children: "OUTLINE"
1348
+ }
1349
+ ),
1350
+ /* @__PURE__ */ jsx20("ol", { role: "list", style: { listStyle: "none", margin: 0, padding: 0 }, children: items.map((t, i) => /* @__PURE__ */ jsx20("li", { children: /* @__PURE__ */ jsxs11(
1351
+ "button",
1352
+ {
1353
+ onClick: t.go,
1354
+ "aria-current": t.active ? "true" : void 0,
1355
+ style: {
1356
+ display: "flex",
1357
+ alignItems: "center",
1358
+ gap: 10,
1359
+ border: "none",
1360
+ background: "none",
1361
+ padding: "10px 4px",
1362
+ fontFamily: "var(--font-family-mono)",
1363
+ fontSize: "var(--font-size-base)",
1364
+ textAlign: "left",
1365
+ width: "100%",
1366
+ boxSizing: "border-box"
1367
+ },
1368
+ children: [
1369
+ /* @__PURE__ */ jsx20(
1370
+ "span",
1371
+ {
1372
+ "aria-hidden": "true",
1373
+ style: { width: 7, height: 7, borderRadius: "50%", flexShrink: 0, background: t.active ? "var(--color-accent)" : "rgba(17,17,17,0.22)" }
1374
+ }
1375
+ ),
1376
+ /* @__PURE__ */ jsx20("span", { style: { color: t.active ? "var(--color-accent)" : "var(--color-text-muted)", fontWeight: t.active ? 600 : 500 }, children: t.label })
1377
+ ]
1378
+ }
1379
+ ) }, i)) })
1380
+ ] });
1381
+ }
1382
+
1383
+ // src/components/CardShell/CardShell.tsx
1384
+ import { jsx as jsx21 } from "react/jsx-runtime";
1385
+ function CardShell({ children, dark = false, tint = false, style, ...rest }) {
1386
+ return /* @__PURE__ */ jsx21(
1387
+ "div",
1388
+ {
1389
+ ...rest,
1390
+ style: {
1391
+ background: dark ? "var(--color-surface-code)" : tint ? "var(--color-accent-tint)" : "var(--color-surface)",
1392
+ border: dark ? "none" : `1px solid ${tint ? "color-mix(in srgb, var(--color-accent) 22%, transparent)" : "var(--border-default)"}`,
1393
+ borderRadius: "var(--radius-card)",
1394
+ margin: "24px 0",
1395
+ ...style
1396
+ },
1397
+ children
1398
+ }
1399
+ );
1400
+ }
1401
+
1402
+ // src/components/CardHeader/CardHeader.tsx
1403
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
1404
+ function CardHeader({
1405
+ eyebrow,
1406
+ eyebrowColor = "var(--color-accent)",
1407
+ title,
1408
+ as: TitleTag = "span",
1409
+ subtitle,
1410
+ right,
1411
+ dark = false,
1412
+ style,
1413
+ ...rest
1414
+ }) {
1415
+ return /* @__PURE__ */ jsxs12("div", { ...rest, style: { display: "flex", alignItems: "baseline", gap: 10, padding: "13px 16px 9px", minWidth: 0, ...style }, children: [
1416
+ /* @__PURE__ */ jsx22(
1417
+ "span",
1418
+ {
1419
+ style: {
1420
+ fontFamily: "var(--font-family-mono)",
1421
+ fontSize: "var(--font-size-xs)",
1422
+ letterSpacing: "var(--letter-spacing-mono-wide)",
1423
+ color: eyebrowColor,
1424
+ whiteSpace: "nowrap",
1425
+ flexShrink: 0
1426
+ },
1427
+ children: eyebrow
1428
+ }
1429
+ ),
1430
+ title && /* @__PURE__ */ jsx22(
1431
+ TitleTag,
1432
+ {
1433
+ style: {
1434
+ margin: 0,
1435
+ fontSize: "var(--font-size-base)",
1436
+ fontWeight: 600,
1437
+ color: dark ? "#EDEBE3" : "var(--color-text-primary)",
1438
+ whiteSpace: "nowrap",
1439
+ overflow: "hidden",
1440
+ textOverflow: "ellipsis",
1441
+ minWidth: 0
1442
+ },
1443
+ children: title
1444
+ }
1445
+ ),
1446
+ subtitle && /* @__PURE__ */ jsx22("span", { style: { fontSize: "var(--font-size-md)", color: dark ? "var(--color-ink-500)" : "var(--color-text-faint)", whiteSpace: "nowrap", flexShrink: 0 }, children: subtitle }),
1447
+ /* @__PURE__ */ jsx22("span", { style: { flex: 1, minWidth: 4 } }),
1448
+ right
1449
+ ] });
1450
+ }
1451
+
1452
+ // src/components/TextBlock/TextBlock.tsx
1453
+ import { jsx as jsx23 } from "react/jsx-runtime";
1454
+ function TextBlock({ text, style, ...rest }) {
1455
+ return /* @__PURE__ */ jsx23("p", { ...rest, style: { margin: "18px 0", color: "var(--color-text-body)", textWrap: "pretty", ...style }, children: text });
1456
+ }
1457
+
1458
+ // src/components/EquationBlock/EquationBlock.tsx
1459
+ import { jsx as jsx24 } from "react/jsx-runtime";
1460
+ function EquationBlock({ tex, style, ...rest }) {
1461
+ return /* @__PURE__ */ jsx24("div", { ...rest, style: { margin: "18px 0", textAlign: "center", padding: "10px 0", ...style }, children: /* @__PURE__ */ jsx24("span", { style: { fontFamily: "Georgia, serif", fontStyle: "italic", fontSize: "17px", color: "var(--color-text-primary)" }, children: tex }) });
1462
+ }
1463
+
1464
+ // src/components/IntuitionCallout/IntuitionCallout.tsx
1465
+ import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
1466
+ function IntuitionCallout({ text, label = "INTUITION", style, ...rest }) {
1467
+ return /* @__PURE__ */ jsxs13(
1468
+ "div",
1469
+ {
1470
+ ...rest,
1471
+ style: {
1472
+ margin: "18px 0",
1473
+ padding: "13px 16px",
1474
+ borderRadius: "var(--radius-lg)",
1475
+ background: "var(--color-warning-tint)",
1476
+ border: "1px solid var(--color-warning-border)",
1477
+ fontSize: "var(--font-size-lg)",
1478
+ color: "var(--color-text-secondary)",
1479
+ ...style
1480
+ },
1481
+ children: [
1482
+ /* @__PURE__ */ jsx25("span", { style: { display: "block", fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "0.12em", color: "var(--color-warning)", marginBottom: 6 }, children: label }),
1483
+ text
1484
+ ]
1485
+ }
1486
+ );
1487
+ }
1488
+
1489
+ // src/components/WalkthroughCard/WalkthroughCard.tsx
1490
+ import { jsx as jsx26, jsxs as jsxs14 } from "react/jsx-runtime";
1491
+ function WalkthroughCard({ title, steps, currentStep, onPrev, onNext, style, ...rest }) {
1492
+ const visible = steps.slice(0, currentStep + 1);
1493
+ const atStart = currentStep === 0;
1494
+ const atEnd = currentStep === steps.length - 1;
1495
+ return /* @__PURE__ */ jsxs14(
1496
+ "div",
1497
+ {
1498
+ ...rest,
1499
+ style: {
1500
+ background: "var(--color-surface)",
1501
+ border: "1px solid var(--border-default)",
1502
+ borderRadius: "var(--radius-card)",
1503
+ margin: "24px 0",
1504
+ padding: "16px 20px 14px",
1505
+ ...style
1506
+ },
1507
+ children: [
1508
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 12 }, children: [
1509
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "baseline", gap: 10 }, children: [
1510
+ /* @__PURE__ */ jsx26("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wide)", color: "var(--color-accent)" }, children: "WALKTHROUGH" }),
1511
+ /* @__PURE__ */ jsx26("span", { style: { fontSize: "var(--font-size-base)", fontWeight: 600, color: "var(--color-text-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 }, children: title })
1512
+ ] }),
1513
+ /* @__PURE__ */ jsxs14("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-sm)", color: "var(--color-text-faint)", whiteSpace: "nowrap" }, children: [
1514
+ "STEP ",
1515
+ currentStep + 1,
1516
+ " OF ",
1517
+ steps.length
1518
+ ] })
1519
+ ] }),
1520
+ /* @__PURE__ */ jsx26("div", { "aria-live": "polite", children: visible.map((s, i) => /* @__PURE__ */ jsxs14(
1521
+ "div",
1522
+ {
1523
+ style: {
1524
+ display: "grid",
1525
+ gridTemplateColumns: "26px 1fr",
1526
+ gap: 12,
1527
+ padding: "9px 0",
1528
+ borderTop: "1px solid var(--border-subtle)",
1529
+ opacity: i === currentStep ? 1 : 0.65
1530
+ },
1531
+ children: [
1532
+ /* @__PURE__ */ jsx26(
1533
+ "span",
1534
+ {
1535
+ style: {
1536
+ width: 24,
1537
+ height: 24,
1538
+ borderRadius: "50%",
1539
+ display: "flex",
1540
+ alignItems: "center",
1541
+ justifyContent: "center",
1542
+ fontFamily: "var(--font-family-mono)",
1543
+ fontSize: "var(--font-size-sm)",
1544
+ marginTop: 4,
1545
+ background: i === currentStep ? "var(--color-accent)" : "var(--color-stone-100)",
1546
+ color: i === currentStep ? "#fff" : "var(--color-text-faint)"
1547
+ },
1548
+ children: i + 1
1549
+ }
1550
+ ),
1551
+ /* @__PURE__ */ jsxs14("div", { style: { minWidth: 0 }, children: [
1552
+ /* @__PURE__ */ jsx26("div", { style: { fontFamily: "Georgia, serif", fontStyle: "italic", textAlign: "center", fontSize: 15, color: "var(--color-text-primary)" }, children: s.tex }),
1553
+ /* @__PURE__ */ jsx26("div", { style: { fontSize: "var(--font-size-base)", color: "var(--color-text-muted)", textAlign: "center" }, children: s.note })
1554
+ ] })
1555
+ ]
1556
+ },
1557
+ i
1558
+ )) }),
1559
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 12 }, children: [
1560
+ /* @__PURE__ */ jsx26(
1561
+ "button",
1562
+ {
1563
+ type: "button",
1564
+ onClick: onPrev,
1565
+ disabled: atStart,
1566
+ style: {
1567
+ border: "1px solid var(--border-strong)",
1568
+ background: "#fff",
1569
+ borderRadius: "var(--radius-sm)",
1570
+ padding: "5px 14px",
1571
+ fontFamily: "var(--font-family-mono)",
1572
+ fontSize: "var(--font-size-sm)",
1573
+ color: "var(--color-text-secondary)",
1574
+ opacity: atStart ? 0.4 : 1
1575
+ },
1576
+ children: "\u2039 Back"
1577
+ }
1578
+ ),
1579
+ /* @__PURE__ */ jsx26(
1580
+ "button",
1581
+ {
1582
+ type: "button",
1583
+ onClick: onNext,
1584
+ disabled: atEnd,
1585
+ style: {
1586
+ border: "none",
1587
+ background: "var(--color-accent)",
1588
+ borderRadius: "var(--radius-sm)",
1589
+ padding: "6px 16px",
1590
+ fontFamily: "var(--font-family-mono)",
1591
+ fontSize: "var(--font-size-sm)",
1592
+ color: "#fff",
1593
+ opacity: atEnd ? 0.4 : 1
1594
+ },
1595
+ children: atEnd ? "Done \u2713" : "Next step \u203A"
1596
+ }
1597
+ )
1598
+ ] })
1599
+ ]
1600
+ }
1601
+ );
1602
+ }
1603
+
1604
+ // src/components/CodeCard/CodeCard.tsx
1605
+ import { jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
1606
+ function CodeCard({ title, lang, code, copyLabel = "Copy", onCopy, style, ...rest }) {
1607
+ return /* @__PURE__ */ jsxs15("div", { ...rest, style: { background: "var(--color-surface-code)", borderRadius: "var(--radius-card)", margin: "24px 0", overflow: "hidden", ...style }, children: [
1608
+ /* @__PURE__ */ jsxs15("div", { style: { display: "flex", alignItems: "baseline", gap: 10, padding: "12px 18px", minWidth: 0 }, children: [
1609
+ /* @__PURE__ */ jsx27("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wide)", color: "var(--color-code-green)", whiteSpace: "nowrap", flexShrink: 0 }, children: "CODE" }),
1610
+ /* @__PURE__ */ jsx27("span", { style: { fontSize: "var(--font-size-base)", fontWeight: 600, color: "#EDEBE3", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 }, children: title }),
1611
+ /* @__PURE__ */ jsx27("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-sm)", color: "var(--color-ink-500)", whiteSpace: "nowrap", flexShrink: 0 }, children: lang }),
1612
+ /* @__PURE__ */ jsx27("span", { style: { flex: 1, minWidth: 4 } }),
1613
+ /* @__PURE__ */ jsx27(
1614
+ "button",
1615
+ {
1616
+ type: "button",
1617
+ onClick: onCopy,
1618
+ style: { border: "none", background: "none", fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-sm)", color: "var(--color-ink-400)", padding: "2px 7px", borderRadius: 5, whiteSpace: "nowrap", flexShrink: 0 },
1619
+ children: copyLabel
1620
+ }
1621
+ )
1622
+ ] }),
1623
+ /* @__PURE__ */ jsx27("pre", { style: { margin: 0, padding: "4px 20px 18px", overflowX: "auto", fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-base)", lineHeight: "var(--line-height-relaxed)", color: "var(--color-text-on-code)", whiteSpace: "pre-wrap" }, children: code })
1624
+ ] });
1625
+ }
1626
+
1627
+ // src/components/TableCard/TableCard.tsx
1628
+ import { jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
1629
+ var srOnly = {
1630
+ position: "absolute",
1631
+ width: 1,
1632
+ height: 1,
1633
+ padding: 0,
1634
+ margin: -1,
1635
+ overflow: "hidden",
1636
+ clip: "rect(0, 0, 0, 0)",
1637
+ whiteSpace: "nowrap",
1638
+ border: 0
1639
+ };
1640
+ function TableCard({ title, header, rows, style, ...rest }) {
1641
+ return /* @__PURE__ */ jsxs16(
1642
+ "div",
1643
+ {
1644
+ ...rest,
1645
+ style: { background: "var(--color-surface)", border: "1px solid var(--border-default)", borderRadius: "var(--radius-card)", margin: "24px 0", padding: "16px 20px 18px", ...style },
1646
+ children: [
1647
+ /* @__PURE__ */ jsxs16("div", { style: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 12 }, children: [
1648
+ /* @__PURE__ */ jsx28("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wide)", color: "var(--color-accent)" }, children: "COMPARE" }),
1649
+ /* @__PURE__ */ jsx28("span", { style: { fontSize: "var(--font-size-base)", fontWeight: 600, color: "var(--color-text-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 }, children: title })
1650
+ ] }),
1651
+ /* @__PURE__ */ jsxs16("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: "var(--font-size-base)" }, children: [
1652
+ /* @__PURE__ */ jsx28("thead", { children: /* @__PURE__ */ jsx28("tr", { children: header.map((h, i) => /* @__PURE__ */ jsx28(
1653
+ "th",
1654
+ {
1655
+ scope: "col",
1656
+ style: {
1657
+ textAlign: "left",
1658
+ padding: "8px 10px",
1659
+ fontWeight: i === 0 ? 400 : 600,
1660
+ color: i === 0 ? "var(--color-text-muted)" : "var(--color-text-primary)",
1661
+ fontFamily: i === 0 ? "var(--font-family-mono)" : "inherit",
1662
+ fontSize: i === 0 ? "var(--font-size-sm)" : "inherit",
1663
+ borderBottom: "1px solid var(--border-subtle)"
1664
+ },
1665
+ children: h || /* @__PURE__ */ jsx28("span", { style: srOnly, children: "Row label" })
1666
+ },
1667
+ i
1668
+ )) }) }),
1669
+ /* @__PURE__ */ jsx28("tbody", { children: rows.map((r, ri) => /* @__PURE__ */ jsx28("tr", { children: r.map((c, ci) => {
1670
+ const cellStyle = {
1671
+ padding: "8px 10px",
1672
+ color: ci === 0 ? "var(--color-text-muted)" : "var(--color-text-secondary)",
1673
+ fontFamily: ci === 0 ? "var(--font-family-mono)" : "inherit",
1674
+ fontSize: ci === 0 ? "var(--font-size-sm)" : "inherit",
1675
+ borderBottom: ri === rows.length - 1 ? "none" : "1px solid var(--border-subtle)"
1676
+ };
1677
+ return ci === 0 ? /* @__PURE__ */ jsx28("th", { scope: "row", style: { ...cellStyle, textAlign: "left", fontWeight: 400 }, children: c }, ci) : /* @__PURE__ */ jsx28("td", { style: cellStyle, children: c }, ci);
1678
+ }) }, ri)) })
1679
+ ] })
1680
+ ]
1681
+ }
1682
+ );
1683
+ }
1684
+
1685
+ // src/components/QuizCard/QuizCard.tsx
1686
+ import { useId as useId3 } from "react";
1687
+ import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
1688
+ function QuizCard({ question, answerOpen, answer, quizLabel, onToggleQuiz, addFlashLabel, onAddFlash, style, ...rest }) {
1689
+ const answerId = useId3();
1690
+ return /* @__PURE__ */ jsxs17(
1691
+ "div",
1692
+ {
1693
+ ...rest,
1694
+ style: {
1695
+ background: "var(--color-accent-tint)",
1696
+ border: "1px solid color-mix(in srgb, var(--color-accent) 22%, transparent)",
1697
+ borderRadius: "var(--radius-card)",
1698
+ margin: "24px 0",
1699
+ padding: "16px 20px 18px",
1700
+ ...style
1701
+ },
1702
+ children: [
1703
+ /* @__PURE__ */ jsxs17("div", { style: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 10 }, children: [
1704
+ /* @__PURE__ */ jsx29("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wide)", color: "var(--color-accent)" }, children: "CHECKPOINT" }),
1705
+ /* @__PURE__ */ jsx29("span", { style: { fontSize: "var(--font-size-base)", fontWeight: 600, color: "var(--color-text-primary)", whiteSpace: "nowrap" }, children: "Still with it?" })
1706
+ ] }),
1707
+ /* @__PURE__ */ jsx29("p", { style: { margin: "0 0 10px", fontSize: "var(--font-size-lg)", color: "var(--color-text-body)" }, children: question }),
1708
+ /* @__PURE__ */ jsx29(
1709
+ "button",
1710
+ {
1711
+ type: "button",
1712
+ onClick: onToggleQuiz,
1713
+ "aria-expanded": answerOpen,
1714
+ "aria-controls": answerId,
1715
+ style: { border: "none", background: "none", padding: 0, fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-base)", color: "var(--color-accent)", whiteSpace: "nowrap" },
1716
+ children: quizLabel
1717
+ }
1718
+ ),
1719
+ /* @__PURE__ */ jsx29(
1720
+ "button",
1721
+ {
1722
+ type: "button",
1723
+ onClick: onAddFlash,
1724
+ style: { marginLeft: 14, border: "none", background: "none", padding: 0, fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-base)", color: "var(--color-text-muted)", whiteSpace: "nowrap" },
1725
+ children: addFlashLabel
1726
+ }
1727
+ ),
1728
+ answerOpen && /* @__PURE__ */ jsx29(
1729
+ "div",
1730
+ {
1731
+ id: answerId,
1732
+ style: {
1733
+ marginTop: 10,
1734
+ padding: "12px 15px",
1735
+ borderRadius: "var(--radius-lg)",
1736
+ background: "var(--color-surface)",
1737
+ border: "1px solid color-mix(in srgb, var(--color-accent) 18%, transparent)",
1738
+ fontSize: "var(--font-size-base)",
1739
+ color: "var(--color-text-secondary)"
1740
+ },
1741
+ children: answer
1742
+ }
1743
+ )
1744
+ ]
1745
+ }
1746
+ );
1747
+ }
1748
+
1749
+ // src/components/ImageCard/ImageCard.tsx
1750
+ import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
1751
+ function ImageCard({ label = "UPLOAD", title, slotId, placeholder, height = 230, caption, style, ...rest }) {
1752
+ return /* @__PURE__ */ jsxs18("div", { ...rest, style: { background: "var(--color-surface)", border: "1px solid var(--border-default)", borderRadius: "var(--radius-card)", margin: "24px 0", padding: "16px 20px 20px", ...style }, children: [
1753
+ /* @__PURE__ */ jsxs18("div", { style: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 12 }, children: [
1754
+ /* @__PURE__ */ jsx30("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wide)", color: "var(--color-accent)" }, children: label }),
1755
+ /* @__PURE__ */ jsx30("span", { style: { fontSize: "var(--font-size-base)", fontWeight: 600, color: "var(--color-text-primary)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 }, children: title })
1756
+ ] }),
1757
+ /* @__PURE__ */ jsx30("image-slot", { id: slotId, shape: "rounded", radius: "10", placeholder, style: { width: "100%", height, display: "block" } }),
1758
+ caption && /* @__PURE__ */ jsx30("div", { style: { marginTop: 8, fontSize: "var(--font-size-md)", color: "var(--color-text-muted)", textAlign: "center" }, children: caption })
1759
+ ] });
1760
+ }
1761
+
1762
+ // src/components/RelatedCard/RelatedCard.tsx
1763
+ import { createElement } from "react";
1764
+ import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
1765
+ function RelatedCard({ items, style, ...rest }) {
1766
+ return /* @__PURE__ */ jsxs19("div", { ...rest, style: { background: "var(--color-surface)", border: "1px solid var(--border-default)", borderRadius: "var(--radius-card)", margin: "24px 0", padding: 16, ...style }, children: [
1767
+ /* @__PURE__ */ jsx31("div", { style: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 10 }, children: /* @__PURE__ */ jsx31("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wide)", color: "var(--color-accent)" }, children: "RELATED" }) }),
1768
+ /* @__PURE__ */ jsx31("ul", { role: "list", style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 8 }, children: items.map((it, i) => {
1769
+ const Element = it.as ?? (it.href ? "a" : "button");
1770
+ return /* @__PURE__ */ jsx31("li", { children: createElement(
1771
+ Element,
1772
+ {
1773
+ type: Element === "button" ? "button" : void 0,
1774
+ href: it.href,
1775
+ onClick: it.onClick,
1776
+ style: {
1777
+ display: "flex",
1778
+ alignItems: "center",
1779
+ gap: 6,
1780
+ width: "100%",
1781
+ boxSizing: "border-box",
1782
+ border: "1px solid var(--border-medium)",
1783
+ background: "var(--color-background)",
1784
+ borderRadius: "var(--radius-xl)",
1785
+ padding: "9px 12px",
1786
+ fontFamily: "inherit",
1787
+ fontSize: "var(--font-size-base)",
1788
+ color: "var(--color-text-secondary)",
1789
+ textAlign: "left",
1790
+ textDecoration: "none"
1791
+ }
1792
+ },
1793
+ /* @__PURE__ */ jsx31("span", { "aria-hidden": "true", style: { width: 6, height: 6, borderRadius: "50%", background: it.color, flexShrink: 0 } }),
1794
+ /* @__PURE__ */ jsx31("span", { style: { flex: 1 }, children: it.label }),
1795
+ /* @__PURE__ */ jsx31("span", { "aria-hidden": "true", style: { color: "var(--color-ink-300)" }, children: "\u203A" })
1796
+ ) }, i);
1797
+ }) })
1798
+ ] });
1799
+ }
1800
+
1801
+ // src/components/ReferencesCard/ReferencesCard.tsx
1802
+ import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
1803
+ function ReferencesCard({ items, style, ...rest }) {
1804
+ return /* @__PURE__ */ jsxs20("div", { ...rest, style: { background: "var(--color-surface)", border: "1px solid var(--border-default)", borderRadius: "var(--radius-card)", margin: "24px 0", padding: 16, ...style }, children: [
1805
+ /* @__PURE__ */ jsx32("div", { style: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 10 }, children: /* @__PURE__ */ jsx32("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wide)", color: "var(--color-accent)" }, children: "REFERENCES" }) }),
1806
+ /* @__PURE__ */ jsx32("ul", { role: "list", style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 8 }, children: items.map((t, i) => /* @__PURE__ */ jsxs20("li", { style: { display: "flex", alignItems: "baseline", gap: 8, fontSize: "var(--font-size-base)" }, children: [
1807
+ /* @__PURE__ */ jsx32("span", { "aria-hidden": "true", style: { color: "var(--color-ink-300)" }, children: "\u203A" }),
1808
+ /* @__PURE__ */ jsx32("span", { style: { color: "var(--color-text-secondary)" }, children: t })
1809
+ ] }, i)) })
1810
+ ] });
1811
+ }
1812
+
1813
+ // src/components/AnnotationPanel/AnnotationPanel.tsx
1814
+ import { useId as useId4 } from "react";
1815
+ import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1816
+ function AnnotationPanel({ open, value, onChange, placeholder = "Jot your own take here\u2026", ...rest }) {
1817
+ const labelId = useId4();
1818
+ if (!open) return null;
1819
+ return /* @__PURE__ */ jsxs21("div", { style: { marginTop: 10, background: "var(--color-annotation-fill)", borderLeft: "3px solid var(--color-annotation-border)", borderRadius: "0 8px 8px 0", padding: "10px 14px" }, children: [
1820
+ /* @__PURE__ */ jsx33("div", { id: labelId, style: { fontFamily: "var(--font-family-mono)", fontSize: "9.5px", letterSpacing: "0.14em", color: "var(--color-annotation-label)", marginBottom: 5 }, children: "MY NOTE" }),
1821
+ /* @__PURE__ */ jsx33(
1822
+ "textarea",
1823
+ {
1824
+ "aria-labelledby": labelId,
1825
+ value,
1826
+ onChange,
1827
+ rows: 2,
1828
+ placeholder,
1829
+ ...rest,
1830
+ style: { width: "100%", boxSizing: "border-box", border: "none", background: "none", fontFamily: "var(--font-family-hand)", fontSize: "14.5px", color: "var(--color-annotation-text)", resize: "vertical", padding: 0 }
1831
+ }
1832
+ )
1833
+ ] });
1834
+ }
1835
+
1836
+ // src/components/AnnotationToggle/AnnotationToggle.tsx
1837
+ import { jsx as jsx34 } from "react/jsx-runtime";
1838
+ function AnnotationToggle({
1839
+ hasText = false,
1840
+ open = false,
1841
+ onClick,
1842
+ hot = false,
1843
+ onMouseEnter,
1844
+ onMouseLeave,
1845
+ onFocus,
1846
+ onBlur,
1847
+ ...rest
1848
+ }) {
1849
+ const { active, interactionHandlers } = useHover({ onMouseEnter, onMouseLeave, onFocus, onBlur });
1850
+ const visible = hot || open || hasText || active;
1851
+ return /* @__PURE__ */ jsx34(
1852
+ "button",
1853
+ {
1854
+ type: "button",
1855
+ onClick,
1856
+ ...rest,
1857
+ ...interactionHandlers,
1858
+ style: {
1859
+ border: "none",
1860
+ background: "none",
1861
+ fontFamily: "var(--font-family-mono)",
1862
+ fontSize: "var(--font-size-xs)",
1863
+ letterSpacing: "0.06em",
1864
+ color: "var(--color-annotation-label)",
1865
+ padding: "2px 7px",
1866
+ borderRadius: 5,
1867
+ whiteSpace: "nowrap",
1868
+ opacity: visible ? 1 : 0
1869
+ },
1870
+ children: hasText ? "\u270E My note" : "+ My note"
1871
+ }
1872
+ );
1873
+ }
1874
+
1875
+ // src/components/McqOption/McqOption.tsx
1876
+ import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
1877
+ var STATE_TEXT = { correct: "Correct", wrong: "Incorrect" };
1878
+ function McqOption({ label, state = "default", onClick, ...rest }) {
1879
+ let border = "var(--border-medium)";
1880
+ let bg = "var(--color-surface)";
1881
+ let color = "var(--color-text-body)";
1882
+ let mark = "";
1883
+ if (state === "correct") {
1884
+ border = "var(--color-success-border)";
1885
+ bg = "var(--color-success-tint)";
1886
+ color = "var(--color-success)";
1887
+ mark = "\u2713";
1888
+ }
1889
+ if (state === "wrong") {
1890
+ border = "var(--color-danger-border)";
1891
+ bg = "var(--color-danger-tint)";
1892
+ color = "var(--color-danger)";
1893
+ mark = "\u2715";
1894
+ }
1895
+ return /* @__PURE__ */ jsxs22(
1896
+ "button",
1897
+ {
1898
+ type: "button",
1899
+ onClick,
1900
+ disabled: state !== "default",
1901
+ ...rest,
1902
+ style: {
1903
+ display: "flex",
1904
+ alignItems: "flex-start",
1905
+ justifyContent: "space-between",
1906
+ gap: 10,
1907
+ textAlign: "left",
1908
+ border: `1px solid ${border}`,
1909
+ background: bg,
1910
+ color,
1911
+ borderRadius: "var(--radius-lg)",
1912
+ padding: "9px 13px",
1913
+ fontFamily: "inherit",
1914
+ fontSize: "var(--font-size-lg)",
1915
+ width: "100%",
1916
+ boxSizing: "border-box"
1917
+ },
1918
+ children: [
1919
+ /* @__PURE__ */ jsx35("span", { style: { flex: 1, minWidth: 0, textWrap: "pretty" }, children: label }),
1920
+ mark && /* @__PURE__ */ jsxs22("span", { style: { fontWeight: 700, flexShrink: 0 }, children: [
1921
+ /* @__PURE__ */ jsx35("span", { "aria-hidden": "true", children: mark }),
1922
+ /* @__PURE__ */ jsxs22(
1923
+ "span",
1924
+ {
1925
+ style: {
1926
+ position: "absolute",
1927
+ width: 1,
1928
+ height: 1,
1929
+ padding: 0,
1930
+ margin: -1,
1931
+ overflow: "hidden",
1932
+ clip: "rect(0, 0, 0, 0)",
1933
+ whiteSpace: "nowrap",
1934
+ border: 0
1935
+ },
1936
+ children: [
1937
+ " ",
1938
+ "(",
1939
+ STATE_TEXT[state],
1940
+ ")"
1941
+ ]
1942
+ }
1943
+ )
1944
+ ] })
1945
+ ]
1946
+ }
1947
+ );
1948
+ }
1949
+
1950
+ // src/components/FillBlankInput/FillBlankInput.tsx
1951
+ import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
1952
+ function FillBlankInput({ value, onChange, checked = false, correct = false, onCheck, resultLabel, style, ...rest }) {
1953
+ const borderColor = checked ? correct ? "var(--color-success-border)" : "var(--color-danger-border)" : "var(--border-medium)";
1954
+ return /* @__PURE__ */ jsxs23("div", { ...rest, style, children: [
1955
+ /* @__PURE__ */ jsxs23("div", { style: { display: "flex", gap: 8, marginTop: 10 }, children: [
1956
+ /* @__PURE__ */ jsx36(
1957
+ TextInput,
1958
+ {
1959
+ value,
1960
+ onChange,
1961
+ placeholder: "Your answer",
1962
+ "aria-label": "Your answer",
1963
+ "aria-invalid": checked ? !correct : void 0,
1964
+ style: { flex: 1, border: `1px solid ${borderColor}`, background: "var(--color-background)", fontSize: "var(--font-size-lg)" }
1965
+ }
1966
+ ),
1967
+ !checked && /* @__PURE__ */ jsx36(
1968
+ "button",
1969
+ {
1970
+ type: "button",
1971
+ onClick: onCheck,
1972
+ style: { border: "none", background: "var(--color-accent)", color: "#fff", borderRadius: "var(--radius-md)", padding: "0 16px", fontFamily: "inherit", fontSize: "var(--font-size-base)", fontWeight: 600 },
1973
+ children: "Check"
1974
+ }
1975
+ )
1976
+ ] }),
1977
+ checked && /* @__PURE__ */ jsx36("div", { "aria-live": "polite", style: { marginTop: 12, padding: "13px 16px", borderRadius: "var(--radius-lg)", background: "var(--color-surface-sunken)", border: "1px solid var(--border-subtle)" }, children: /* @__PURE__ */ jsx36("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "0.1em", color: correct ? "var(--color-success)" : "var(--color-danger)" }, children: resultLabel }) })
1978
+ ] });
1979
+ }
1980
+
1981
+ // src/components/ScenarioBox/ScenarioBox.tsx
1982
+ import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
1983
+ function ScenarioBox({ text, style, ...rest }) {
1984
+ return /* @__PURE__ */ jsxs24(
1985
+ "div",
1986
+ {
1987
+ ...rest,
1988
+ style: { margin: "2px 0 12px", padding: "12px 14px", borderRadius: "var(--radius-lg)", background: "var(--color-warning-tint)", border: "1px solid var(--color-warning-border)", ...style },
1989
+ children: [
1990
+ /* @__PURE__ */ jsx37("span", { style: { display: "block", fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "0.12em", color: "var(--color-warning)", marginBottom: 5 }, children: "SCENARIO" }),
1991
+ /* @__PURE__ */ jsx37("p", { style: { margin: 0, fontSize: "var(--font-size-base)", color: "var(--color-ink-700)", textWrap: "pretty" }, children: text })
1992
+ ]
1993
+ }
1994
+ );
1995
+ }
1996
+
1997
+ // src/components/Flashcard/Flashcard.tsx
1998
+ import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
1999
+ function Flashcard({ flipped, front, back, boxLabel, onFlip, ...rest }) {
2000
+ return /* @__PURE__ */ jsxs25("div", { children: [
2001
+ /* @__PURE__ */ jsx38("div", { style: { textAlign: "right", marginBottom: 6 }, children: /* @__PURE__ */ jsx38("span", { style: { fontFamily: "var(--font-family-mono)", fontSize: "9.5px", letterSpacing: "0.1em", color: "var(--color-ink-300)" }, children: boxLabel }) }),
2002
+ /* @__PURE__ */ jsx38(
2003
+ "button",
2004
+ {
2005
+ type: "button",
2006
+ onClick: onFlip,
2007
+ "aria-pressed": flipped,
2008
+ ...rest,
2009
+ style: {
2010
+ display: "block",
2011
+ width: "100%",
2012
+ minHeight: 220,
2013
+ background: "var(--color-surface)",
2014
+ border: "1px solid var(--border-medium)",
2015
+ borderRadius: "var(--radius-surface)",
2016
+ padding: "30px 34px",
2017
+ fontFamily: "inherit",
2018
+ textAlign: "center",
2019
+ boxShadow: "var(--shadow-sm)",
2020
+ boxSizing: "border-box"
2021
+ },
2022
+ children: /* @__PURE__ */ jsx38("div", { "aria-live": "polite", children: !flipped ? /* @__PURE__ */ jsxs25("div", { children: [
2023
+ /* @__PURE__ */ jsx38("div", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wider)", color: "var(--color-text-faint)", marginBottom: 18 }, children: "PROMPT" }),
2024
+ /* @__PURE__ */ jsx38("div", { style: { fontSize: "var(--font-size-2xl)", fontWeight: 600, color: "var(--color-text-primary)", marginBottom: 14, textWrap: "pretty" }, children: front }),
2025
+ /* @__PURE__ */ jsx38("div", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-sm)", color: "var(--color-ink-300)", marginTop: 26 }, children: "tap to reveal" })
2026
+ ] }) : /* @__PURE__ */ jsxs25("div", { children: [
2027
+ /* @__PURE__ */ jsx38("div", { style: { fontFamily: "var(--font-family-mono)", fontSize: "var(--font-size-xs)", letterSpacing: "var(--letter-spacing-mono-wider)", color: "var(--color-accent)", marginBottom: 18 }, children: "ANSWER" }),
2028
+ /* @__PURE__ */ jsx38("div", { style: { fontSize: "var(--font-size-lg)", color: "var(--color-text-tertiary)", textWrap: "pretty" }, children: back })
2029
+ ] }) })
2030
+ }
2031
+ )
2032
+ ] });
2033
+ }
2034
+
2035
+ // src/components/RateButtons/RateButtons.tsx
2036
+ import { jsx as jsx39, jsxs as jsxs26 } from "react/jsx-runtime";
2037
+ var buttonStyle = (border, bg, color) => ({
2038
+ border: `1px solid ${border}`,
2039
+ background: bg,
2040
+ color,
2041
+ borderRadius: "var(--radius-lg)",
2042
+ padding: "8px 22px",
2043
+ fontFamily: "inherit",
2044
+ fontSize: "var(--font-size-lg)",
2045
+ fontWeight: 600
2046
+ });
2047
+ function RateButtons({ enabled = false, onAgain, onGood, onEasy, style, ...rest }) {
2048
+ return /* @__PURE__ */ jsxs26("div", { role: "group", "aria-label": "Rate your recall", ...rest, style: { display: "flex", gap: 10, justifyContent: "center", marginTop: 18, opacity: enabled ? 1 : 0.25, ...style }, children: [
2049
+ /* @__PURE__ */ jsx39("button", { type: "button", onClick: onAgain, disabled: !enabled, style: buttonStyle("var(--color-danger-border)", "var(--color-danger-tint)", "var(--color-danger)"), children: "Again" }),
2050
+ /* @__PURE__ */ jsx39("button", { type: "button", onClick: onGood, disabled: !enabled, style: buttonStyle("var(--color-warning-border)", "var(--color-warning-tint)", "var(--color-warning)"), children: "Good" }),
2051
+ /* @__PURE__ */ jsx39("button", { type: "button", onClick: onEasy, disabled: !enabled, style: buttonStyle("var(--color-success-border)", "var(--color-success-tint)", "var(--color-success)"), children: "Easy" })
2052
+ ] });
2053
+ }
2054
+ export {
2055
+ AnnotationPanel,
2056
+ AnnotationToggle,
2057
+ Avatar,
2058
+ Badge,
2059
+ BottomSheet,
2060
+ Button,
2061
+ CardHeader,
2062
+ CardShell,
2063
+ CodeCard,
2064
+ ColorSwatch,
2065
+ ContextMenu,
2066
+ DragHandle,
2067
+ EquationBlock,
2068
+ ExportRow,
2069
+ FillBlankInput,
2070
+ Flashcard,
2071
+ IconButton,
2072
+ ImageCard,
2073
+ ImportExportModal,
2074
+ IntuitionCallout,
2075
+ McqOption,
2076
+ NavTabs,
2077
+ NoteRow,
2078
+ QuizCard,
2079
+ RateButtons,
2080
+ ReferencesCard,
2081
+ RelatedCard,
2082
+ ScenarioBox,
2083
+ Sidebar,
2084
+ SolvedStatusButton,
2085
+ TableCard,
2086
+ TagChip,
2087
+ TextArea,
2088
+ TextBlock,
2089
+ TextInput,
2090
+ TocFab,
2091
+ TocRail,
2092
+ TocSheetList,
2093
+ TopicRow,
2094
+ WalkthroughCard
2095
+ };
2096
+ //# sourceMappingURL=index.js.map