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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Button/Button.tsx","../src/internal/useHover.ts","../src/components/IconButton/IconButton.tsx","../src/components/TagChip/TagChip.tsx","../src/components/Badge/Badge.tsx","../src/components/SolvedStatusButton/SolvedStatusButton.tsx","../src/components/TextInput/TextInput.tsx","../src/components/TextArea/TextArea.tsx","../src/components/Avatar/Avatar.tsx","../src/components/ColorSwatch/ColorSwatch.tsx","../src/components/DragHandle/DragHandle.tsx","../src/components/NavTabs/NavTabs.tsx","../src/components/Sidebar/Sidebar.tsx","../src/components/TopicRow/TopicRow.tsx","../src/components/NoteRow/NoteRow.tsx","../src/components/ContextMenu/ContextMenu.tsx","../src/internal/useDialog.ts","../src/components/BottomSheet/BottomSheet.tsx","../src/components/ImportExportModal/ImportExportModal.tsx","../src/components/TocRail/TocRail.tsx","../src/components/TocFab/TocFab.tsx","../src/components/TocSheetList/TocSheetList.tsx","../src/components/CardShell/CardShell.tsx","../src/components/CardHeader/CardHeader.tsx","../src/components/TextBlock/TextBlock.tsx","../src/components/EquationBlock/EquationBlock.tsx","../src/components/IntuitionCallout/IntuitionCallout.tsx","../src/components/WalkthroughCard/WalkthroughCard.tsx","../src/components/CodeCard/CodeCard.tsx","../src/components/TableCard/TableCard.tsx","../src/components/QuizCard/QuizCard.tsx","../src/components/ImageCard/ImageCard.tsx","../src/components/RelatedCard/RelatedCard.tsx","../src/components/ReferencesCard/ReferencesCard.tsx","../src/components/AnnotationPanel/AnnotationPanel.tsx","../src/components/AnnotationToggle/AnnotationToggle.tsx","../src/components/McqOption/McqOption.tsx","../src/components/FillBlankInput/FillBlankInput.tsx","../src/components/ScenarioBox/ScenarioBox.tsx","../src/components/Flashcard/Flashcard.tsx","../src/components/RateButtons/RateButtons.tsx"],"sourcesContent":["import type { ButtonHTMLAttributes, CSSProperties, MouseEvent, ReactNode } from 'react';\n\nexport interface ButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'title' | 'type'> {\n /** Visual treatment. 'nav' is the segmented top-bar tab style (Learn/Practice/Review). */\n variant?: 'primary' | 'dark' | 'secondary' | 'ghost' | 'nav';\n size?: 'sm' | 'md';\n /** For variant=\"nav\" — whether this tab is the active one. */\n active?: boolean;\n disabled?: boolean;\n /** Optional leading glyph, e.g. an ↥ import icon. Rendered aria-hidden — pass meaningful text via children, not icon. */\n icon?: ReactNode;\n children?: ReactNode;\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n title?: string;\n}\n\nconst SIZE = {\n sm: { padY: '6px', padX: '14px', font: 'var(--font-size-sm)' },\n md: { padY: '9px', padX: '18px', font: 'var(--font-size-base)' },\n} as const;\n\n/**\n * Button — Clio's pill-shaped mono-label action button.\n * Variants: primary (filled accent), dark (filled ink-900, e.g. DOWNLOAD),\n * secondary (outlined), ghost (text-only), nav (segmented top-nav tab).\n */\nexport function Button({\n variant = 'secondary',\n size = 'md',\n active = false,\n disabled = false,\n icon = null,\n children,\n onClick,\n title,\n ...rest\n}: ButtonProps) {\n const s = SIZE[size] ?? SIZE.md;\n const base: CSSProperties = {\n fontFamily: 'var(--font-family-mono)',\n fontSize: s.font,\n letterSpacing: 'var(--letter-spacing-mono-label)',\n padding: `${s.padY} ${s.padX}`,\n borderRadius: 'var(--radius-pill)',\n border: 'none',\n display: 'inline-flex',\n alignItems: 'center',\n gap: '7px',\n cursor: disabled ? 'default' : 'pointer',\n opacity: disabled ? 0.4 : 1,\n transition: 'background var(--duration-fast) ease, color var(--duration-fast) ease',\n };\n let style: CSSProperties = { ...base };\n if (variant === 'primary') {\n style = { ...style, background: 'var(--color-accent)', color: '#FFFFFF' };\n } else if (variant === 'dark') {\n style = { ...style, background: 'var(--color-ink-900)', color: 'var(--color-cream-50)' };\n } else if (variant === 'secondary') {\n style = {\n ...style,\n background: 'var(--color-surface)',\n color: 'var(--color-text-secondary)',\n border: '1px solid var(--border-medium)',\n };\n } else if (variant === 'ghost') {\n style = { ...style, background: 'transparent', color: 'var(--color-text-muted)', padding: '2px 4px' };\n } else if (variant === 'nav') {\n style = {\n ...style,\n background: active ? 'var(--color-ink-900)' : 'transparent',\n color: active ? 'var(--color-cream-50)' : 'var(--color-text-muted)',\n };\n }\n return (\n <button type=\"button\" title={title} disabled={disabled} onClick={onClick} {...rest} style={style}>\n {icon ? (\n <span aria-hidden=\"true\" style={{ fontSize: '13px', lineHeight: 1 }}>\n {icon}\n </span>\n ) : null}\n {children}\n </button>\n );\n}\n","import { useState } from 'react';\nimport type { FocusEventHandler, MouseEventHandler } from 'react';\n\nexport interface UseInteractionStateOptions {\n onMouseEnter?: MouseEventHandler<HTMLElement>;\n onMouseLeave?: MouseEventHandler<HTMLElement>;\n onFocus?: FocusEventHandler<HTMLElement>;\n onBlur?: FocusEventHandler<HTMLElement>;\n}\n\n/**\n * Tracks hover AND keyboard-focus state for components ported from the design\n * system's `style-hover` attribute convention. Using React state (rather than\n * mutating the DOM node directly in onMouseEnter/onMouseLeave) avoids the\n * hover style being silently reverted by React's next render while the mouse\n * is still over the element.\n *\n * Focus is tracked alongside hover — not just as an alias — so keyboard users\n * get the same visual affordance mouse users get on hover; a pointer-only\n * implementation leaves keyboard navigation with no feedback at all.\n *\n * Any caller-supplied onMouseEnter/onMouseLeave/onFocus/onBlur (e.g. analytics\n * hooks) are composed, not clobbered — both the caller's handler and this\n * hook's internal state update run.\n */\nexport function useHover(options: UseInteractionStateOptions = {}) {\n const [hovered, setHovered] = useState(false);\n const [focused, setFocused] = useState(false);\n return {\n hovered,\n focused,\n active: hovered || focused,\n interactionHandlers: {\n onMouseEnter: (e: Parameters<MouseEventHandler<HTMLElement>>[0]) => {\n setHovered(true);\n options.onMouseEnter?.(e);\n },\n onMouseLeave: (e: Parameters<MouseEventHandler<HTMLElement>>[0]) => {\n setHovered(false);\n options.onMouseLeave?.(e);\n },\n onFocus: (e: Parameters<FocusEventHandler<HTMLElement>>[0]) => {\n setFocused(true);\n options.onFocus?.(e);\n },\n onBlur: (e: Parameters<FocusEventHandler<HTMLElement>>[0]) => {\n setFocused(false);\n options.onBlur?.(e);\n },\n },\n } as const;\n}\n","import type { ButtonHTMLAttributes, MouseEvent, ReactNode } from 'react';\nimport { useHover } from '../../internal/useHover';\n\nexport interface IconButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'type' | 'title'> {\n size?: number;\n children?: ReactNode;\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n /** Also used as the accessible name (via aria-label) — required so glyph-only buttons are never announced by their raw unicode content. */\n title: string;\n /** Adds a hairline border + surface fill (used for ⚙ manage-tags, ⇥ import/export). */\n bordered?: boolean;\n hoverColor?: string;\n disabled?: boolean;\n /** Corner radius token. Defaults to the standard control radius; row-level menu triggers use the smaller 'var(--radius-sm)'. */\n radius?: string;\n}\n\n/**\n * IconButton — circular glyph-only button (⋯ menu trigger, ⚙ manage tags,\n * chevron collapse toggle, back arrow).\n */\nexport function IconButton({\n size = 26,\n children,\n onClick,\n title,\n bordered = false,\n hoverColor = 'var(--color-text-secondary)',\n disabled = false,\n radius = 'var(--radius-md)',\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...rest\n}: IconButtonProps) {\n const { active, interactionHandlers } = useHover({ onMouseEnter, onMouseLeave, onFocus, onBlur });\n return (\n <button\n type=\"button\"\n title={title}\n aria-label={title}\n onClick={onClick}\n disabled={disabled}\n {...rest}\n {...interactionHandlers}\n style={{\n width: size,\n height: size,\n border: bordered ? '1px solid var(--border-medium)' : 'none',\n background: active ? 'rgba(17,17,17,0.08)' : bordered ? 'var(--color-surface)' : 'transparent',\n borderRadius: radius,\n color: active ? hoverColor : 'var(--color-text-muted)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '15px',\n lineHeight: 1,\n padding: 0,\n cursor: disabled ? 'default' : 'pointer',\n opacity: disabled ? 0.4 : 1,\n transition: 'background var(--duration-fast) ease, color var(--duration-fast) ease',\n }}\n >\n {children}\n </button>\n );\n}\n","import type { ButtonHTMLAttributes, MouseEvent } from 'react';\n\nexport interface TagChipProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'color' | 'type'> {\n label: string;\n /** Tag or topic color — tints when inactive, fills solid when active. */\n color?: string;\n active?: boolean;\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n removable?: boolean;\n onRemove?: () => void;\n size?: 'sm' | 'md';\n}\n\n/**\n * TagChip — mono capsule tag (#exam-prep). Two states: inactive (tinted)\n * and active/selected (solid fill, white text) used in tag filter bars.\n */\nexport function TagChip({\n label,\n color = 'var(--color-ink-500)',\n active = false,\n onClick,\n removable = false,\n onRemove,\n size = 'md',\n ...rest\n}: TagChipProps) {\n const tint = active ? color : `color-mix(in srgb, ${color} 14%, transparent)`;\n const textColor = active ? '#FFFFFF' : color;\n const font = size === 'sm' ? '9px' : '10.5px';\n return (\n <span\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 5,\n borderRadius: 'var(--radius-pill)',\n padding: removable ? '3px 6px 3px 9px' : '3px 10px',\n fontFamily: 'var(--font-family-mono)',\n fontSize: font,\n background: tint,\n color: textColor,\n whiteSpace: 'nowrap',\n }}\n >\n <button\n type=\"button\"\n onClick={onClick}\n {...rest}\n style={{ border: 'none', background: 'none', padding: 0, font: 'inherit', color: 'inherit', cursor: 'pointer' }}\n >\n #{label}\n </button>\n {removable && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onRemove?.();\n }}\n aria-label={`Remove ${label} tag`}\n style={{\n border: 'none',\n background: 'none',\n padding: '0 1px',\n opacity: 0.7,\n fontSize: '12px',\n lineHeight: 1,\n color: 'inherit',\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n )}\n </span>\n );\n}\n","import type { ReactNode } from 'react';\n\nexport interface BadgeProps {\n variant?: 'topic' | 'mono' | 'eyebrow' | 'count';\n color?: string;\n tint?: string;\n children?: ReactNode;\n}\n\n/**\n * Badge — small labeled pill/rect used across the product:\n * - 'topic' : rounded-rect topic-color label on note headers (e.g. MACHINE LEARNING)\n * - 'mono' : neutral rounded-rect mono badge (e.g. MULTIPLE CHOICE problem type)\n * - 'eyebrow' : borderless mono accent label above a content card (e.g. INTERACTIVE, CODE)\n * - 'count' : small circular counter (review due-count)\n */\nexport function Badge({ variant = 'mono', children, color, tint }: BadgeProps) {\n if (variant === 'topic') {\n return (\n <span\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-sm)',\n letterSpacing: '0.06em',\n fontWeight: 500,\n color: color || 'var(--color-accent)',\n background: tint || 'color-mix(in srgb, var(--color-accent) 10%, transparent)',\n padding: '3px 9px',\n borderRadius: 'var(--radius-xs)',\n whiteSpace: 'nowrap',\n display: 'inline-block',\n }}\n >\n {children}\n </span>\n );\n }\n if (variant === 'eyebrow') {\n return (\n <span\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-xs)',\n letterSpacing: 'var(--letter-spacing-mono-wide)',\n color: color || 'var(--color-accent)',\n whiteSpace: 'nowrap',\n }}\n >\n {children}\n </span>\n );\n }\n if (variant === 'count') {\n return (\n <span\n style={{\n minWidth: 17,\n height: 17,\n padding: '0 4px',\n boxSizing: 'border-box',\n borderRadius: 'var(--radius-full)',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '9.5px',\n background: tint || 'color-mix(in srgb, var(--color-accent) 14%, transparent)',\n color: color || 'var(--color-accent)',\n }}\n >\n {children}\n </span>\n );\n }\n return (\n <span\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-xs)',\n letterSpacing: '0.1em',\n color: 'var(--color-text-muted)',\n background: 'var(--border-hairline)',\n padding: '2px 8px',\n borderRadius: 'var(--radius-xs)',\n }}\n >\n {children}\n </span>\n );\n}\n","import type { ButtonHTMLAttributes, MouseEvent } from 'react';\n\nexport interface SolvedStatusButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'type'> {\n solved?: boolean;\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n}\n\n/**\n * SolvedStatusButton — Practice problem's status toggle. Two states only:\n * unsolved (neutral outline, \"MARK SOLVED\") and solved (green tint, \"✓ SOLVED\").\n * FLAGGED IN README: exact green was inferred from the app's shared success\n * color (#059669) — confirm this is intentional vs. a distinct status hue.\n */\nexport function SolvedStatusButton({ solved = false, onClick, ...rest }: SolvedStatusButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n {...rest}\n style={{\n border: `1px solid ${solved ? 'color-mix(in srgb, var(--color-success) 35%, transparent)' : 'var(--border-medium)'}`,\n background: solved ? 'var(--color-success-tint)' : 'transparent',\n color: solved ? 'var(--color-success)' : 'var(--color-text-muted)',\n borderRadius: 'var(--radius-sm)',\n padding: '3px 10px',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-xs)',\n letterSpacing: '0.06em',\n }}\n >\n {solved ? '✓ SOLVED' : 'MARK SOLVED'}\n </button>\n );\n}\n","import type { ChangeEventHandler, CSSProperties, InputHTMLAttributes } from 'react';\n\nexport interface TextInputProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'style' | 'aria-label' | 'type'> {\n value: string;\n onChange: ChangeEventHandler<HTMLInputElement>;\n placeholder?: string;\n mono?: boolean;\n autoFocus?: boolean;\n style?: CSSProperties;\n /** Accessible name. The source design has no visible label for this field — pass this when the placeholder alone isn't a sufficient accessible name. */\n 'aria-label'?: string;\n /** Restricted to text-like input types — this component's value/onChange contract assumes a string, which checkbox/radio/file don't provide. */\n type?: 'text' | 'search' | 'email' | 'password' | 'tel' | 'url';\n}\n\n/** TextInput — single-line text field (rename inputs, tag search). */\nexport function TextInput({\n value,\n onChange,\n placeholder,\n mono = false,\n autoFocus = false,\n style,\n 'aria-label': ariaLabel,\n type = 'text',\n ...rest\n}: TextInputProps) {\n return (\n <input\n type={type}\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- opt-in via `autoFocus`, only for user-triggered inline rename, never on page load\n autoFocus={autoFocus}\n aria-label={ariaLabel}\n {...rest}\n style={{\n border: '1px solid var(--border-medium)',\n borderRadius: 'var(--radius-md)',\n background: 'var(--color-surface)',\n fontFamily: mono ? 'var(--font-family-mono)' : 'inherit',\n fontSize: mono ? 'var(--font-size-base)' : 'var(--font-size-lg)',\n color: 'var(--color-text-primary)',\n padding: '7px 11px',\n boxSizing: 'border-box',\n ...style,\n }}\n />\n );\n}\n","import type { ChangeEventHandler, TextareaHTMLAttributes } from 'react';\n\nexport interface TextAreaProps\n extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'value' | 'onChange' | 'style' | 'aria-label'> {\n value: string;\n onChange: ChangeEventHandler<HTMLTextAreaElement>;\n placeholder?: string;\n rows?: number;\n mono?: boolean;\n /** Accessible name. The source design has no visible label for this field — pass this when the placeholder alone isn't a sufficient accessible name. */\n 'aria-label'?: string;\n}\n\n/** TextArea — multi-line field (import/export paste box). */\nexport function TextArea({\n value,\n onChange,\n placeholder,\n rows = 6,\n mono = true,\n 'aria-label': ariaLabel,\n ...rest\n}: TextAreaProps) {\n return (\n <textarea\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n rows={rows}\n aria-label={ariaLabel}\n {...rest}\n style={{\n width: '100%',\n boxSizing: 'border-box',\n resize: 'vertical',\n border: '1px solid var(--border-medium)',\n borderRadius: 'var(--radius-xl)',\n background: 'var(--color-surface)',\n padding: '12px 14px',\n fontFamily: mono ? 'var(--font-family-mono)' : 'inherit',\n fontSize: mono ? 'var(--font-size-md)' : 'var(--font-size-lg)',\n lineHeight: 1.55,\n color: 'var(--color-text-body)',\n }}\n />\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface AvatarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n initial?: string;\n size?: number;\n dark?: boolean;\n style?: CSSProperties;\n}\n\n/** Avatar — user initial circle in the topbar (dark mono initial on tint). */\nexport function Avatar({ initial = 'M', size = 28, dark = false, style, ...rest }: AvatarProps) {\n return (\n <div\n {...rest}\n style={{\n width: size,\n height: size,\n borderRadius: '50%',\n background: dark ? 'var(--color-surface-inverse)' : 'var(--color-stone-100)',\n color: dark ? 'var(--color-text-on-inverse)' : 'var(--color-text-secondary)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: size * 0.43,\n fontWeight: 600,\n fontFamily: 'var(--font-family-sans)',\n ...style,\n }}\n >\n {initial}\n </div>\n );\n}\n","import { forwardRef } from 'react';\nimport type { ButtonHTMLAttributes, MouseEvent } from 'react';\n\nexport interface ColorSwatchProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'color' | 'type' | 'title'> {\n color: string;\n active?: boolean;\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n size?: number;\n title?: string;\n}\n\n/** ColorSwatch — small circular color-picker swatch used in recolor rows. */\nexport const ColorSwatch = forwardRef<HTMLButtonElement, ColorSwatchProps>(function ColorSwatch(\n { color, active = false, onClick, size = 17, title = 'Recolor', ...rest },\n ref,\n) {\n return (\n <button\n ref={ref}\n type=\"button\"\n onClick={onClick}\n title={title}\n aria-label={title}\n {...rest}\n style={{\n width: size,\n height: size,\n borderRadius: '50%',\n background: color,\n padding: 0,\n border: `2px solid ${active ? 'var(--color-ink-900)' : 'transparent'}`,\n }}\n />\n );\n});\n","import type { CSSProperties, DragEventHandler, HTMLAttributes } from 'react';\n\nexport interface DragHandleProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'onDragStart' | 'title' | 'style'> {\n onDragStart?: DragEventHandler<HTMLSpanElement>;\n title?: string;\n style?: CSSProperties;\n}\n\n/**\n * DragHandle — the ⋮⋮ grip used to reorder topic/note rows.\n *\n * KNOWN GAP: this uses HTML5 native drag-and-drop (the `draggable` attribute),\n * which has no keyboard equivalent — keyboard-only and screen-reader users\n * cannot trigger it. It's marked aria-hidden so it isn't announced as a\n * false, non-operable affordance in the meantime. Real keyboard reordering\n * (e.g. Space to lift, arrow keys to move, a live region announcing the new\n * position) needs actual reorder state to wire into, which belongs in the\n * list that owns it (Sidebar/TopicRow/NoteRow) — revisit this when those\n * are built, not in this leaf component alone.\n */\nexport function DragHandle({ onDragStart, title = 'Drag to reorder', style, ...rest }: DragHandleProps) {\n return (\n <span\n draggable\n onDragStart={onDragStart}\n title={title}\n aria-hidden=\"true\"\n {...rest}\n style={{\n cursor: 'grab',\n width: 16,\n height: 22,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: 'var(--color-ink-300)',\n fontSize: 19,\n letterSpacing: '-2px',\n lineHeight: 1,\n userSelect: 'none',\n ...style,\n }}\n >\n ⋮⋮\n </span>\n );\n}\n","import { useRef } from 'react';\nimport type { HTMLAttributes, KeyboardEvent } from 'react';\nimport { Badge } from '../Badge';\n\nexport type NavTabId = 'notes' | 'practice' | 'review';\n\nexport interface NavTabsProps extends Omit<HTMLAttributes<HTMLDivElement>, 'role' | 'onChange'> {\n active?: NavTabId;\n onChange?: (id: NavTabId) => void;\n reviewCount?: number;\n}\n\nconst TAB_ORDER: NavTabId[] = ['notes', 'practice', 'review'];\nconst TAB_LABEL: Record<NavTabId, string> = { notes: 'LEARN', practice: 'PRACTICE', review: 'REVIEW' };\n\ninterface TabProps {\n id: NavTabId;\n active: boolean;\n badge?: number;\n onSelect: (id: NavTabId) => void;\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>, id: NavTabId) => void;\n buttonRef: (el: HTMLButtonElement | null) => void;\n}\n\n// Hoisted to module scope: defining this inside NavTabs would give it a new\n// component identity every render, forcing React to unmount/remount every\n// tab (losing focus, breaking the background/color transition) on every\n// re-render of the parent.\nfunction Tab({ id, active, badge, onSelect, onKeyDown, buttonRef }: TabProps) {\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n tabIndex={active ? 0 : -1}\n onClick={() => onSelect(id)}\n onKeyDown={(e) => onKeyDown(e, id)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 7,\n border: 'none',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-sm)',\n letterSpacing: 'var(--letter-spacing-mono-label)',\n padding: '7px 18px',\n borderRadius: 'var(--radius-pill)',\n background: active ? 'var(--color-ink-900)' : 'transparent',\n color: active ? 'var(--color-cream-50)' : 'var(--color-text-muted)',\n transition: 'background var(--duration-fast) ease, color var(--duration-fast) ease',\n }}\n >\n {TAB_LABEL[id]}\n {badge != null && badge > 0 && (\n <Badge variant=\"count\" color=\"inherit\" tint=\"rgba(255,255,255,0.22)\">\n {badge}\n </Badge>\n )}\n </button>\n );\n}\n\n/**\n * NavTabs — top-bar Learn / Practice / Review segmented control, with an\n * optional due-count badge on the Review tab.\n *\n * Implements the ARIA tabs pattern (role=\"tablist\"/\"tab\", aria-selected,\n * roving tabindex + arrow-key navigation) rather than aria-current, since\n * these buttons swap the active view in place — aria-current is intended for\n * navigation links to different pages/locations, not view-switching controls.\n */\nexport function NavTabs({ active = 'notes', onChange, reviewCount = 0, ...rest }: NavTabsProps) {\n const buttonRefs = useRef<Partial<Record<NavTabId, HTMLButtonElement | null>>>({});\n\n const select = (id: NavTabId) => onChange?.(id);\n\n const focusTab = (id: NavTabId) => {\n buttonRefs.current[id]?.focus();\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>, id: NavTabId) => {\n const currentIndex = TAB_ORDER.indexOf(id);\n let nextIndex: number | null = null;\n if (event.key === 'ArrowRight') {\n nextIndex = (currentIndex + 1) % TAB_ORDER.length;\n } else if (event.key === 'ArrowLeft') {\n nextIndex = (currentIndex - 1 + TAB_ORDER.length) % TAB_ORDER.length;\n } else if (event.key === 'Home') {\n nextIndex = 0;\n } else if (event.key === 'End') {\n nextIndex = TAB_ORDER.length - 1;\n }\n if (nextIndex !== null) {\n event.preventDefault();\n const nextId = TAB_ORDER[nextIndex];\n select(nextId);\n focusTab(nextId);\n }\n };\n\n return (\n <div role=\"tablist\" aria-label=\"Sections\" {...rest} style={{ display: 'flex', alignItems: 'center', gap: 6, ...rest.style }}>\n {TAB_ORDER.map((id) => (\n <Tab\n key={id}\n id={id}\n active={active === id}\n badge={id === 'review' ? reviewCount : undefined}\n onSelect={select}\n onKeyDown={handleKeyDown}\n buttonRef={(el) => {\n buttonRefs.current[id] = el;\n }}\n />\n ))}\n </div>\n );\n}\n","import { useId } from 'react';\nimport type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\nimport { IconButton } from '../IconButton';\n\nexport interface SidebarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n collapsed?: boolean;\n onToggle?: () => void;\n /** Eyebrow section label, e.g. \"TOPICS\" or \"CONCEPTS\". */\n label?: string;\n width?: number;\n children?: ReactNode;\n borderSide?: 'right' | 'none';\n style?: CSSProperties;\n}\n\n/**\n * Sidebar — collapsible panel shell used for both the topics column and the\n * notes column on desktop. Collapsed state shrinks to a 26px chevron rail;\n * expanded shows a scrollable content area. Pass a section label + children.\n */\nexport function Sidebar({\n collapsed = false,\n onToggle,\n label,\n width = 222,\n children,\n borderSide = 'right',\n style,\n ...rest\n}: SidebarProps) {\n const contentId = useId();\n return (\n <div\n {...rest}\n style={{\n display: 'flex',\n flexShrink: 0,\n borderRight: borderSide === 'right' ? '1px solid var(--border-hairline)' : 'none',\n ...style,\n }}\n >\n <div style={{ width: 26, flexShrink: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', paddingTop: 16 }}>\n <IconButton\n title={collapsed ? 'Expand' : 'Collapse'}\n onClick={onToggle}\n size={22}\n radius=\"var(--radius-sm)\"\n aria-expanded={!collapsed}\n aria-controls={contentId}\n >\n <span\n aria-hidden=\"true\"\n style={{\n display: 'flex',\n fontSize: 12,\n transform: `rotate(${collapsed ? 180 : 0}deg)`,\n transition: 'transform var(--duration-standard) var(--ease-standard)',\n }}\n >\n ‹\n </span>\n </IconButton>\n </div>\n <div\n id={contentId}\n inert={collapsed}\n style={{\n width: collapsed ? 0 : width,\n opacity: collapsed ? 0 : 1,\n overflow: 'hidden',\n transition: 'width var(--duration-standard) var(--ease-standard), opacity var(--duration-fast) ease',\n }}\n >\n <div style={{ width, minHeight: '100%', boxSizing: 'border-box', padding: '16px 10px 16px 0', display: 'flex', flexDirection: 'column', gap: 3 }}>\n {label && (\n <div\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-xs)',\n letterSpacing: 'var(--letter-spacing-mono-wider)',\n color: 'var(--color-text-muted)',\n padding: '4px 12px 10px',\n }}\n >\n {label}\n </div>\n )}\n {children}\n </div>\n </div>\n </div>\n );\n}\n","import type { CSSProperties, DragEventHandler, HTMLAttributes, MouseEvent } from 'react';\nimport { DragHandle } from '../DragHandle';\nimport { IconButton } from '../IconButton';\n\nexport interface TopicRowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onClick' | 'style' | 'color'> {\n name: string;\n color: string;\n notesLabel: string;\n selected?: boolean;\n onClick?: () => void;\n onMenuClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n draggable?: boolean;\n onDragStart?: DragEventHandler<HTMLSpanElement>;\n /** Mobile topics-screen layout omits the drag handle + indent. */\n dense?: boolean;\n style?: CSSProperties;\n}\n\n/**\n * TopicRow — a single row in the topics sidebar (desktop) / topics screen\n * (mobile). Shows color dot, name, note count, drag handle, and a hover-\n * revealed ⋯ menu. `selected` drives the sunken background + bold text.\n *\n * The selectable area (dot + name + note count) is a real <button>, not a\n * click handler on the outer row: the row also hosts the drag handle and the\n * ⋯ menu button, and an ARIA `role=\"button\"` on the outer element would\n * improperly nest interactive descendants inside another interactive\n * element. A native button sidesteps that entirely.\n */\nexport function TopicRow({\n name,\n color,\n notesLabel,\n selected = false,\n onClick,\n onMenuClick,\n draggable = true,\n onDragStart,\n dense = false,\n style,\n ...rest\n}: TopicRowProps) {\n return (\n <div\n {...rest}\n style={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 8,\n padding: dense ? '12px 8px' : '9px 32px 9px 8px',\n borderRadius: 'var(--radius-row)',\n background: selected ? 'var(--color-surface-sunken)' : 'transparent',\n position: 'relative',\n ...style,\n }}\n >\n {draggable && !dense && <DragHandle onDragStart={onDragStart} />}\n <button\n type=\"button\"\n onClick={onClick}\n style={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 8,\n flex: 1,\n minWidth: 0,\n border: 'none',\n background: 'none',\n padding: 0,\n textAlign: 'left',\n font: 'inherit',\n cursor: 'pointer',\n }}\n >\n <span style={{ width: 7, height: 7, borderRadius: '50%', flexShrink: 0, background: color, marginTop: 6 }} />\n <span style={{ display: 'flex', flexDirection: 'column', gap: 5, flex: 1, minWidth: 0 }}>\n <span\n style={{\n fontSize: 'var(--font-size-base)',\n fontWeight: selected ? 600 : 500,\n color: selected ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n }}\n >\n {name}\n </span>\n <span\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-2xs)',\n color: 'var(--color-text-faint)',\n paddingLeft: dense ? 0 : 15,\n }}\n >\n {notesLabel}\n </span>\n </span>\n </button>\n {onMenuClick && (\n <div style={{ position: 'absolute', top: 8, right: 6 }}>\n <IconButton\n title=\"Topic options\"\n onClick={(e) => {\n e.stopPropagation();\n onMenuClick(e);\n }}\n size={22}\n radius=\"var(--radius-sm)\"\n >\n ⋯\n </IconButton>\n </div>\n )}\n </div>\n );\n}\n","import type { CSSProperties, DragEventHandler, HTMLAttributes, MouseEvent } from 'react';\nimport { DragHandle } from '../DragHandle';\nimport { IconButton } from '../IconButton';\n\nexport interface NoteRowTag {\n label: string;\n color: string;\n}\n\nexport interface NoteRowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onClick' | 'style'> {\n title: string;\n meta: string;\n selected?: boolean;\n showTopic?: boolean;\n topicColor?: string;\n topicName?: string;\n tags?: NoteRowTag[];\n onClick?: () => void;\n onMenuClick?: (event: MouseEvent<HTMLButtonElement>) => void;\n draggable?: boolean;\n onDragStart?: DragEventHandler<HTMLSpanElement>;\n style?: CSSProperties;\n}\n\n/**\n * NoteRow — a single concept/note row in the notes list (desktop sidebar\n * column 2) / concepts screen (mobile). Optional topic dot+label (shown\n * when listing across topics, e.g. tag-filtered results) and tag chips.\n *\n * Like TopicRow, the selectable area is a real <button> rather than a click\n * handler on the outer row, since the row also hosts the drag handle and the\n * ⋯ menu button as separate interactive controls.\n */\nexport function NoteRow({\n title,\n meta,\n selected = false,\n showTopic = false,\n topicColor,\n topicName,\n tags = [],\n onClick,\n onMenuClick,\n draggable = true,\n onDragStart,\n style,\n ...rest\n}: NoteRowProps) {\n return (\n <div\n {...rest}\n style={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 8,\n padding: '9px 32px 9px 8px',\n borderRadius: 'var(--radius-row)',\n background: selected ? 'var(--color-surface-sunken)' : 'transparent',\n position: 'relative',\n ...style,\n }}\n >\n {draggable && <DragHandle onDragStart={onDragStart} style={{ marginTop: 1 }} />}\n <button\n type=\"button\"\n onClick={onClick}\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n flex: 1,\n minWidth: 0,\n border: 'none',\n background: 'none',\n padding: 0,\n textAlign: 'left',\n font: 'inherit',\n cursor: 'pointer',\n }}\n >\n {showTopic && (\n <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <span style={{ width: 6, height: 6, borderRadius: '50%', background: topicColor }} />\n <span\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: '9px',\n letterSpacing: '0.08em',\n color: 'var(--color-text-faint)',\n textTransform: 'uppercase',\n }}\n >\n {topicName}\n </span>\n </span>\n )}\n <span\n style={{\n fontSize: 'var(--font-size-base)',\n lineHeight: 1.4,\n fontWeight: selected ? 600 : 500,\n color: selected ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n }}\n >\n {title}\n </span>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-2xs)', color: 'var(--color-text-faint)' }}>\n {meta}\n </span>\n {tags.length > 0 && !selected && (\n <span style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 1 }}>\n {tags.map((t, i) => (\n <span\n key={`${t.label}-${i}`}\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: '9px',\n color: t.color,\n background: `color-mix(in srgb, ${t.color} 14%, transparent)`,\n padding: '1px 7px',\n borderRadius: 'var(--radius-pill)',\n }}\n >\n #{t.label}\n </span>\n ))}\n </span>\n )}\n </button>\n {onMenuClick && (\n <div style={{ position: 'absolute', top: 7, right: 4 }}>\n <IconButton\n title=\"Concept options\"\n onClick={(e) => {\n e.stopPropagation();\n onMenuClick(e);\n }}\n size={22}\n radius=\"var(--radius-sm)\"\n >\n ⋯\n </IconButton>\n </div>\n )}\n </div>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport type { CSSProperties, HTMLAttributes, KeyboardEvent, ReactNode } from 'react';\nimport { ColorSwatch } from '../ColorSwatch';\n\nexport interface ContextMenuItem {\n label?: string;\n onClick?: () => void;\n danger?: boolean;\n icon?: ReactNode;\n divider?: boolean;\n}\n\nexport interface ContextMenuSwatch {\n color: string;\n active?: boolean;\n pick: () => void;\n}\n\nexport interface ContextMenuProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onClick' | 'style' | 'role' | 'tabIndex'> {\n items: ContextMenuItem[];\n /** Recolor swatch row, e.g. topic/tag color picker. */\n swatches?: ContextMenuSwatch[];\n width?: number;\n style?: CSSProperties;\n /** Called on Escape — the menu itself doesn't track open/closed state; the parent (typically toggled by a row's ⋯ button) owns that. */\n onClose?: () => void;\n /** Accessible label for the menu, since its contents vary by context (e.g. \"Topic options\"). */\n 'aria-label'?: string;\n}\n\n/**\n * ContextMenu — desktop floating dropdown (topic ⋯, note ⋯, manage tags).\n * Pass `items`: array of { label, onClick, danger? } or { divider: true },\n * plus optional `swatches` (color-recolor row) and `header`.\n *\n * Implements the ARIA menu pattern: role=\"menu\"/\"menuitem\", roving tabindex,\n * Arrow/Home/End navigation, and Escape-to-close — none of which the source\n * design has, since it only renders the dropdown's visual chrome.\n */\nexport function ContextMenu({\n items = [],\n swatches,\n width = 176,\n style,\n onClose,\n 'aria-label': ariaLabel,\n ...rest\n}: ContextMenuProps) {\n // Computed with plain (non-mutating) array derivations, not a shared\n // counter variable, so each item/swatch gets a stable, sequential roving-\n // tabindex position across the combined items+swatches control set.\n const nonDividerCount = items.filter((it) => !it.divider).length;\n const itemFocusIndex = items.map((it, i) => (it.divider ? -1 : items.slice(0, i).filter((x) => !x.divider).length));\n const swatchFocusIndex = (swatches ?? []).map((_, i) => nonDividerCount + i);\n const focusableCount = nonDividerCount + (swatches?.length ?? 0);\n\n const controlRefs = useRef<(HTMLButtonElement | null)[]>([]);\n const [activeIndex, setActiveIndex] = useState(0);\n\n useEffect(() => {\n controlRefs.current[0]?.focus();\n }, []);\n\n const focusIndex = (index: number) => {\n const clamped = (index + focusableCount) % focusableCount;\n controlRefs.current[clamped]?.focus();\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n onClose?.();\n return;\n }\n if (focusableCount === 0) return;\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n focusIndex(activeIndex + 1);\n } else if (event.key === 'ArrowUp') {\n event.preventDefault();\n focusIndex(activeIndex - 1);\n } else if (event.key === 'Home') {\n event.preventDefault();\n focusIndex(0);\n } else if (event.key === 'End') {\n event.preventDefault();\n focusIndex(focusableCount - 1);\n }\n };\n\n return (\n <div\n role=\"menu\"\n tabIndex={-1}\n aria-label={ariaLabel}\n // Escape (handled above) is the keyboard-equivalent way to dismiss the\n // menu; this stopPropagation only prevents an ancestor row's own click\n // handler from firing when the pointer interacts with the menu itself.\n onClick={(e) => e.stopPropagation()}\n onKeyDown={handleKeyDown}\n {...rest}\n style={{\n width,\n background: 'var(--color-surface)',\n border: '1px solid var(--border-medium)',\n borderRadius: 'var(--radius-xl)',\n boxShadow: 'var(--shadow-md)',\n padding: 6,\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n ...style,\n }}\n >\n {items.map((it, i) => {\n if (it.divider) {\n return <div key={i} role=\"separator\" aria-orientation=\"horizontal\" style={{ height: 1, background: 'var(--border-subtle)', margin: '2px 4px' }} />;\n }\n const index = itemFocusIndex[i];\n return (\n <button\n key={i}\n role=\"menuitem\"\n ref={(el) => {\n controlRefs.current[index] = el;\n }}\n tabIndex={activeIndex === index ? 0 : -1}\n onFocus={() => setActiveIndex(index)}\n onClick={it.onClick}\n style={{\n textAlign: 'left',\n border: 'none',\n background: 'none',\n borderRadius: 'var(--radius-sm)',\n padding: '7px 9px',\n fontFamily: 'inherit',\n fontSize: 'var(--font-size-base)',\n color: it.danger ? 'var(--color-danger)' : 'var(--color-text-secondary)',\n }}\n >\n {it.icon && (\n <span aria-hidden=\"true\" style={{ marginRight: 7 }}>\n {it.icon}\n </span>\n )}\n {it.label}\n </button>\n );\n })}\n {swatches && (\n <div role=\"group\" aria-label=\"Color\" style={{ display: 'flex', gap: 5, padding: '7px 9px 4px' }}>\n {swatches.map((sw, i) => {\n const index = swatchFocusIndex[i];\n return (\n <ColorSwatch\n key={i}\n ref={(el) => {\n controlRefs.current[index] = el;\n }}\n tabIndex={activeIndex === index ? 0 : -1}\n onFocus={() => setActiveIndex(index)}\n color={sw.color}\n active={sw.active}\n onClick={sw.pick}\n role=\"menuitemradio\"\n aria-checked={!!sw.active}\n />\n );\n })}\n </div>\n )}\n </div>\n );\n}\n","import { useEffect, useRef } from 'react';\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\nexport interface UseDialogOptions {\n open: boolean;\n onClose?: () => void;\n}\n\n/**\n * Shared behavior for true modal overlays (BottomSheet, ImportExportModal):\n * - moves focus into the dialog when it opens (first focusable descendant,\n * or the dialog container itself if it has none)\n * - traps Tab/Shift+Tab focus cycling within the dialog while open\n * - Escape calls onClose\n * - restores focus to whatever was focused before the dialog opened, once\n * it closes\n *\n * None of this is present in the source design (which only conditionally\n * renders the overlay with no keyboard handling at all) — without it, a\n * keyboard user opening either overlay has no way to reach its contents or\n * close it without a mouse.\n */\nexport function useDialog<T extends HTMLElement>({ open, onClose }: UseDialogOptions) {\n const containerRef = useRef<T | null>(null);\n const previouslyFocusedRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!open) return;\n\n previouslyFocusedRef.current = document.activeElement as HTMLElement | null;\n const container = containerRef.current;\n const focusables = container?.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR);\n (focusables?.[0] ?? container)?.focus();\n\n return () => {\n previouslyFocusedRef.current?.focus?.();\n };\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n // Guard with containment (not just \"am I open\"): the Escape listener\n // is registered on `document`, so if two dialogs are ever open at\n // once, both listeners fire on every Escape press. Since the focus\n // trap always keeps focus inside whichever dialog is topmost, only\n // that dialog's container actually contains the active element —\n // this makes Escape close just the topmost one instead of both,\n // without needing a global dialog stack.\n if (containerRef.current?.contains(document.activeElement)) {\n onClose?.();\n }\n return;\n }\n if (event.key !== 'Tab') return;\n\n const container = containerRef.current;\n if (!container) return;\n const focusables = Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));\n if (focusables.length === 0) {\n event.preventDefault();\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [open, onClose]);\n\n return containerRef;\n}\n","import type { CSSProperties, HTMLAttributes, MouseEvent, ReactNode } from 'react';\nimport { useDialog } from '../../internal/useDialog';\n\nexport interface BottomSheetProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'style' | 'onClick' | 'role' | 'aria-modal' | 'tabIndex'> {\n open: boolean;\n onClose?: () => void;\n children?: ReactNode;\n maxHeight?: string | number;\n style?: CSSProperties;\n /** Accessible name for the sheet, since its content varies by context (e.g. \"Topic actions\"). Prefer aria-labelledby if the sheet's content has its own visible heading. */\n 'aria-label'?: string;\n}\n\n/**\n * BottomSheet — mobile modal pattern: dims the screen, slides a rounded-top\n * panel up from the bottom with a drag-handle bar. Used for topic/note\n * action sheets, manage-tags, add-tag, and the TOC outline.\n *\n * A true modal dialog: role=\"dialog\" + aria-modal, focus moves into the\n * sheet on open and is trapped there, Escape closes it, and focus returns to\n * whatever triggered it on close (see internal/useDialog). The source design\n * has none of this — it's presentational chrome only.\n */\nexport function BottomSheet({\n open,\n onClose,\n children,\n maxHeight = '70%',\n style,\n 'aria-label': ariaLabel,\n ...rest\n}: BottomSheetProps) {\n const dialogRef = useDialog<HTMLDivElement>({ open, onClose });\n\n if (!open) return null;\n\n return (\n // Escape (handled by useDialog) is the keyboard-equivalent way to\n // dismiss the sheet; clicking the backdrop is a mouse-only convenience,\n // not the only way to close it.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events\n <div\n onClick={onClose}\n style={{ position: 'absolute', inset: 0, zIndex: 60, background: 'rgba(24,23,20,0.4)', display: 'flex', alignItems: 'flex-end' }}\n >\n {/* The onClick below only stops backdrop-dismiss clicks from reaching the panel's own content; Escape (via useDialog) remains the keyboard path. */}\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */}\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n tabIndex={-1}\n onClick={(e: MouseEvent) => e.stopPropagation()}\n {...rest}\n style={{\n width: '100%',\n boxSizing: 'border-box',\n background: 'var(--color-background)',\n borderRadius: 'var(--radius-surface) var(--radius-surface) 0 0',\n padding: '18px 18px 26px',\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n maxHeight,\n overflowY: 'auto',\n boxShadow: 'var(--shadow-sheet)',\n ...style,\n }}\n >\n <div aria-hidden=\"true\" style={{ width: 36, height: 4, borderRadius: 2, background: 'rgba(17,17,17,0.15)', margin: '0 auto 4px' }} />\n {children}\n </div>\n </div>\n );\n}\n","import { useEffect, useRef } from 'react';\nimport type { HTMLAttributes, KeyboardEvent, ReactNode } from 'react';\nimport { IconButton } from '../IconButton';\nimport { useDialog } from '../../internal/useDialog';\n\nexport type ImportExportTab = 'import' | 'export';\n\nconst TAB_ORDER: ImportExportTab[] = ['import', 'export'];\nconst TAB_LABEL: Record<ImportExportTab, string> = { import: 'IMPORT', export: 'EXPORT' };\n\nexport interface ImportExportModalProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'style' | 'onClick' | 'role' | 'aria-modal' | 'tabIndex'> {\n open: boolean;\n tab?: ImportExportTab;\n onTabChange?: (tab: ImportExportTab) => void;\n onClose?: () => void;\n children?: ReactNode;\n}\n\n/**\n * ImportExportModal — desktop centered modal (mobile uses a full-screen\n * variant, same content structure with a header row instead of an X close).\n *\n * A true modal dialog: role=\"dialog\" + aria-modal, focus trapped inside and\n * moved in on open / restored on close (internal/useDialog), Escape closes,\n * and page scroll is locked while open (unlike BottomSheet, this overlay is\n * `position: fixed; inset: 0` over the whole viewport, so background scroll\n * genuinely needs to be suppressed here). The Import/Export toggle uses the\n * ARIA tabs pattern (role=\"tablist\"/\"tab\", aria-selected, roving tabindex +\n * arrow-key navigation) since it swaps the modal's content in place, same\n * reasoning as NavTabs. None of this exists in the source design.\n */\nexport function ImportExportModal({ open, tab = 'import', onTabChange, onClose, children, ...rest }: ImportExportModalProps) {\n const dialogRef = useDialog<HTMLDivElement>({ open, onClose });\n const tabRefs = useRef<Partial<Record<ImportExportTab, HTMLButtonElement | null>>>({});\n\n // KNOWN LIMITATION: this snapshots/restores document.body.style.overflow\n // directly rather than reference-counting it. If this modal were ever\n // opened while another fixed, viewport-covering overlay had already locked\n // scroll the same way, closing whichever one closes first would restore\n // the OTHER overlay's \"locked\" value instead of the true original,\n // permanently leaving the page scroll-locked. Acceptable for now since the\n // product only ever has one such overlay open at a time (there's a single\n // Import/Export feature); revisit with a shared lock count if that changes.\n useEffect(() => {\n if (!open) return;\n const original = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = original;\n };\n }, [open]);\n\n if (!open) return null;\n\n const selectTab = (id: ImportExportTab) => onTabChange?.(id);\n\n const handleTabKeyDown = (event: KeyboardEvent<HTMLButtonElement>, id: ImportExportTab) => {\n const currentIndex = TAB_ORDER.indexOf(id);\n let nextIndex: number | null = null;\n if (event.key === 'ArrowRight') nextIndex = (currentIndex + 1) % TAB_ORDER.length;\n else if (event.key === 'ArrowLeft') nextIndex = (currentIndex - 1 + TAB_ORDER.length) % TAB_ORDER.length;\n else if (event.key === 'Home') nextIndex = 0;\n else if (event.key === 'End') nextIndex = TAB_ORDER.length - 1;\n if (nextIndex !== null) {\n event.preventDefault();\n const nextId = TAB_ORDER[nextIndex];\n selectTab(nextId);\n tabRefs.current[nextId]?.focus();\n }\n };\n\n return (\n // Escape (handled by useDialog) is the keyboard-equivalent way to\n // dismiss the modal; clicking the backdrop is a mouse-only convenience,\n // not the only way to close it.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events\n <div\n onClick={onClose}\n style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(24,23,20,0.42)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}\n >\n {/* The onClick below only stops backdrop-dismiss clicks from reaching the panel's own content; Escape (via useDialog) remains the keyboard path. */}\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */}\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Import or export notes\"\n tabIndex={-1}\n onClick={(e) => e.stopPropagation()}\n {...rest}\n style={{\n width: 640,\n maxWidth: '100%',\n maxHeight: '86vh',\n background: 'var(--color-background)',\n borderRadius: 'var(--radius-surface)',\n boxShadow: 'var(--shadow-lg)',\n padding: '20px 24px 22px',\n boxSizing: 'border-box',\n display: 'flex',\n flexDirection: 'column',\n gap: 14,\n overflowY: 'auto',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div\n role=\"tablist\"\n aria-label=\"Import or export\"\n style={{ display: 'flex', alignItems: 'center', gap: 4, background: 'var(--color-stone-100)', borderRadius: 'var(--radius-pill)', padding: 3 }}\n >\n {TAB_ORDER.map((id) => (\n <button\n key={id}\n ref={(el) => {\n tabRefs.current[id] = el;\n }}\n type=\"button\"\n role=\"tab\"\n aria-selected={tab === id}\n tabIndex={tab === id ? 0 : -1}\n onClick={() => selectTab(id)}\n onKeyDown={(e) => handleTabKeyDown(e, id)}\n style={{\n border: 'none',\n borderRadius: 17,\n padding: '6px 16px',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-sm)',\n letterSpacing: '0.1em',\n background: tab === id ? 'var(--color-ink-900)' : 'transparent',\n color: tab === id ? 'var(--color-cream-50)' : 'var(--color-text-muted)',\n }}\n >\n {TAB_LABEL[id]}\n </button>\n ))}\n </div>\n <IconButton title=\"Close\" onClick={onClose}>\n ×\n </IconButton>\n </div>\n {children}\n </div>\n </div>\n );\n}\n\nexport interface ExportRowProps {\n title: string;\n sub: string;\n onCopy?: () => void;\n copyLabel?: string;\n onDownload?: () => void;\n}\n\n/** ExportRow — one exportable-item row inside the EXPORT tab (This note, Topic, Full backup). */\nexport function ExportRow({ title, sub, onCopy, copyLabel = 'COPY', onDownload }: ExportRowProps) {\n return (\n <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' }}>\n <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 2 }}>\n <span style={{ fontSize: 'var(--font-size-base)', fontWeight: 600, color: 'var(--color-text-primary)' }}>{title}</span>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-sm)', color: 'var(--color-text-faint)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {sub}\n </span>\n </div>\n <button\n type=\"button\"\n onClick={onCopy}\n 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)' }}\n >\n {copyLabel}\n </button>\n <button\n type=\"button\"\n onClick={onDownload}\n 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)' }}\n >\n DOWNLOAD\n </button>\n </div>\n );\n}\n","import type { CSSProperties, FocusEvent, HTMLAttributes } from 'react';\n\nexport interface TocItem {\n label: string;\n active?: boolean;\n go?: () => void;\n}\n\nexport interface TocRailProps\n extends Omit<\n HTMLAttributes<HTMLElement>,\n 'onMouseEnter' | 'onMouseLeave' | 'onFocus' | 'onBlur' | 'aria-label' | 'style'\n > {\n items: TocItem[];\n /** Hovering (or focusing, via keyboard) the rail expands dots into labels. */\n hovered?: boolean;\n onHoverIn?: () => void;\n onHoverOut?: () => void;\n 'aria-label'?: string;\n style?: CSSProperties;\n}\n\n/**\n * TocRail — desktop floating-dot outline rail (scroll-spy), hover to reveal\n * labels.\n *\n * The source design only expands labels on mouse hover (onMouseEnter/\n * onMouseLeave on the wrapping div) — a keyboard user tabbing through the\n * rail's buttons never sees the labels, only bare dots. Also triggers the\n * same expansion on focus-within (with a relatedTarget check so tabbing\n * between the rail's own buttons doesn't flicker collapsed/expanded), and\n * wraps the items in nav > ol so screen readers announce it as a real list\n * inside a labeled navigation landmark, with aria-current marking the\n * active section (this is exactly what aria-current is for — the current\n * location within a browsing context — unlike a view-switching control).\n * role=\"list\" on the <ol> works around a long-standing Safari/VoiceOver\n * quirk where `list-style: none` drops the implicit list semantics.\n */\nexport function TocRail({\n items,\n hovered,\n onHoverIn,\n onHoverOut,\n 'aria-label': ariaLabel = 'Page outline',\n style,\n ...rest\n}: TocRailProps) {\n return (\n <nav\n aria-label={ariaLabel}\n onMouseEnter={onHoverIn}\n onMouseLeave={onHoverOut}\n onFocus={onHoverIn}\n onBlur={(e: FocusEvent<HTMLElement>) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) onHoverOut?.();\n }}\n {...rest}\n style={{ padding: '6px 4px', ...style }}\n >\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- explicit role=\"list\" restores list semantics Safari/VoiceOver drops once list-style: none is applied */}\n <ol role=\"list\" style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 10 }}>\n {items.map((t, i) => (\n <li key={i}>\n <button\n onClick={t.go}\n aria-current={t.active ? 'true' : undefined}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n border: 'none',\n background: 'none',\n padding: '2px 4px',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-sm)',\n textAlign: 'left',\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: 7,\n height: 7,\n borderRadius: '50%',\n flexShrink: 0,\n background: t.active ? 'var(--color-accent)' : 'rgba(17,17,17,0.22)',\n transform: t.active ? 'scale(1.4)' : 'scale(1)',\n }}\n />\n <span\n style={{\n width: hovered ? 82 : 0,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n color: t.active ? 'var(--color-accent)' : 'var(--color-text-muted)',\n fontWeight: t.active ? 600 : 500,\n transition: 'width var(--duration-standard) var(--ease-standard)',\n }}\n >\n {t.label}\n </span>\n </button>\n </li>\n ))}\n </ol>\n </nav>\n );\n}\n","import type { ButtonHTMLAttributes, CSSProperties } from 'react';\n\nexport interface TocFabProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'type'> {\n onClick?: () => void;\n /** Accessible name — the glyph alone (\"☰\") has no meaning to a screen reader. */\n 'aria-label'?: string;\n style?: CSSProperties;\n}\n\n/** TocFab — mobile floating action button that opens the TOC bottom sheet. */\nexport function TocFab({ onClick, 'aria-label': ariaLabel = 'Open outline', style, ...rest }: TocFabProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n {...rest}\n style={{\n position: 'absolute',\n right: 16,\n bottom: 16,\n width: 46,\n height: 46,\n borderRadius: '50%',\n border: 'none',\n background: 'var(--color-surface-inverse)',\n color: 'var(--color-text-on-inverse)',\n fontSize: 17,\n boxShadow: 'var(--shadow-fab)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 20,\n ...style,\n }}\n >\n <span aria-hidden=\"true\">☰</span>\n </button>\n );\n}\n","import { useId } from 'react';\nimport type { TocItem } from '../TocRail';\n\nexport interface TocSheetListProps {\n items: TocItem[];\n}\n\n/**\n * TocSheetList — the outline list rendered inside a BottomSheet on mobile.\n *\n * Wrapped in nav > ol (screen readers announce it as a real list inside a\n * navigation landmark) with the visible \"OUTLINE\" eyebrow as the landmark's\n * accessible name via aria-labelledby, rather than a redundant separate\n * aria-label repeating the same text. aria-current marks the active section\n * — this is exactly what aria-current is for (current location within a\n * browsing context), matching TocRail. role=\"list\" on the <ol> works around\n * a long-standing Safari/VoiceOver quirk where `list-style: none` drops the\n * implicit list semantics.\n */\nexport function TocSheetList({ items }: TocSheetListProps) {\n const headingId = useId();\n return (\n <nav aria-labelledby={headingId}>\n <div\n id={headingId}\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-xs)',\n letterSpacing: 'var(--letter-spacing-mono-wide)',\n color: 'var(--color-text-muted)',\n marginBottom: 6,\n }}\n >\n OUTLINE\n </div>\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- explicit role=\"list\" restores list semantics Safari/VoiceOver drops once list-style: none is applied */}\n <ol role=\"list\" style={{ listStyle: 'none', margin: 0, padding: 0 }}>\n {items.map((t, i) => (\n <li key={i}>\n <button\n onClick={t.go}\n aria-current={t.active ? 'true' : undefined}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n border: 'none',\n background: 'none',\n padding: '10px 4px',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-base)',\n textAlign: 'left',\n width: '100%',\n boxSizing: 'border-box',\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{ width: 7, height: 7, borderRadius: '50%', flexShrink: 0, background: t.active ? 'var(--color-accent)' : 'rgba(17,17,17,0.22)' }}\n />\n <span style={{ color: t.active ? 'var(--color-accent)' : 'var(--color-text-muted)', fontWeight: t.active ? 600 : 500 }}>{t.label}</span>\n </button>\n </li>\n ))}\n </ol>\n </nav>\n );\n}\n","import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\n\nexport interface CardShellProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n children?: ReactNode;\n dark?: boolean;\n tint?: boolean;\n style?: CSSProperties;\n}\n\n/** CardShell — shared white-surface wrapper most content-card types use. */\nexport function CardShell({ children, dark = false, tint = false, style, ...rest }: CardShellProps) {\n return (\n <div\n {...rest}\n style={{\n background: dark ? 'var(--color-surface-code)' : tint ? 'var(--color-accent-tint)' : 'var(--color-surface)',\n border: dark ? 'none' : `1px solid ${tint ? 'color-mix(in srgb, var(--color-accent) 22%, transparent)' : 'var(--border-default)'}`,\n borderRadius: 'var(--radius-card)',\n margin: '24px 0',\n ...style,\n }}\n >\n {children}\n </div>\n );\n}\n","import type { CSSProperties, ElementType, HTMLAttributes, ReactNode } from 'react';\n\nexport interface CardHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n /** e.g. \"INTERACTIVE\", \"WALKTHROUGH\", \"CODE\", \"COMPARE\", \"CHECKPOINT\" */\n eyebrow: string;\n eyebrowColor?: string;\n title?: string;\n /**\n * Element the title renders as. Defaults to a plain `span` (matches the\n * source design exactly). Content cards sit at an arbitrary point in a\n * note's document outline that only the consuming app knows — this\n * library can't safely guess a heading level (h2 vs h3 vs h4) without\n * risking an inconsistent or skipped-level heading hierarchy. Pass e.g.\n * \"h3\" here when the consumer knows the right level and wants the title\n * reachable via screen-reader heading navigation.\n */\n as?: ElementType;\n subtitle?: string;\n right?: ReactNode;\n dark?: boolean;\n style?: CSSProperties;\n}\n\n/** CardHeader — eyebrow + title row shared by interactive/walkthrough/code/table/quiz/image/related/references cards. */\nexport function CardHeader({\n eyebrow,\n eyebrowColor = 'var(--color-accent)',\n title,\n as: TitleTag = 'span',\n subtitle,\n right,\n dark = false,\n style,\n ...rest\n}: CardHeaderProps) {\n return (\n <div {...rest} style={{ display: 'flex', alignItems: 'baseline', gap: 10, padding: '13px 16px 9px', minWidth: 0, ...style }}>\n <span\n style={{\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-xs)',\n letterSpacing: 'var(--letter-spacing-mono-wide)',\n color: eyebrowColor,\n whiteSpace: 'nowrap',\n flexShrink: 0,\n }}\n >\n {eyebrow}\n </span>\n {title && (\n <TitleTag\n style={{\n margin: 0,\n fontSize: 'var(--font-size-base)',\n fontWeight: 600,\n color: dark ? '#EDEBE3' : 'var(--color-text-primary)',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: 0,\n }}\n >\n {title}\n </TitleTag>\n )}\n {subtitle && (\n <span style={{ fontSize: 'var(--font-size-md)', color: dark ? 'var(--color-ink-500)' : 'var(--color-text-faint)', whiteSpace: 'nowrap', flexShrink: 0 }}>\n {subtitle}\n </span>\n )}\n <span style={{ flex: 1, minWidth: 4 }} />\n {right}\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface TextBlockProps extends Omit<HTMLAttributes<HTMLParagraphElement>, 'style' | 'children'> {\n text: string;\n style?: CSSProperties;\n}\n\n/** TextBlock — plain paragraph content block (no card shell, no eyebrow). */\nexport function TextBlock({ text, style, ...rest }: TextBlockProps) {\n return (\n <p {...rest} style={{ margin: '18px 0', color: 'var(--color-text-body)', textWrap: 'pretty', ...style }}>\n {text}\n </p>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface EquationBlockProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n /** Raw TeX/LaTeX source — real product renders via KaTeX (`<ka-tex>`). */\n tex: string;\n style?: CSSProperties;\n}\n\n/**\n * EquationBlock — display-math content block. Renders bare (no card shell).\n * The real product uses a `<ka-tex>` custom element backed by KaTeX; this\n * design-system stand-in renders the raw TeX in an italic serif style so\n * the layout/spacing is representative without a KaTeX runtime dependency.\n * Consumers should mount the actual `ka-tex` element (see readme.md).\n */\nexport function EquationBlock({ tex, style, ...rest }: EquationBlockProps) {\n return (\n <div {...rest} style={{ margin: '18px 0', textAlign: 'center', padding: '10px 0', ...style }}>\n <span style={{ fontFamily: 'Georgia, serif', fontStyle: 'italic', fontSize: '17px', color: 'var(--color-text-primary)' }}>{tex}</span>\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface IntuitionCalloutProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n text: string;\n /** e.g. \"INTUITION\" or \"THIRD LAW\" for a named-principle variant. */\n label?: string;\n style?: CSSProperties;\n}\n\n/** IntuitionCallout — tinted amber-ochre inline callout box (plain-language intuition, no card shell/border-radius-2xl but its own padded box). */\nexport function IntuitionCallout({ text, label = 'INTUITION', style, ...rest }: IntuitionCalloutProps) {\n return (\n <div\n {...rest}\n style={{\n margin: '18px 0',\n padding: '13px 16px',\n borderRadius: 'var(--radius-lg)',\n background: 'var(--color-warning-tint)',\n border: '1px solid var(--color-warning-border)',\n fontSize: 'var(--font-size-lg)',\n color: 'var(--color-text-secondary)',\n ...style,\n }}\n >\n <span style={{ display: 'block', fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: '0.12em', color: 'var(--color-warning)', marginBottom: 6 }}>\n {label}\n </span>\n {text}\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface WalkthroughStep {\n tex: string;\n note: string;\n}\n\nexport interface WalkthroughCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n title: string;\n steps: WalkthroughStep[];\n currentStep: number;\n onPrev?: () => void;\n onNext?: () => void;\n style?: CSSProperties;\n}\n\n/**\n * WalkthroughCard — numbered step-through derivation. Steps reveal one at\n * a time via Back/Next (earlier steps stay visible, dimmed).\n *\n * Two fixes over the source: the Next button now gets a real `disabled`\n * attribute at the last step (it previously only dimmed via opacity while\n * remaining fully clickable — inconsistent with Back, which already\n * disables for real at the first step, and would let Next keep firing past\n * the end). The revealed-steps list is wrapped in an aria-live region so\n * screen reader users are told a new step appeared after Next/Back, rather\n * than needing to rediscover it themselves.\n */\nexport function WalkthroughCard({ title, steps, currentStep, onPrev, onNext, style, ...rest }: WalkthroughCardProps) {\n const visible = steps.slice(0, currentStep + 1);\n const atStart = currentStep === 0;\n const atEnd = currentStep === steps.length - 1;\n return (\n <div\n {...rest}\n style={{\n background: 'var(--color-surface)',\n border: '1px solid var(--border-default)',\n borderRadius: 'var(--radius-card)',\n margin: '24px 0',\n padding: '16px 20px 14px',\n ...style,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: 'var(--letter-spacing-mono-wide)', color: 'var(--color-accent)' }}>\n WALKTHROUGH\n </span>\n <span style={{ fontSize: 'var(--font-size-base)', fontWeight: 600, color: 'var(--color-text-primary)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }}>\n {title}\n </span>\n </div>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-sm)', color: 'var(--color-text-faint)', whiteSpace: 'nowrap' }}>\n STEP {currentStep + 1} OF {steps.length}\n </span>\n </div>\n <div aria-live=\"polite\">\n {visible.map((s, i) => (\n <div\n key={i}\n style={{\n display: 'grid',\n gridTemplateColumns: '26px 1fr',\n gap: 12,\n padding: '9px 0',\n borderTop: '1px solid var(--border-subtle)',\n opacity: i === currentStep ? 1 : 0.65,\n }}\n >\n <span\n style={{\n width: 24,\n height: 24,\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-sm)',\n marginTop: 4,\n background: i === currentStep ? 'var(--color-accent)' : 'var(--color-stone-100)',\n color: i === currentStep ? '#fff' : 'var(--color-text-faint)',\n }}\n >\n {i + 1}\n </span>\n <div style={{ minWidth: 0 }}>\n <div style={{ fontFamily: 'Georgia, serif', fontStyle: 'italic', textAlign: 'center', fontSize: 15, color: 'var(--color-text-primary)' }}>{s.tex}</div>\n <div style={{ fontSize: 'var(--font-size-base)', color: 'var(--color-text-muted)', textAlign: 'center' }}>{s.note}</div>\n </div>\n </div>\n ))}\n </div>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12 }}>\n <button\n type=\"button\"\n onClick={onPrev}\n disabled={atStart}\n style={{\n border: '1px solid var(--border-strong)',\n background: '#fff',\n borderRadius: 'var(--radius-sm)',\n padding: '5px 14px',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-sm)',\n color: 'var(--color-text-secondary)',\n opacity: atStart ? 0.4 : 1,\n }}\n >\n ‹ Back\n </button>\n <button\n type=\"button\"\n onClick={onNext}\n disabled={atEnd}\n style={{\n border: 'none',\n background: 'var(--color-accent)',\n borderRadius: 'var(--radius-sm)',\n padding: '6px 16px',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-sm)',\n color: '#fff',\n opacity: atEnd ? 0.4 : 1,\n }}\n >\n {atEnd ? 'Done ✓' : 'Next step ›'}\n </button>\n </div>\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface CodeCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n title: string;\n lang: string;\n code: string;\n copyLabel?: string;\n onCopy?: () => void;\n style?: CSSProperties;\n}\n\n/** CodeCard — dark code block with copy button + optional My-note annotation trigger. */\nexport function CodeCard({ title, lang, code, copyLabel = 'Copy', onCopy, style, ...rest }: CodeCardProps) {\n return (\n <div {...rest} style={{ background: 'var(--color-surface-code)', borderRadius: 'var(--radius-card)', margin: '24px 0', overflow: 'hidden', ...style }}>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, padding: '12px 18px', minWidth: 0 }}>\n <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 }}>\n CODE\n </span>\n <span style={{ fontSize: 'var(--font-size-base)', fontWeight: 600, color: '#EDEBE3', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }}>{title}</span>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-sm)', color: 'var(--color-ink-500)', whiteSpace: 'nowrap', flexShrink: 0 }}>{lang}</span>\n <span style={{ flex: 1, minWidth: 4 }} />\n <button\n type=\"button\"\n onClick={onCopy}\n 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 }}\n >\n {copyLabel}\n </button>\n </div>\n <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' }}>\n {code}\n </pre>\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface TableCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n title: string;\n header: string[];\n rows: string[][];\n style?: CSSProperties;\n}\n\n// Visually hidden but still readable by assistive tech — the standard\n// clip/absolute pattern, not `display:none`/`visibility:hidden` (which\n// would remove it from the accessibility tree too).\nconst srOnly: CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/**\n * TableCard — \"COMPARE\" content block; a labeled comparison table.\n *\n * The source markup rendered every cell — header row included — as `<td>`\n * inside a single flat `<tr>` list, with no `<thead>`/`<tbody>` split: a\n * screen reader navigating the table got no column-header announcements at\n * all. This shape is actually a two-way table (header[0] is blank because\n * it's the corner above the row-label column — rows[i][0] labels that row,\n * e.g. \"Memory\", the same way header[1..] label columns, e.g. \"SGD\"). Fixed\n * to `<thead><tr><th scope=\"col\">` for the header row and `<th scope=\"row\">`\n * for each row's first cell — the standard markup for a table with both row\n * and column headers. The empty corner header cell gets a visually-hidden\n * label (real content tables always pass a non-empty `header[0]` in\n * practice, but an empty `<th>` fails an accessibility check regardless of\n * why it's empty, so this covers that case defensively too).\n */\nexport function TableCard({ title, header, rows, style, ...rest }: TableCardProps) {\n return (\n <div\n {...rest}\n style={{ background: 'var(--color-surface)', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-card)', margin: '24px 0', padding: '16px 20px 18px', ...style }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 12 }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: 'var(--letter-spacing-mono-wide)', color: 'var(--color-accent)' }}>COMPARE</span>\n <span style={{ fontSize: 'var(--font-size-base)', fontWeight: 600, color: 'var(--color-text-primary)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }}>{title}</span>\n </div>\n <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 'var(--font-size-base)' }}>\n <thead>\n <tr>\n {header.map((h, i) => (\n <th\n key={i}\n scope=\"col\"\n style={{\n textAlign: 'left',\n padding: '8px 10px',\n fontWeight: i === 0 ? 400 : 600,\n color: i === 0 ? 'var(--color-text-muted)' : 'var(--color-text-primary)',\n fontFamily: i === 0 ? 'var(--font-family-mono)' : 'inherit',\n fontSize: i === 0 ? 'var(--font-size-sm)' : 'inherit',\n borderBottom: '1px solid var(--border-subtle)',\n }}\n >\n {h || <span style={srOnly}>Row label</span>}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((r, ri) => (\n <tr key={ri}>\n {r.map((c, ci) => {\n const cellStyle: CSSProperties = {\n padding: '8px 10px',\n color: ci === 0 ? 'var(--color-text-muted)' : 'var(--color-text-secondary)',\n fontFamily: ci === 0 ? 'var(--font-family-mono)' : 'inherit',\n fontSize: ci === 0 ? 'var(--font-size-sm)' : 'inherit',\n borderBottom: ri === rows.length - 1 ? 'none' : '1px solid var(--border-subtle)',\n };\n return ci === 0 ? (\n <th key={ci} scope=\"row\" style={{ ...cellStyle, textAlign: 'left', fontWeight: 400 }}>\n {c}\n </th>\n ) : (\n <td key={ci} style={cellStyle}>\n {c}\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n","import { useId } from 'react';\nimport type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface QuizCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n question: string;\n answerOpen: boolean;\n answer: string;\n quizLabel: string;\n onToggleQuiz?: () => void;\n addFlashLabel: string;\n onAddFlash?: () => void;\n style?: CSSProperties;\n}\n\n/**\n * QuizCard — \"CHECKPOINT\" self-test block: question, reveal-answer toggle,\n * add-to-flashcards. Uses the accent-tinted background (mixes with the\n * active topic color).\n *\n * The reveal-answer button is a disclosure widget (it shows/hides the\n * answer panel below), so it now carries aria-expanded and aria-controls —\n * the source only changed the button's visible text (quizLabel), giving\n * assistive tech no programmatic signal of the panel's state or its\n * relationship to the toggle, same gap fixed on Sidebar's chevron earlier.\n */\nexport function QuizCard({ question, answerOpen, answer, quizLabel, onToggleQuiz, addFlashLabel, onAddFlash, style, ...rest }: QuizCardProps) {\n const answerId = useId();\n return (\n <div\n {...rest}\n style={{\n background: 'var(--color-accent-tint)',\n border: '1px solid color-mix(in srgb, var(--color-accent) 22%, transparent)',\n borderRadius: 'var(--radius-card)',\n margin: '24px 0',\n padding: '16px 20px 18px',\n ...style,\n }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 10 }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: 'var(--letter-spacing-mono-wide)', color: 'var(--color-accent)' }}>CHECKPOINT</span>\n <span style={{ fontSize: 'var(--font-size-base)', fontWeight: 600, color: 'var(--color-text-primary)', whiteSpace: 'nowrap' }}>Still with it?</span>\n </div>\n <p style={{ margin: '0 0 10px', fontSize: 'var(--font-size-lg)', color: 'var(--color-text-body)' }}>{question}</p>\n <button\n type=\"button\"\n onClick={onToggleQuiz}\n aria-expanded={answerOpen}\n aria-controls={answerId}\n style={{ border: 'none', background: 'none', padding: 0, fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-base)', color: 'var(--color-accent)', whiteSpace: 'nowrap' }}\n >\n {quizLabel}\n </button>\n <button\n type=\"button\"\n onClick={onAddFlash}\n 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' }}\n >\n {addFlashLabel}\n </button>\n {answerOpen && (\n <div\n id={answerId}\n style={{\n marginTop: 10,\n padding: '12px 15px',\n borderRadius: 'var(--radius-lg)',\n background: 'var(--color-surface)',\n border: '1px solid color-mix(in srgb, var(--color-accent) 18%, transparent)',\n fontSize: 'var(--font-size-base)',\n color: 'var(--color-text-secondary)',\n }}\n >\n {answer}\n </div>\n )}\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface ImageCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n /** \"UPLOAD\" (user's own work) or \"FIGURE\" (author-provided diagram). */\n label?: 'UPLOAD' | 'FIGURE';\n title: string;\n /** Unique id — required for the drop to persist (see image-slot.js). */\n slotId: string;\n placeholder?: string;\n height?: number;\n caption?: string;\n style?: CSSProperties;\n}\n\n/**\n * ImageCard — \"UPLOAD\"/\"FIGURE\" content block wrapping the product's\n * `<image-slot>` web component (drag-and-drop image placeholder).\n *\n * `<image-slot>` is an opaque vendored utility, not a component this library\n * owns — its internal accessibility (accessible name, keyboard operability\n * of the drop zone) lives in that script, out of this port's scope. See\n * readme.md for the empty/filled state spec, flagged there as ambiguous.\n */\nexport function ImageCard({ label = 'UPLOAD', title, slotId, placeholder, height = 230, caption, style, ...rest }: ImageCardProps) {\n return (\n <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 }}>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 12 }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: 'var(--letter-spacing-mono-wide)', color: 'var(--color-accent)' }}>{label}</span>\n <span style={{ fontSize: 'var(--font-size-base)', fontWeight: 600, color: 'var(--color-text-primary)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }}>{title}</span>\n </div>\n <image-slot id={slotId} shape=\"rounded\" radius=\"10\" placeholder={placeholder} style={{ width: '100%', height, display: 'block' }} />\n {caption && <div style={{ marginTop: 8, fontSize: 'var(--font-size-md)', color: 'var(--color-text-muted)', textAlign: 'center' }}>{caption}</div>}\n </div>\n );\n}\n","import { createElement } from 'react';\nimport type { CSSProperties, ElementType, HTMLAttributes, MouseEvent } from 'react';\n\nexport interface RelatedCardItem {\n label: string;\n color: string;\n onClick?: (event: MouseEvent) => void;\n /** Renders as a real link (enabling native middle-click/Cmd-click \"open in new tab\") instead of a button. */\n href?: string;\n /** Render as a custom element/component — e.g. a router's Link — instead of the default <a>/<button>. Receives href and onClick. */\n as?: ElementType;\n}\n\nexport interface RelatedCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n items: RelatedCardItem[];\n style?: CSSProperties;\n}\n\n/**\n * RelatedCard — \"RELATED\" content block linking to other concepts.\n *\n * Items are wrapped in a real <ul role=\"list\">/<li> instead of bare\n * <button>s, so screen readers announce \"list of N items\" and let a user\n * navigate it as a list; the trailing \"›\" glyph is aria-hidden since it's\n * purely decorative next to each item's own visible label.\n *\n * Each item renders as a real <a href> when `href` is given (so\n * middle-click/Cmd-click \"open in new tab\" works natively, which a <button>\n * can never support), or as a fully custom element via `as` (e.g. a router's\n * Link component) — falling back to a plain <button> only when neither is\n * given.\n */\nexport function RelatedCard({ items, style, ...rest }: RelatedCardProps) {\n return (\n <div {...rest} style={{ background: 'var(--color-surface)', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-card)', margin: '24px 0', padding: 16, ...style }}>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 10 }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: 'var(--letter-spacing-mono-wide)', color: 'var(--color-accent)' }}>RELATED</span>\n </div>\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- explicit role=\"list\" restores list semantics Safari/VoiceOver drops once list-style: none is applied */}\n <ul role=\"list\" style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 8 }}>\n {items.map((it, i) => {\n const Element: ElementType = it.as ?? (it.href ? 'a' : 'button');\n return (\n <li key={i}>\n {createElement(\n Element,\n {\n type: Element === 'button' ? 'button' : undefined,\n href: it.href,\n onClick: it.onClick,\n style: {\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n width: '100%',\n boxSizing: 'border-box',\n border: '1px solid var(--border-medium)',\n background: 'var(--color-background)',\n borderRadius: 'var(--radius-xl)',\n padding: '9px 12px',\n fontFamily: 'inherit',\n fontSize: 'var(--font-size-base)',\n color: 'var(--color-text-secondary)',\n textAlign: 'left',\n textDecoration: 'none',\n },\n },\n <span aria-hidden=\"true\" style={{ width: 6, height: 6, borderRadius: '50%', background: it.color, flexShrink: 0 }} />,\n <span style={{ flex: 1 }}>{it.label}</span>,\n <span aria-hidden=\"true\" style={{ color: 'var(--color-ink-300)' }}>\n ›\n </span>,\n )}\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface ReferencesCardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n items: string[];\n style?: CSSProperties;\n}\n\n/**\n * ReferencesCard — \"REFERENCES\" content block: a simple citation list.\n *\n * Items are wrapped in a real <ul role=\"list\">/<li> instead of bare <div>s,\n * so screen readers announce \"list of N items\"; the leading \"›\" glyph is\n * aria-hidden since it's a purely decorative bullet marker.\n */\nexport function ReferencesCard({ items, style, ...rest }: ReferencesCardProps) {\n return (\n <div {...rest} style={{ background: 'var(--color-surface)', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-card)', margin: '24px 0', padding: 16, ...style }}>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 10 }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: 'var(--letter-spacing-mono-wide)', color: 'var(--color-accent)' }}>REFERENCES</span>\n </div>\n {/* eslint-disable-next-line jsx-a11y/no-redundant-roles -- explicit role=\"list\" restores list semantics Safari/VoiceOver drops once list-style: none is applied */}\n <ul role=\"list\" style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 8 }}>\n {items.map((t, i) => (\n <li key={i} style={{ display: 'flex', alignItems: 'baseline', gap: 8, fontSize: 'var(--font-size-base)' }}>\n <span aria-hidden=\"true\" style={{ color: 'var(--color-ink-300)' }}>\n ›\n </span>\n <span style={{ color: 'var(--color-text-secondary)' }}>{t}</span>\n </li>\n ))}\n </ul>\n </div>\n );\n}\n","import { useId } from 'react';\nimport type { ChangeEventHandler, TextareaHTMLAttributes } from 'react';\n\nexport interface AnnotationPanelProps\n extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'value' | 'onChange' | 'placeholder' | 'style' | 'aria-labelledby' | 'rows'> {\n open: boolean;\n value: string;\n onChange: ChangeEventHandler<HTMLTextAreaElement>;\n placeholder?: string;\n}\n\n/**\n * AnnotationPanel — the \"MY NOTE\" panel appended to every content-card and\n * practice-problem type. Always amber, regardless of the active topic\n * accent. Font is the hand-script Kalam — the ONLY place it's used.\n *\n * The visible \"MY NOTE\" label had no programmatic association with the\n * textarea below it (just adjacent markup) — linked via aria-labelledby so\n * the textarea has a real accessible name instead of none. Native textarea\n * attributes (disabled, maxLength, onKeyDown, onBlur, etc.) spread onto the\n * textarea itself, since that's the one interactive element here — the\n * outer wrapper div has no independent need for them.\n */\nexport function AnnotationPanel({ open, value, onChange, placeholder = 'Jot your own take here…', ...rest }: AnnotationPanelProps) {\n const labelId = useId();\n if (!open) return null;\n return (\n <div style={{ marginTop: 10, background: 'var(--color-annotation-fill)', borderLeft: '3px solid var(--color-annotation-border)', borderRadius: '0 8px 8px 0', padding: '10px 14px' }}>\n <div id={labelId} style={{ fontFamily: 'var(--font-family-mono)', fontSize: '9.5px', letterSpacing: '0.14em', color: 'var(--color-annotation-label)', marginBottom: 5 }}>\n MY NOTE\n </div>\n <textarea\n aria-labelledby={labelId}\n value={value}\n onChange={onChange}\n rows={2}\n placeholder={placeholder}\n {...rest}\n 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 }}\n />\n </div>\n );\n}\n","import type { ButtonHTMLAttributes, MouseEventHandler } from 'react';\nimport { useHover } from '../../internal/useHover';\n\nexport interface AnnotationToggleProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'type'> {\n hasText?: boolean;\n open?: boolean;\n onClick?: MouseEventHandler<HTMLButtonElement>;\n /** Row is hovered — reveals the otherwise-invisible toggle. */\n hot?: boolean;\n}\n\n/**\n * AnnotationToggle — the small \"+ My note\" trigger button shown in a card's\n * header row.\n *\n * The source only reveals this button when the parent row reports `hot`\n * (mouse hover). A keyboard user tabbing to the button directly (without\n * the row ever being \"hot\") would land on an invisible-but-focusable\n * control with no visual indication it exists until they arrive at it.\n * Reusing the shared useHover hook makes the button also reveal itself on\n * its own hover/focus, so tabbing to it makes it visible the same way\n * hovering the row does.\n */\nexport function AnnotationToggle({\n hasText = false,\n open = false,\n onClick,\n hot = false,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...rest\n}: AnnotationToggleProps) {\n const { active, interactionHandlers } = useHover({ onMouseEnter, onMouseLeave, onFocus, onBlur });\n const visible = hot || open || hasText || active;\n return (\n <button\n type=\"button\"\n onClick={onClick}\n {...rest}\n {...interactionHandlers}\n style={{\n border: 'none',\n background: 'none',\n fontFamily: 'var(--font-family-mono)',\n fontSize: 'var(--font-size-xs)',\n letterSpacing: '0.06em',\n color: 'var(--color-annotation-label)',\n padding: '2px 7px',\n borderRadius: 5,\n whiteSpace: 'nowrap',\n opacity: visible ? 1 : 0,\n }}\n >\n {hasText ? '✎ My note' : '+ My note'}\n </button>\n );\n}\n","import type { ButtonHTMLAttributes } from 'react';\n\nexport interface McqOptionProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'type' | 'disabled'> {\n label: string;\n /** 'default' before pick; 'correct'/'wrong' after pick (shown on both the chosen option and the true correct one). */\n state?: 'default' | 'correct' | 'wrong';\n onClick?: () => void;\n}\n\nconst STATE_TEXT: Record<'correct' | 'wrong', string> = { correct: 'Correct', wrong: 'Incorrect' };\n\n/**\n * McqOption — a single multiple-choice option row. States: default, hover,\n * picked-correct, picked-wrong.\n *\n * Two fixes over the source: the ✓/✕ mark was the ONLY signal of an\n * option's correctness, conveyed purely as a raw glyph character with no\n * semantic backing — some screen readers won't announce it meaningfully at\n * all, and unlike a decorative icon next to a text label, hiding it outright\n * would remove the only indicator entirely. Kept the mark visible but added\n * adjacent visually-hidden text (\"Correct\"/\"Incorrect\") so the state reaches\n * assistive tech in words, not just a symbol. Also: once a state is set\n * (the question has been answered), the option is no longer meant to be\n * re-clickable, but the source left every option fully interactive\n * regardless of state — added a real `disabled` once state !== 'default'.\n */\nexport function McqOption({ label, state = 'default', onClick, ...rest }: McqOptionProps) {\n let border = 'var(--border-medium)';\n let bg = 'var(--color-surface)';\n let color = 'var(--color-text-body)';\n let mark = '';\n if (state === 'correct') {\n border = 'var(--color-success-border)';\n bg = 'var(--color-success-tint)';\n color = 'var(--color-success)';\n mark = '✓';\n }\n if (state === 'wrong') {\n border = 'var(--color-danger-border)';\n bg = 'var(--color-danger-tint)';\n color = 'var(--color-danger)';\n mark = '✕';\n }\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={state !== 'default'}\n {...rest}\n style={{\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'space-between',\n gap: 10,\n textAlign: 'left',\n border: `1px solid ${border}`,\n background: bg,\n color,\n borderRadius: 'var(--radius-lg)',\n padding: '9px 13px',\n fontFamily: 'inherit',\n fontSize: 'var(--font-size-lg)',\n width: '100%',\n boxSizing: 'border-box',\n }}\n >\n <span style={{ flex: 1, minWidth: 0, textWrap: 'pretty' }}>{label}</span>\n {mark && (\n <span style={{ fontWeight: 700, flexShrink: 0 }}>\n <span aria-hidden=\"true\">{mark}</span>\n <span\n style={{\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: 0,\n }}\n >\n {' '}\n ({STATE_TEXT[state as 'correct' | 'wrong']})\n </span>\n </span>\n )}\n </button>\n );\n}\n","import type { ChangeEventHandler, CSSProperties, HTMLAttributes } from 'react';\nimport { TextInput } from '../TextInput';\n\nexport interface FillBlankInputProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n value: string;\n onChange: ChangeEventHandler<HTMLInputElement>;\n checked?: boolean;\n correct?: boolean;\n onCheck?: () => void;\n resultLabel?: string;\n style?: CSSProperties;\n}\n\n/**\n * FillBlankInput — fill-in-the-blank answer row with Check button + result\n * state.\n *\n * Reuses the TextInput component (with a style override for the\n * correct/incorrect border color) instead of a bare hand-rolled <input>. The\n * input had no accessible name at all beyond its placeholder (not reliable\n * across browsers/screen readers) — added one, plus aria-invalid reflecting\n * the check result programmatically, not just via border color. The result\n * panel is wrapped in an aria-live region so screen reader users hear the\n * outcome as soon as Check is pressed, rather than needing to find it.\n */\nexport function FillBlankInput({ value, onChange, checked = false, correct = false, onCheck, resultLabel, style, ...rest }: FillBlankInputProps) {\n const borderColor = checked ? (correct ? 'var(--color-success-border)' : 'var(--color-danger-border)') : 'var(--border-medium)';\n return (\n <div {...rest} style={style}>\n <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>\n <TextInput\n value={value}\n onChange={onChange}\n placeholder=\"Your answer\"\n aria-label=\"Your answer\"\n aria-invalid={checked ? !correct : undefined}\n style={{ flex: 1, border: `1px solid ${borderColor}`, background: 'var(--color-background)', fontSize: 'var(--font-size-lg)' }}\n />\n {!checked && (\n <button\n type=\"button\"\n onClick={onCheck}\n 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 }}\n >\n Check\n </button>\n )}\n </div>\n {checked && (\n <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)' }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: '0.1em', color: correct ? 'var(--color-success)' : 'var(--color-danger)' }}>\n {resultLabel}\n </span>\n </div>\n )}\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface ScenarioBoxProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style'> {\n text: string;\n style?: CSSProperties;\n}\n\n/** ScenarioBox — amber-tinted scenario framing shown above a practice prompt. */\nexport function ScenarioBox({ text, style, ...rest }: ScenarioBoxProps) {\n return (\n <div\n {...rest}\n 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 }}\n >\n <span style={{ display: 'block', fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: '0.12em', color: 'var(--color-warning)', marginBottom: 5 }}>\n SCENARIO\n </span>\n <p style={{ margin: 0, fontSize: 'var(--font-size-base)', color: 'var(--color-ink-700)', textWrap: 'pretty' }}>{text}</p>\n </div>\n );\n}\n","import type { ButtonHTMLAttributes } from 'react';\n\nexport interface FlashcardProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'style' | 'type' | 'aria-pressed'> {\n flipped: boolean;\n front: string;\n back: string;\n /** e.g. \"BOX 3\" or \"NEW\" */\n boxLabel: string;\n onFlip?: () => void;\n}\n\n/**\n * Flashcard — flippable review card (front prompt / back answer) + box\n * label.\n *\n * Added aria-pressed (the flip button is a real toggle — flipped/unflipped\n * — so this is the correct ARIA state for it) and wrapped the revealed\n * content in an aria-live region so screen reader users hear the answer as\n * soon as the card flips, rather than needing to re-navigate into the\n * button to discover it changed.\n */\nexport function Flashcard({ flipped, front, back, boxLabel, onFlip, ...rest }: FlashcardProps) {\n return (\n <div>\n <div style={{ textAlign: 'right', marginBottom: 6 }}>\n <span style={{ fontFamily: 'var(--font-family-mono)', fontSize: '9.5px', letterSpacing: '0.1em', color: 'var(--color-ink-300)' }}>{boxLabel}</span>\n </div>\n <button\n type=\"button\"\n onClick={onFlip}\n aria-pressed={flipped}\n {...rest}\n style={{\n display: 'block',\n width: '100%',\n minHeight: 220,\n background: 'var(--color-surface)',\n border: '1px solid var(--border-medium)',\n borderRadius: 'var(--radius-surface)',\n padding: '30px 34px',\n fontFamily: 'inherit',\n textAlign: 'center',\n boxShadow: 'var(--shadow-sm)',\n boxSizing: 'border-box',\n }}\n >\n <div aria-live=\"polite\">\n {!flipped ? (\n <div>\n <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 }}>\n PROMPT\n </div>\n <div style={{ fontSize: 'var(--font-size-2xl)', fontWeight: 600, color: 'var(--color-text-primary)', marginBottom: 14, textWrap: 'pretty' }}>{front}</div>\n <div style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-sm)', color: 'var(--color-ink-300)', marginTop: 26 }}>tap to reveal</div>\n </div>\n ) : (\n <div>\n <div style={{ fontFamily: 'var(--font-family-mono)', fontSize: 'var(--font-size-xs)', letterSpacing: 'var(--letter-spacing-mono-wider)', color: 'var(--color-accent)', marginBottom: 18 }}>\n ANSWER\n </div>\n <div style={{ fontSize: 'var(--font-size-lg)', color: 'var(--color-text-tertiary)', textWrap: 'pretty' }}>{back}</div>\n </div>\n )}\n </div>\n </button>\n </div>\n );\n}\n","import type { CSSProperties, HTMLAttributes } from 'react';\n\nexport interface RateButtonsProps extends Omit<HTMLAttributes<HTMLDivElement>, 'style' | 'role' | 'aria-label'> {\n /** Only enabled once the card is flipped. */\n enabled?: boolean;\n onAgain?: () => void;\n onGood?: () => void;\n onEasy?: () => void;\n style?: CSSProperties;\n}\n\nconst buttonStyle = (border: string, bg: string, color: string): CSSProperties => ({\n border: `1px solid ${border}`,\n background: bg,\n color,\n borderRadius: 'var(--radius-lg)',\n padding: '8px 22px',\n fontFamily: 'inherit',\n fontSize: 'var(--font-size-lg)',\n fontWeight: 600,\n});\n\n/**\n * RateButtons — Again / Good / Easy spaced-repetition rating row, revealed\n * once flipped.\n *\n * The source \"disabled\" the row purely via `opacity` + `pointer-events:\n * none` on the wrapping div, with no `disabled` attribute on the buttons\n * themselves. `pointer-events: none` blocks mouse clicks but NOT keyboard\n * activation — a keyboard user could Tab to these buttons and press\n * Enter/Space to rate a card before flipping it, bypassing the entire\n * intended flow. Added a real `disabled` to each button so it's actually\n * inert, not just unclickable by mouse.\n */\nexport function RateButtons({ enabled = false, onAgain, onGood, onEasy, style, ...rest }: RateButtonsProps) {\n return (\n <div role=\"group\" aria-label=\"Rate your recall\" {...rest} style={{ display: 'flex', gap: 10, justifyContent: 'center', marginTop: 18, opacity: enabled ? 1 : 0.25, ...style }}>\n <button type=\"button\" onClick={onAgain} disabled={!enabled} style={buttonStyle('var(--color-danger-border)', 'var(--color-danger-tint)', 'var(--color-danger)')}>\n Again\n </button>\n <button type=\"button\" onClick={onGood} disabled={!enabled} style={buttonStyle('var(--color-warning-border)', 'var(--color-warning-tint)', 'var(--color-warning)')}>\n Good\n </button>\n <button type=\"button\" onClick={onEasy} disabled={!enabled} style={buttonStyle('var(--color-success-border)', 'var(--color-success-tint)', 'var(--color-success)')}>\n Easy\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsx","jsxs","jsx","jsx","jsx","jsx","jsx","jsx","ColorSwatch","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useRef","jsx","jsxs","useEffect","useRef","jsx","jsxs","TAB_ORDER","TAB_LABEL","useRef","useEffect","jsx","jsxs","jsx","useId","jsx","jsxs","jsx","jsx","jsxs","jsx","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useId","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","useId","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "clio-design-system",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Component library for the Clio design system",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/manojravindran90/clio-design-system.git"
10
+ },
11
+ "main": "./dist/index.cjs",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js",
18
+ "require": "./dist/index.cjs"
19
+ },
20
+ "./styles.css": "./styles/styles.css",
21
+ "./package.json": "./package.json"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "styles"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "dev": "tsup --watch",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "lint": "eslint .",
33
+ "storybook": "storybook dev -p 6006",
34
+ "build-storybook": "storybook build",
35
+ "changeset": "changeset",
36
+ "version": "changeset version",
37
+ "release": "npm run build && changeset publish"
38
+ },
39
+ "peerDependencies": {
40
+ "react": ">=18",
41
+ "react-dom": ">=18"
42
+ },
43
+ "devDependencies": {
44
+ "@changesets/cli": "^2.31.0",
45
+ "@chromatic-com/storybook": "^5.2.1",
46
+ "@eslint/js": "^9.39.4",
47
+ "@storybook/addon-a11y": "^10.4.6",
48
+ "@storybook/addon-docs": "^10.4.6",
49
+ "@storybook/addon-mcp": "^0.6.0",
50
+ "@storybook/addon-vitest": "^10.4.6",
51
+ "@storybook/react-vite": "^10.4.6",
52
+ "@testing-library/jest-dom": "^6.9.1",
53
+ "@testing-library/react": "^16.3.2",
54
+ "@testing-library/user-event": "^14.6.1",
55
+ "@types/react": "^18.3.31",
56
+ "@types/react-dom": "^18.3.7",
57
+ "@vitest/browser-playwright": "^4.1.9",
58
+ "@vitest/coverage-v8": "^4.1.9",
59
+ "axe-core": "^4.12.1",
60
+ "eslint": "^9.39.4",
61
+ "eslint-plugin-jsx-a11y": "^6.10.2",
62
+ "eslint-plugin-react-hooks": "^7.1.1",
63
+ "eslint-plugin-storybook": "^10.4.6",
64
+ "jsdom": "^29.1.1",
65
+ "playwright": "^1.61.1",
66
+ "react": "^19.2.7",
67
+ "react-dom": "^19.2.7",
68
+ "storybook": "^10.4.6",
69
+ "tsup": "^8.5.1",
70
+ "typescript": "^5.9.3",
71
+ "typescript-eslint": "^8.62.1",
72
+ "vitest": "^4.1.9",
73
+ "vitest-axe": "^0.1.0"
74
+ },
75
+ "allowScripts": {
76
+ "esbuild@0.27.7": true,
77
+ "fsevents@2.3.3": true,
78
+ "fsevents@2.3.2": true
79
+ }
80
+ }
@@ -0,0 +1,19 @@
1
+ @import "./tokens/fonts.css";
2
+ @import "./tokens/colors.css";
3
+ @import "./tokens/typography.css";
4
+ @import "./tokens/spacing.css";
5
+ @import "./tokens/radius.css";
6
+ @import "./tokens/shadows.css";
7
+ @import "./tokens/semantic.css";
8
+ @import "./tokens/topic-accent.css";
9
+ @import "./tokens/brand-theme.css";
10
+ @import "./tokens/dark-mode.css";
11
+
12
+ /* Base resets — the only non-token rules in the global stylesheet */
13
+ html, body { margin: 0; padding: 0; background: var(--color-background); }
14
+ body { font-family: var(--font-family-sans); color: var(--color-text-body); font-size: var(--font-size-xl); line-height: var(--line-height-normal); }
15
+ button { cursor: pointer; font-family: inherit; }
16
+ ::-webkit-scrollbar { width: 8px; height: 8px; }
17
+ ::-webkit-scrollbar-track { background: transparent; }
18
+ ::-webkit-scrollbar-thumb { background: rgba(17, 17, 17, 0.12); border-radius: 4px; }
19
+ textarea:focus, input:focus { outline: none; }
@@ -0,0 +1,12 @@
1
+ /* ============================================================
2
+ BRAND THEME PATTERN
3
+ Separate from the per-topic accent above: --color-accent's BASE
4
+ value (used in Review, and anywhere no topic is active) is itself
5
+ swappable. Clio ships 4 built-in brand themes — set one class on
6
+ <html> or <body> to reskin every consuming site/product at once
7
+ without touching component code.
8
+ ============================================================ */
9
+ :root, .theme-indigo { --color-accent: var(--color-indigo-600); }
10
+ .theme-teal { --color-accent: var(--color-teal-700); }
11
+ .theme-orange { --color-accent: var(--color-orange-600); }
12
+ .theme-violet { --color-accent: var(--color-violet-700); }
@@ -0,0 +1,87 @@
1
+ /* ============================================================
2
+ COLOR TOKENS — Layer 1: Primitives
3
+ Raw named values only. No semantic meaning. Components never
4
+ reference these directly — they consume Layer 2 (semantic.css).
5
+ ============================================================ */
6
+ :root {
7
+ /* Neutrals — warm "paper" tint, not true gray */
8
+ --color-white: #FFFFFF;
9
+ --color-cream-50: #FAF9F6; /* desktop app background */
10
+ --color-cream-100: #F1EFE8; /* selected row background */
11
+ --color-stone-100: #EFEDE6; /* selected topic / tag-bg / mobile chip track */
12
+ --color-stone-200: #EAE6DC; /* mobile canvas backdrop behind phone frame */
13
+ --color-ink-950: #111111; /* raw black used only inside rgba() hairlines/shadows */
14
+ --color-ink-900: #131313; /* headings, primary buttons, phone status text */
15
+ --color-ink-850: #24231F; /* code block surface */
16
+ --color-ink-800: #2B2A27; /* body text, app base color */
17
+ --color-ink-700: #45443F; /* secondary text, icon-button color */
18
+ --color-ink-600: #5A5954; /* tertiary text */
19
+ --color-ink-500: #8A8781; /* muted text — meta, placeholders, mono labels */
20
+ --color-ink-400: #A09D96; /* faint text — timestamps, disabled-ish mono */
21
+ --color-ink-300: #C4C1B9; /* hairline icon color, chevrons, disabled marks */
22
+ --color-ink-200: #D8D5CB; /* code text on dark surface */
23
+
24
+ /* Brand / accent hues — the 8-color topic palette pulls from these */
25
+ --color-orange-600: #B4530A; /* brand default accent (indigo is actual default; orange is a theme option) */
26
+ --color-orange-700: #C0650F; /* topic: Material Science */
27
+ --color-red-600: #C13A3A; /* topic: Thermodynamics */
28
+ --color-red-700: #DC2626; /* error / destructive (distinct from topic red) */
29
+ --color-amber-700: #A07708; /* topic: (Ochre) + intuition-callout label */
30
+ --color-amber-500: #D9A404; /* "My note" annotation accent border */
31
+ --color-amber-400: #E0B84D; /* code-block annotation accent border */
32
+ --color-amber-tint: #FFFBEB; /* "My note" annotation panel fill */
33
+ --color-blue-600: #1F7AAE; /* topic: Steel Blue */
34
+ --color-green-700: #2C7A4B; /* topic: Forest Green */
35
+ --color-green-600: #059669; /* success / correct-answer state */
36
+ --color-violet-600: #7A4BD6; /* topic: Machine Learning */
37
+ --color-violet-700: #7C3AED; /* theme option (brand default alt) */
38
+ --color-indigo-600: #4F46E5; /* brand default accent (the actual code fallback) */
39
+ --color-teal-600: #0F8A78; /* topic: Teal */
40
+ --color-teal-700: #0F766E; /* theme option (brand default alt) */
41
+ --color-pink-600: #B4448E; /* topic: Magenta */
42
+ --color-code-green: #8FD16A; /* syntax-style accent label on dark code surface */
43
+
44
+ /* Reframe/upload accessory accent (image-slot component, not brand-tunable) */
45
+ --color-rust-500: #C96442;
46
+
47
+ /* ── Dark-mode primitives ──────────────────────────────────
48
+ A second, independent scale — not a filter/invert of the light
49
+ scale. Still warm (never blue-black or pure gray). */
50
+ --color-dark-bg: #1C1B18; /* app canvas */
51
+ --color-dark-surface: #242320; /* cards, rows-list panel, modal, sheet */
52
+ --color-dark-surface-sunken: #2C2A26; /* selected row / sunken wash */
53
+ --color-dark-surface-code: #131110; /* code block — deliberately darker than --color-dark-surface so it still reads as inset */
54
+ --color-dark-text-900: #F3F1EA; /* headings, primary buttons' inverse text target */
55
+ --color-dark-text-800: #D9D6CC; /* body text */
56
+ --color-dark-text-700: #B8B4A8; /* secondary (menu items, icon glyphs) */
57
+ --color-dark-text-600: #96938A; /* tertiary */
58
+ --color-dark-text-500: #7D7A72; /* muted — tuned to clear 4.5:1 on --color-dark-bg */
59
+ --color-dark-text-400: #635F57; /* faint / disabled marks */
60
+
61
+ /* Topic hues, lightened for legibility as text/badges on dark surfaces
62
+ (same 8, same order — never a 9th hue) */
63
+ --color-topic-red-dark: #E27272;
64
+ --color-topic-orange-dark: #E08A45;
65
+ --color-topic-ochre-dark: #D9A93F;
66
+ --color-topic-blue-dark: #59B0E0;
67
+ --color-topic-green-dark: #56B683;
68
+ --color-topic-violet-dark: #A186EA;
69
+ --color-topic-teal-dark: #3FBFA8;
70
+ --color-topic-magenta-dark: #D976B4;
71
+
72
+ /* Brand-theme accents, lightened to match */
73
+ --color-indigo-600-dark: #8583F0;
74
+ --color-teal-700-dark: #2FB5A5;
75
+ --color-orange-600-dark: #E0954F;
76
+ --color-violet-700-dark: #A688F5;
77
+
78
+ /* Feedback, lightened */
79
+ --color-success-dark: #3ECF95;
80
+ --color-danger-dark: #F17971;
81
+ --color-warning-dark: #D9A93F;
82
+
83
+ /* Annotation ("My note"), tuned for dark surfaces */
84
+ --color-annotation-text-dark: #E8C874;
85
+ --color-annotation-label-dark: #E0B84D;
86
+ --color-annotation-border-dark: #D9A404;
87
+ }