@tokyo3rdhq/magi-design-system 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/classnames.ts","../src/layout/Container.tsx","../src/layout/Section.tsx","../src/layout/Stack.tsx","../src/components/Button/Button.tsx","../src/components/Card/Card.tsx","../src/components/Badge/Badge.tsx","../src/components/Checkbox/Checkbox.tsx","../src/components/Input/Input.tsx","../src/components/FormField/FormField.tsx","../src/components/Segmented/Segmented.tsx","../src/components/Banner/Banner.tsx","../src/components/EmptyState/EmptyState.tsx","../src/theme.tsx"],"sourcesContent":["/** Join truthy class strings with a space. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(' ');\n}","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type ContainerSize = 'sm' | 'md' | 'lg' | 'xl' | 'wide' | 'full';\n\nexport interface ContainerProps extends HTMLAttributes<HTMLElement> {\n /** Maximum width at desktop. Default: `xl` (1200px). */\n size?: ContainerSize;\n /** Override the rendered tag. Default: `div`. */\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Container — centers content and constrains max-width.\n *\n * @example\n * <Container size=\"lg\">...</Container>\n */\nexport function Container({\n size = 'xl',\n as,\n className,\n children,\n ...rest\n}: ContainerProps) {\n const Component = (as ?? 'div') as ElementType;\n const cls = cx('magi-container', `magi-container--${size}`, className);\n return (\n <Component className={cls} {...rest}>\n {children}\n </Component>\n );\n}\n","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type SectionSpacing = 'sm' | 'md' | 'lg' | 'xl';\nexport type SectionSurface = 'default' | 'raised' | 'elevated';\n\nexport interface SectionProps extends HTMLAttributes<HTMLElement> {\n /** Vertical padding scale. Default: `lg`. */\n spacing?: SectionSpacing;\n /** Background surface. Default: `default` (transparent). */\n surface?: SectionSurface;\n /** Drop the inner Container padding. Useful for full-bleed content. */\n fullWidth?: boolean;\n /** Override the rendered tag. Default: `section`. */\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Section — page-level vertical rhythm primitive.\n *\n * @example\n * <Section spacing=\"xl\" surface=\"default\">...</Section>\n */\nexport function Section({\n spacing = 'lg',\n surface = 'default',\n fullWidth = false,\n as,\n className,\n children,\n ...rest\n}: SectionProps) {\n const Component = (as ?? 'section') as ElementType;\n const cls = cx(\n 'magi-section',\n `magi-section--${spacing}`,\n `magi-section--${surface}`,\n fullWidth && 'magi-section--fullWidth',\n className,\n );\n return (\n <Component className={cls} {...rest}>\n {children}\n </Component>\n );\n}\n","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type StackGap =\n | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '8' | '10' | '12' | '16';\nexport type StackAlign = 'start' | 'center' | 'end' | 'stretch';\n\nexport interface StackProps extends HTMLAttributes<HTMLElement> {\n /** Layout direction. Default: vertical (column). */\n direction?: 'row' | 'column';\n /** Gap token. Default: `4` (16px). */\n gap?: StackGap;\n /** Cross-axis alignment. Default: `stretch`. */\n align?: StackAlign;\n /** Allow wrapping when `direction=\"row\"`. Default: true. */\n wrap?: boolean;\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Stack — vertical or horizontal flex primitive with semantic gap tokens.\n *\n * @example\n * <Stack gap=\"6\" align=\"center\">...</Stack>\n * <Stack direction=\"row\" gap=\"3\">...</Stack>\n */\nexport function Stack({\n direction = 'column',\n gap = '4',\n align = 'stretch',\n wrap = true,\n as,\n className,\n style,\n children,\n ...rest\n}: StackProps) {\n const Component = (as ?? 'div') as ElementType;\n const wrapStyle =\n direction === 'row' && !wrap ? { flexWrap: 'nowrap' as const } : undefined;\n const cls = cx(\n 'magi-stack',\n direction === 'row' && 'magi-stack--row',\n `magi-stack--gap-${gap}`,\n `magi-stack--align-${align}`,\n className,\n );\n\n return (\n <Component className={cls} style={{ ...wrapStyle, ...style }} {...rest}>\n {children}\n </Component>\n );\n}\n","import { forwardRef, type ButtonHTMLAttributes } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style. Default: `primary`. */\n variant?: ButtonVariant;\n /** Height + padding tier. Default: `md`. */\n size?: ButtonSize;\n /** Show a spinner and disable interaction. */\n loading?: boolean;\n}\n\n/**\n * Button — the canonical MAGI action element.\n *\n * Pill-shaped, four variants (primary/secondary/ghost/danger), three sizes.\n * Use `primary` for the dominant action on a page; `secondary` for supporting\n * actions; `ghost` for inline/tertiary; `danger` for destructive intent.\n *\n * @example\n * <Button variant=\"primary\" onClick={...}>Save</Button>\n * <Button variant=\"secondary\">Cancel</Button>\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n function Button(\n {\n variant = 'primary',\n size = 'md',\n loading = false,\n disabled,\n className,\n children,\n type,\n ...rest\n },\n ref,\n ) {\n const cls = cx(\n 'magi-button',\n `magi-button--${variant}`,\n `magi-button--${size}`,\n loading && 'magi-button--loading',\n className,\n );\n\n return (\n <button\n ref={ref}\n className={cls}\n type={type ?? 'button'}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...rest}\n >\n {children}\n </button>\n );\n },\n);\n","import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type CardVariant = 'default' | 'elevated' | 'interactive';\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Visual emphasis. Default: `default`. `interactive` adds hover state. */\n variant?: CardVariant;\n /** Inner padding. Default: `md`. */\n padding?: CardPadding;\n children?: ReactNode;\n}\n\n/**\n * Card — minimal dark surface with subtle border. Three variants:\n * default (flat), elevated (more contrast), interactive (hover state).\n *\n * @example\n * <Card variant=\"elevated\">...</Card>\n * <Card variant=\"interactive\" onClick={...}>...</Card>\n */\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n { variant = 'default', padding = 'md', className, children, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-card',\n `magi-card--${variant}`,\n `magi-card--padding-${padding}`,\n className,\n );\n return (\n <div ref={ref} className={cls} {...rest}>\n {children}\n </div>\n );\n});\n","import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type BadgeVariant = 'neutral' | 'accent' | 'success' | 'warning' | 'error';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Color/meaning. Default: `neutral`. */\n variant?: BadgeVariant;\n /** Show a leading colored dot. */\n dot?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Badge — compact status / metadata label.\n *\n * @example\n * <Badge variant=\"accent\">128K context</Badge>\n * <Badge variant=\"success\" dot>Online</Badge>\n */\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(function Badge(\n { variant = 'neutral', dot = false, className, children, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-badge',\n `magi-badge--${variant}`,\n className,\n );\n return (\n <span ref={ref} className={cls} {...rest}>\n {dot ? <span className=\"magi-badge__dot\" aria-hidden=\"true\" /> : null}\n {children}\n </span>\n );\n});\n","import {\n forwardRef,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type CheckboxLabelPosition = 'right' | 'left';\n\n/**\n * Omit `type` from native input attrs — this component is always\n * `type=\"checkbox\"` under the hood. Letting `type` pass through would\n * let consumers render e.g. `type=\"radio\"` with checkbox styles.\n */\nexport interface CheckboxProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {\n /** Optional label rendered next to the checkbox. */\n children?: ReactNode;\n /** Position of the label relative to the checkbox. Default: 'right'. */\n labelPosition?: CheckboxLabelPosition;\n}\n\n/**\n * Checkbox — restyled native checkbox for the MAGI dark theme.\n *\n * Uses a native `<input type=\"checkbox\">` under the hood for full form\n * integration and screen-reader compatibility. The CSS only restyles\n * the visible state.\n *\n * @example\n * // Uncontrolled:\n * <Checkbox aria-label=\"Accept terms\" defaultChecked />\n *\n * // Controlled with label:\n * <Checkbox\n * checked={providers.includes('nvidia')}\n * onChange={(e) => toggle('nvidia', e.target.checked)}\n * >\n * NVIDIA\n * </Checkbox>\n */\nexport const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(\n function Checkbox(\n {\n children,\n labelPosition = 'right',\n className,\n disabled,\n ...rest\n },\n ref,\n ) {\n const input = (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cx('magi-checkbox', className)}\n disabled={disabled}\n {...rest}\n />\n );\n\n if (children === undefined || children === null) {\n return input;\n }\n\n return (\n <label\n className={cx(\n 'magi-checkbox-label',\n disabled && 'magi-checkbox-label--disabled',\n )}\n >\n {labelPosition === 'left' ? (\n <>\n <span>{children}</span>\n {input}\n </>\n ) : (\n <>\n {input}\n <span>{children}</span>\n </>\n )}\n </label>\n );\n },\n);","import { forwardRef, type InputHTMLAttributes } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type InputSize = 'sm' | 'md' | 'lg';\n\nexport interface InputProps extends InputHTMLAttributes<HTMLInputElement> {\n /** Visual size. Default: `md`. */\n inputSize?: InputSize;\n /** Error state — adds error border + aria-invalid. */\n invalid?: boolean;\n}\n\n/**\n * Input — `<input>` styled for the MAGI dark theme.\n *\n * Wraps the native element directly. No custom state management — value /\n * onChange / defaultValue / ref all pass through.\n *\n * @example\n * <Input placeholder=\"e.g. Coding assistant\" />\n * <Input type=\"password\" />\n * <Input invalid defaultValue=\"bad value\" />\n */\nexport const Input = forwardRef<HTMLInputElement, InputProps>(function Input(\n { inputSize = 'md', invalid = false, className, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-input',\n `magi-input--${inputSize}`,\n invalid && 'magi-input--invalid',\n className,\n );\n\n return (\n <input\n ref={ref}\n className={cls}\n aria-invalid={invalid || undefined}\n {...rest}\n />\n );\n});","import { useId, type ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport interface FormFieldProps {\n /** Visible label above the control. Required. */\n label: string;\n /** Optional helper text below the control. */\n helper?: string;\n /** Error message — overrides helper styling + sets aria-describedby. */\n error?: string;\n /** The control itself (Input, Select, Segmented, etc.). */\n children: ReactNode;\n /** Stack alignment override. Default: stretch. */\n align?: 'start' | 'center' | 'end' | 'stretch';\n /** Extra className for the wrapper. */\n className?: string;\n /** Optional id for the helper/error element (for aria-describedby). */\n helperId?: string;\n}\n\n/**\n * FormField — label + control + optional helper/error wrapper.\n *\n * Wires the helper or error element to the input via `aria-describedby`,\n * so screen readers announce them when the control receives focus.\n *\n * @example\n * <FormField label=\"Email\" helper=\"We'll never share this.\">\n * <Input type=\"email\" />\n * </FormField>\n *\n * <FormField label=\"Max models\" error=\"Pick a value between 1 and 10.\">\n * <Segmented value=\"3\" options={...} onChange={...} />\n * </FormField>\n */\nexport function FormField({\n label,\n helper,\n error,\n children,\n align = 'stretch',\n className,\n helperId,\n}: FormFieldProps) {\n const reactId = useId();\n const describedById = helperId ?? `magi-field-${reactId}`;\n\n return (\n <div\n className={cx(\n 'magi-field',\n `magi-field--align-${align}`,\n className,\n )}\n >\n <label className=\"magi-field-label\">{label}</label>\n {/* children are passed through; consumers should pass an input with id\n matching describedById (or omit and accept the default). */}\n {children}\n {(error || helper) && (\n <span\n id={describedById}\n className={cx(\n 'magi-field-helper',\n error && 'magi-field-helper--error',\n )}\n >\n {error || helper}\n </span>\n )}\n </div>\n );\n}","import type { ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type SegmentedSize = 'sm' | 'md' | 'lg';\n\nexport interface SegmentedOption<V extends string = string> {\n value: V;\n label: string;\n /** Optional: disable this individual option. */\n disabled?: boolean;\n}\n\nexport interface SegmentedProps<V extends string = string> {\n /** Currently selected option value. */\n value: V;\n /** Options to display. */\n options: SegmentedOption<V>[];\n /** Called when the user picks a different option. */\n onChange: (value: V) => void;\n /** Use accent color for the active state (cyan for tfi, etc.). Default: false. */\n accent?: boolean;\n /** Visual size. Default: `md`. */\n size?: SegmentedSize;\n /** Disable the whole control. */\n disabled?: boolean;\n /** Group label for screen readers. */\n 'aria-label'?: string;\n /** Optional id for the group. */\n id?: string;\n /** Extra className for the wrapper. */\n className?: string;\n /** Render-prop variant — render function receives each option and its state. */\n children?: (option: SegmentedOption<V>, state: {\n active: boolean;\n disabled: boolean;\n onSelect: () => void;\n }) => ReactNode;\n}\n\n/**\n * Segmented — pill-shaped single-select chip group.\n *\n * **SINGLE-SELECT ONLY.** For multi-select (e.g. provider toggles, multi-tag\n * pickers), use a `Checkbox` group instead — a multi-item segmented control\n * implies exclusive selection and confuses the interaction model.\n *\n * @example\n * <Segmented\n * value={contextMin}\n * options={[\n * { value: '128k', label: '128K+' },\n * { value: '32k', label: '32K+' },\n * { value: '8k', label: '8K+' },\n * { value: 'any', label: 'Any' },\n * ]}\n * onChange={(v) => setContextMin(v as ContextMin)}\n * />\n *\n * <Segmented value={cost} options={[...] onChange={...} accent />\n */\nexport function Segmented<V extends string = string>({\n value,\n options,\n onChange,\n accent = false,\n size = 'md',\n disabled = false,\n id,\n className,\n 'aria-label': ariaLabel,\n children,\n}: SegmentedProps<V>) {\n return (\n <div\n role=\"radiogroup\"\n id={id}\n aria-label={ariaLabel}\n className={cx(\n 'magi-segmented',\n `magi-segmented--${size}`,\n disabled && 'magi-segmented--disabled',\n className,\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n const isDisabled = !!(disabled || opt.disabled);\n const onSelect = () => {\n if (isDisabled || active) return;\n onChange(opt.value);\n };\n\n if (children) {\n return (\n <div key={opt.value}>\n {children(opt, { active, disabled: isDisabled, onSelect })}\n </div>\n );\n }\n\n return (\n <button\n key={opt.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={active}\n disabled={isDisabled}\n onClick={onSelect}\n className={cx(\n 'magi-segmented-item',\n active && 'magi-segmented-item--active',\n accent && 'magi-segmented-item--accent',\n )}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n );\n}","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type BannerVariant = 'warning' | 'error' | 'success' | 'info';\n\nexport interface BannerProps extends HTMLAttributes<HTMLDivElement> {\n /** Semantic variant. Default: `warning`. */\n variant?: BannerVariant;\n /** Banner content. Inline elements (links, code) are allowed. */\n children: ReactNode;\n}\n\n/**\n * Banner — inline notice with a left-border accent.\n *\n * Use for hints, warnings, errors, and confirmations. Persists until the\n * condition resolves; no dismiss by default.\n *\n * - `warning` (default) — yellow accent, actionable risk\n * - `error` — red accent, blocker\n * - `success` — green accent, confirmation\n * - `info` — cyan accent, neutral hint (uses product accent)\n *\n * @example\n * <Banner variant=\"info\">No requirements set. <a href=\"/\">Go back</a>.</Banner>\n * <Banner variant=\"error\">Could not load KV catalog: {error.message}.</Banner>\n * <Banner variant=\"success\">Saved.</Banner>\n */\nexport function Banner({\n variant = 'warning',\n className,\n children,\n ...rest\n}: BannerProps) {\n return (\n <div\n role={variant === 'error' || variant === 'warning' ? 'alert' : 'status'}\n className={cx(\n 'magi-banner',\n `magi-banner--${variant}`,\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n );\n}","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport interface EmptyStateProps extends HTMLAttributes<HTMLDivElement> {\n /** Optional bold title above the description (structured mode). */\n title?: string;\n /** Optional description text — used in structured mode. Defaults to children. */\n description?: ReactNode;\n /** Optional primary call-to-action (e.g. a Button or Link). */\n action?: ReactNode;\n /** Body content. Required in simple mode (when no `description`).\n * In structured mode it is shown only if `description` is not provided. */\n children?: ReactNode;\n}\n\n/**\n * EmptyState — centered placeholder for \"no data yet\" cases.\n *\n * Two patterns:\n *\n * @example Simple (string + inline elements):\n * <EmptyState>\n * No models match. Try loosening the constraints — <Link to=\"/\">edit requirements</Link>.\n * </EmptyState>\n *\n * @example Structured (title + description + action):\n * <EmptyState\n * title=\"Nothing selected\"\n * description=\"Pick models on the Browse page first.\"\n * action={<Button variant=\"primary\">Go to Browse</Button>}\n * />\n */\nexport function EmptyState({\n title,\n description,\n action,\n children,\n className,\n ...rest\n}: EmptyStateProps) {\n const structured = Boolean(title || description || action);\n const body = description ?? children;\n\n return (\n <div\n className={cx(\n 'magi-empty',\n structured && 'magi-empty--structured',\n className,\n )}\n {...rest}\n >\n {structured ? (\n <>\n {title ? <p className=\"magi-empty-title\">{title}</p> : null}\n {body !== undefined && body !== null ? (\n <p className=\"magi-empty-description\">{body}</p>\n ) : null}\n {action ? <div className=\"magi-empty-action\">{action}</div> : null}\n </>\n ) : (\n children\n )}\n </div>\n );\n}","/**\n * ProductTheme — allows a product to override the accent (and accent-muted\n * / accent-soft / accent-contrast) without touching typography, spacing, or\n * base surfaces. Implemented as CSS custom properties on a scoped selector;\n * components consume the variables and re-render automatically.\n *\n * Usage:\n * <ProductTheme accent=\"cyan\" name=\"token-factory\">\n * <App />\n * </ProductTheme>\n *\n * Or set them manually in CSS:\n * [data-magi-product='token-factory'] {\n * --magi-accent: #38bdf8;\n * --magi-accent-hover: #7dd3fc;\n * --magi-accent-soft: rgba(56, 189, 248, 0.08);\n * }\n */\n\nimport type { CSSProperties, ReactNode } from 'react';\n\nexport type ProductAccent =\n | 'green' // default — MAGI core\n | 'cyan' // Token Factory Initializr\n | 'violet' // API product\n | 'amber' // Agent product\n | 'white'; // monochrome MAGI\n\ninterface AccentTokens {\n '--magi-accent': string;\n '--magi-accent-hover': string;\n '--magi-accent-soft': string;\n '--magi-accent-contrast': string;\n}\n\nconst ACCENT_PRESETS: Record<ProductAccent, AccentTokens> = {\n green: {\n '--magi-accent': '#00c853',\n '--magi-accent-hover': '#00e676',\n '--magi-accent-soft': 'rgba(0, 200, 83, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n cyan: {\n '--magi-accent': '#38bdf8',\n '--magi-accent-hover': '#7dd3fc',\n '--magi-accent-soft': 'rgba(56, 189, 248, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n violet: {\n '--magi-accent': '#8b5cf6',\n '--magi-accent-hover': '#a78bfa',\n '--magi-accent-soft': 'rgba(139, 92, 246, 0.08)',\n '--magi-accent-contrast': '#f5f5f7',\n },\n amber: {\n '--magi-accent': '#f59e0b',\n '--magi-accent-hover': '#fbbf24',\n '--magi-accent-soft': 'rgba(245, 158, 11, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n white: {\n '--magi-accent': '#ffffff',\n '--magi-accent-hover': '#f5f5f7',\n '--magi-accent-soft': 'rgba(255, 255, 255, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n};\n\nexport interface ProductThemeProps {\n /** Accent preset. Default: `green`. */\n accent?: ProductAccent;\n /** Optional product identifier. Sets `data-magi-product=\"<name>\"`. */\n name?: string;\n /** Override individual token values; merged with the preset. */\n tokens?: Partial<CSSProperties>;\n children?: ReactNode;\n}\n\n/**\n * ProductTheme — overrides the MAGI accent for a subtree.\n *\n * Renders a `<div>` with `data-magi-product` and the accent tokens applied as\n * inline custom properties. All children consume the new accent automatically.\n */\nexport function ProductTheme({\n accent = 'green',\n name,\n tokens,\n children,\n}: ProductThemeProps) {\n const preset = ACCENT_PRESETS[accent];\n const style: CSSProperties = { ...preset, ...tokens };\n\n return (\n <div data-magi-product={name} style={style}>\n {children}\n </div>\n );\n}"],"names":["cx","parts","Container","size","as","className","children","rest","Component","cls","Section","spacing","surface","fullWidth","Stack","direction","gap","align","wrap","style","wrapStyle","jsx","Button","forwardRef","variant","loading","disabled","type","ref","Card","padding","Badge","dot","Checkbox","labelPosition","input","jsxs","Fragment","Input","inputSize","invalid","FormField","label","helper","error","helperId","reactId","useId","describedById","Segmented","value","options","onChange","accent","id","ariaLabel","opt","active","isDisabled","onSelect","Banner","EmptyState","title","description","action","structured","body","ACCENT_PRESETS","ProductTheme","name","tokens"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/classnames.ts","../src/layout/Container.tsx","../src/layout/Section.tsx","../src/layout/Stack.tsx","../src/components/Button/Button.tsx","../src/components/Card/Card.tsx","../src/components/Badge/Badge.tsx","../src/components/Checkbox/Checkbox.tsx","../src/components/Input/Input.tsx","../src/components/FormField/FormField.tsx","../src/components/Segmented/Segmented.tsx","../src/components/Banner/Banner.tsx","../src/components/EmptyState/EmptyState.tsx","../src/theme.tsx"],"sourcesContent":["/** Join truthy class strings with a space. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(' ');\n}","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type ContainerSize = 'sm' | 'md' | 'lg' | 'xl' | 'wide' | 'full';\n\nexport interface ContainerProps extends HTMLAttributes<HTMLElement> {\n /** Maximum width at desktop. Default: `xl` (1200px). */\n size?: ContainerSize;\n /** Override the rendered tag. Default: `div`. */\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Container — centers content and constrains max-width.\n *\n * @example\n * <Container size=\"lg\">...</Container>\n */\nexport function Container({\n size = 'xl',\n as,\n className,\n children,\n ...rest\n}: ContainerProps) {\n const Component = (as ?? 'div') as ElementType;\n const cls = cx('magi-container', `magi-container--${size}`, className);\n return (\n <Component className={cls} {...rest}>\n {children}\n </Component>\n );\n}\n","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type SectionSpacing = 'sm' | 'md' | 'lg' | 'xl';\nexport type SectionSurface = 'default' | 'raised' | 'elevated';\n\nexport interface SectionProps extends HTMLAttributes<HTMLElement> {\n /** Vertical padding scale. Default: `lg`. */\n spacing?: SectionSpacing;\n /** Background surface. Default: `default` (transparent). */\n surface?: SectionSurface;\n /** Drop the inner Container padding. Useful for full-bleed content. */\n fullWidth?: boolean;\n /** Override the rendered tag. Default: `section`. */\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Section — page-level vertical rhythm primitive.\n *\n * @example\n * <Section spacing=\"xl\" surface=\"default\">...</Section>\n */\nexport function Section({\n spacing = 'lg',\n surface = 'default',\n fullWidth = false,\n as,\n className,\n children,\n ...rest\n}: SectionProps) {\n const Component = (as ?? 'section') as ElementType;\n const cls = cx(\n 'magi-section',\n `magi-section--${spacing}`,\n `magi-section--${surface}`,\n fullWidth && 'magi-section--fullWidth',\n className,\n );\n return (\n <Component className={cls} {...rest}>\n {children}\n </Component>\n );\n}\n","import type { ElementType, HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../utils/classnames';\n\nexport type StackGap =\n | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '8' | '10' | '12' | '16';\nexport type StackAlign = 'start' | 'center' | 'end' | 'stretch';\n\nexport interface StackProps extends HTMLAttributes<HTMLElement> {\n /** Layout direction. Default: vertical (column). */\n direction?: 'row' | 'column';\n /** Gap token. Default: `4` (16px). */\n gap?: StackGap;\n /** Cross-axis alignment. Default: `stretch`. */\n align?: StackAlign;\n /** Allow wrapping when `direction=\"row\"`. Default: true. */\n wrap?: boolean;\n as?: ElementType;\n children?: ReactNode;\n}\n\n/**\n * Stack — vertical or horizontal flex primitive with semantic gap tokens.\n *\n * @example\n * <Stack gap=\"6\" align=\"center\">...</Stack>\n * <Stack direction=\"row\" gap=\"3\">...</Stack>\n */\nexport function Stack({\n direction = 'column',\n gap = '4',\n align = 'stretch',\n wrap = true,\n as,\n className,\n style,\n children,\n ...rest\n}: StackProps) {\n const Component = (as ?? 'div') as ElementType;\n const wrapStyle =\n direction === 'row' && !wrap ? { flexWrap: 'nowrap' as const } : undefined;\n const cls = cx(\n 'magi-stack',\n direction === 'row' && 'magi-stack--row',\n `magi-stack--gap-${gap}`,\n `magi-stack--align-${align}`,\n className,\n );\n\n return (\n <Component className={cls} style={{ ...wrapStyle, ...style }} {...rest}>\n {children}\n </Component>\n );\n}\n","import { forwardRef, type ButtonHTMLAttributes } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style. Default: `primary`. */\n variant?: ButtonVariant;\n /** Height + padding tier. Default: `md`. */\n size?: ButtonSize;\n /** Show a spinner and disable interaction. */\n loading?: boolean;\n}\n\n/**\n * Button — the canonical MAGI action element.\n *\n * Pill-shaped, four variants (primary/secondary/ghost/danger), three sizes.\n * Use `primary` for the dominant action on a page; `secondary` for supporting\n * actions; `ghost` for inline/tertiary; `danger` for destructive intent.\n *\n * @example\n * <Button variant=\"primary\" onClick={...}>Save</Button>\n * <Button variant=\"secondary\">Cancel</Button>\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n function Button(\n {\n variant = 'primary',\n size = 'md',\n loading = false,\n disabled,\n className,\n children,\n type,\n ...rest\n },\n ref,\n ) {\n const cls = cx(\n 'magi-button',\n `magi-button--${variant}`,\n `magi-button--${size}`,\n loading && 'magi-button--loading',\n className,\n );\n\n return (\n <button\n ref={ref}\n className={cls}\n type={type ?? 'button'}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...rest}\n >\n {children}\n </button>\n );\n },\n);\n","import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type CardVariant = 'default' | 'elevated' | 'interactive';\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Visual emphasis. Default: `default`. `interactive` adds hover state. */\n variant?: CardVariant;\n /** Inner padding. Default: `md`. */\n padding?: CardPadding;\n children?: ReactNode;\n}\n\n/**\n * Card — minimal dark surface with subtle border. Three variants:\n * default (flat), elevated (more contrast), interactive (hover state).\n *\n * @example\n * <Card variant=\"elevated\">...</Card>\n * <Card variant=\"interactive\" onClick={...}>...</Card>\n */\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n { variant = 'default', padding = 'md', className, children, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-card',\n `magi-card--${variant}`,\n `magi-card--padding-${padding}`,\n className,\n );\n return (\n <div ref={ref} className={cls} {...rest}>\n {children}\n </div>\n );\n});\n","import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type BadgeVariant = 'neutral' | 'accent' | 'success' | 'warning' | 'error';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Color/meaning. Default: `neutral`. */\n variant?: BadgeVariant;\n /** Show a leading colored dot. */\n dot?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Badge — compact status / metadata label.\n *\n * @example\n * <Badge variant=\"accent\">128K context</Badge>\n * <Badge variant=\"success\" dot>Online</Badge>\n */\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(function Badge(\n { variant = 'neutral', dot = false, className, children, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-badge',\n `magi-badge--${variant}`,\n className,\n );\n return (\n <span ref={ref} className={cls} {...rest}>\n {dot ? <span className=\"magi-badge__dot\" aria-hidden=\"true\" /> : null}\n {children}\n </span>\n );\n});\n","import {\n forwardRef,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type CheckboxLabelPosition = 'right' | 'left';\n\n/**\n * Omit `type` from native input attrs — this component is always\n * `type=\"checkbox\"` under the hood. Letting `type` pass through would\n * let consumers render e.g. `type=\"radio\"` with checkbox styles.\n */\nexport interface CheckboxProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {\n /** Optional label rendered next to the checkbox. */\n children?: ReactNode;\n /** Position of the label relative to the checkbox. Default: 'right'. */\n labelPosition?: CheckboxLabelPosition;\n}\n\n/**\n * Checkbox — restyled native checkbox for the MAGI dark theme.\n *\n * Uses a native `<input type=\"checkbox\">` under the hood for full form\n * integration and screen-reader compatibility. The CSS only restyles\n * the visible state.\n *\n * @example\n * // Uncontrolled:\n * <Checkbox aria-label=\"Accept terms\" defaultChecked />\n *\n * // Controlled with label:\n * <Checkbox\n * checked={providers.includes('nvidia')}\n * onChange={(e) => toggle('nvidia', e.target.checked)}\n * >\n * NVIDIA\n * </Checkbox>\n */\nexport const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(\n function Checkbox(\n {\n children,\n labelPosition = 'right',\n className,\n disabled,\n ...rest\n },\n ref,\n ) {\n const input = (\n <input\n ref={ref}\n type=\"checkbox\"\n className={cx('magi-checkbox', className)}\n disabled={disabled}\n {...rest}\n />\n );\n\n if (children === undefined || children === null) {\n return input;\n }\n\n return (\n <label\n className={cx(\n 'magi-checkbox-label',\n disabled && 'magi-checkbox-label--disabled',\n )}\n >\n {labelPosition === 'left' ? (\n <>\n <span>{children}</span>\n {input}\n </>\n ) : (\n <>\n {input}\n <span>{children}</span>\n </>\n )}\n </label>\n );\n },\n);","import { forwardRef, type InputHTMLAttributes } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type InputSize = 'sm' | 'md' | 'lg';\n\nexport interface InputProps extends InputHTMLAttributes<HTMLInputElement> {\n /** Visual size. Default: `md`. */\n inputSize?: InputSize;\n /** Error state — adds error border + aria-invalid. */\n invalid?: boolean;\n}\n\n/**\n * Input — `<input>` styled for the MAGI dark theme.\n *\n * Wraps the native element directly. No custom state management — value /\n * onChange / defaultValue / ref all pass through.\n *\n * @example\n * <Input placeholder=\"e.g. Coding assistant\" />\n * <Input type=\"password\" />\n * <Input invalid defaultValue=\"bad value\" />\n */\nexport const Input = forwardRef<HTMLInputElement, InputProps>(function Input(\n { inputSize = 'md', invalid = false, className, ...rest },\n ref,\n) {\n const cls = cx(\n 'magi-input',\n `magi-input--${inputSize}`,\n invalid && 'magi-input--invalid',\n className,\n );\n\n return (\n <input\n ref={ref}\n className={cls}\n aria-invalid={invalid || undefined}\n {...rest}\n />\n );\n});","import {\n Children,\n cloneElement,\n isValidElement,\n useId,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cx } from '../../utils/classnames';\n\ntype ChildProps = {\n id?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: boolean | 'grammar' | 'spelling' | 'false' | 'true';\n 'aria-labelledby'?: string;\n};\n\nexport interface FormFieldProps {\n /** Visible label above the control. Required. */\n label: string;\n /** Optional helper text below the control. */\n helper?: string;\n /** Error message — overrides helper styling + sets aria-invalid + aria-describedby. */\n error?: string;\n /** The control itself (Input, Select, Segmented, etc.). */\n children: ReactNode;\n /** Stack alignment override. Default: stretch. */\n align?: 'start' | 'center' | 'end' | 'stretch';\n /** Extra className for the wrapper. */\n className?: string;\n /** Optional id for the helper/error element (overrides the auto-generated one). */\n helperId?: string;\n}\n\n/**\n * Merge ARIA id-list attributes (space-separated per WAI-ARIA spec).\n * Empty / null / undefined entries are dropped.\n */\nfunction mergeIds(\n ...ids: Array<string | undefined | null>\n): string | undefined {\n const filtered = ids.filter(\n (id): id is string => typeof id === 'string' && id.length > 0,\n );\n return filtered.length > 0 ? filtered.join(' ') : undefined;\n}\n\n/**\n * FormField — label + control + optional helper/error wrapper.\n *\n * Wires `aria-describedby` to the helper/error span and `aria-labelledby`\n * to the label, by cloning the single child element with the appropriate\n * ARIA attributes. Sets `aria-invalid=\"true\"` on the child when `error` is\n * present.\n *\n * **Consumer-supplied ARIA attributes are preserved (merged, not overwritten).**\n * For example, if the consumer passes `aria-describedby=\"external-help\"`,\n * the resulting attribute is `\"external-help <generated-helper-id>\"`.\n * This matches the WAI-ARIA spec for multi-value id lists.\n *\n * The child MUST be a single focusable element (Input, Select, native\n * `<input>`, Segmented, etc.). If `children` is not a valid React element,\n * the ARIA wiring is skipped — the label and helper/error still render.\n *\n * @example\n * <FormField label=\"Email\" helper=\"We'll never share this.\">\n * <Input type=\"email\" placeholder=\"you@example.com\" />\n * </FormField>\n *\n * <FormField label=\"Max models\" error=\"Pick a value between 1 and 10.\">\n * <Segmented value=\"3\" options={...} onChange={...} />\n * </FormField>\n */\nexport function FormField({\n label,\n helper,\n error,\n children,\n align = 'stretch',\n className,\n helperId,\n}: FormFieldProps) {\n const reactId = useId();\n const fieldId = `magi-field-${reactId}`;\n const labelId = `${fieldId}-label`;\n const describedById = helperId ?? `${fieldId}-helper`;\n const hasMessage = Boolean(error || helper);\n\n let enhanced: ReactNode = children;\n if (isValidElement<ChildProps>(children)) {\n const existing = children.props;\n enhanced = cloneElement(children, {\n id: existing.id ?? fieldId,\n // MERGE with consumer-supplied IDs. The order is: consumer's first,\n // then FormField's. This matches ARIA's \"consumer-supplied IDs win\n // for ordering\" intuition — FormField's helpers are appended.\n 'aria-describedby': mergeIds(\n existing['aria-describedby'],\n hasMessage ? describedById : undefined,\n ),\n 'aria-labelledby': mergeIds(\n existing['aria-labelledby'],\n labelId,\n ),\n // aria-invalid: when FormField has an error, force true (overriding\n // consumer). When no error, preserve consumer's setting.\n 'aria-invalid': error ? true : (existing['aria-invalid'] ?? undefined),\n });\n }\n\n return (\n <div\n className={cx(\n 'magi-field',\n `magi-field--align-${align}`,\n className,\n )}\n >\n <label id={labelId} className=\"magi-field-label\">\n {label}\n </label>\n {enhanced}\n {hasMessage && (\n <span\n id={describedById}\n className={cx(\n 'magi-field-helper',\n error && 'magi-field-helper--error',\n )}\n >\n {error || helper}\n </span>\n )}\n </div>\n );\n}","import type { ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type SegmentedSize = 'sm' | 'md' | 'lg';\n\nexport interface SegmentedOption<V extends string = string> {\n value: V;\n label: string;\n /** Optional: disable this individual option. */\n disabled?: boolean;\n}\n\nexport interface SegmentedProps<V extends string = string> {\n /** Currently selected option value. */\n value: V;\n /** Options to display. */\n options: SegmentedOption<V>[];\n /** Called when the user picks a different option. */\n onChange: (value: V) => void;\n /** Use accent color for the active state (cyan for tfi, etc.). Default: false. */\n accent?: boolean;\n /** Visual size. Default: `md`. */\n size?: SegmentedSize;\n /** Disable the whole control. */\n disabled?: boolean;\n /** Group label for screen readers. */\n 'aria-label'?: string;\n /** Optional id for the group. */\n id?: string;\n /** Extra className for the wrapper. */\n className?: string;\n /** Render-prop variant — render function receives each option and its state. */\n children?: (option: SegmentedOption<V>, state: {\n active: boolean;\n disabled: boolean;\n onSelect: () => void;\n }) => ReactNode;\n}\n\n/**\n * Segmented — pill-shaped single-select chip group.\n *\n * **SINGLE-SELECT ONLY.** For multi-select (e.g. provider toggles, multi-tag\n * pickers), use a `Checkbox` group instead — a multi-item segmented control\n * implies exclusive selection and confuses the interaction model.\n *\n * @example\n * <Segmented\n * value={contextMin}\n * options={[\n * { value: '128k', label: '128K+' },\n * { value: '32k', label: '32K+' },\n * { value: '8k', label: '8K+' },\n * { value: 'any', label: 'Any' },\n * ]}\n * onChange={(v) => setContextMin(v as ContextMin)}\n * />\n *\n * <Segmented value={cost} options={[...] onChange={...} accent />\n */\nexport function Segmented<V extends string = string>({\n value,\n options,\n onChange,\n accent = false,\n size = 'md',\n disabled = false,\n id,\n className,\n 'aria-label': ariaLabel,\n children,\n}: SegmentedProps<V>) {\n return (\n <div\n role=\"radiogroup\"\n id={id}\n aria-label={ariaLabel}\n className={cx(\n 'magi-segmented',\n `magi-segmented--${size}`,\n disabled && 'magi-segmented--disabled',\n className,\n )}\n >\n {options.map((opt) => {\n const active = opt.value === value;\n const isDisabled = !!(disabled || opt.disabled);\n const onSelect = () => {\n if (isDisabled || active) return;\n onChange(opt.value);\n };\n\n if (children) {\n return (\n <div key={opt.value}>\n {children(opt, { active, disabled: isDisabled, onSelect })}\n </div>\n );\n }\n\n return (\n <button\n key={opt.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={active}\n disabled={isDisabled}\n onClick={onSelect}\n className={cx(\n 'magi-segmented-item',\n active && 'magi-segmented-item--active',\n accent && 'magi-segmented-item--accent',\n )}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n );\n}","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport type BannerVariant = 'warning' | 'error' | 'success' | 'info';\n\nexport interface BannerProps extends HTMLAttributes<HTMLDivElement> {\n /** Semantic variant. Default: `warning`. */\n variant?: BannerVariant;\n /** Banner content. Inline elements (links, code) are allowed. */\n children: ReactNode;\n}\n\n/**\n * Banner — inline notice with a left-border accent.\n *\n * Use for hints, warnings, errors, and confirmations. Persists until the\n * condition resolves; no dismiss by default.\n *\n * - `warning` (default) — yellow accent, actionable risk\n * - `error` — red accent, blocker\n * - `success` — green accent, confirmation\n * - `info` — cyan accent, neutral hint (uses product accent)\n *\n * @example\n * <Banner variant=\"info\">No requirements set. <a href=\"/\">Go back</a>.</Banner>\n * <Banner variant=\"error\">Could not load KV catalog: {error.message}.</Banner>\n * <Banner variant=\"success\">Saved.</Banner>\n */\nexport function Banner({\n variant = 'warning',\n className,\n children,\n ...rest\n}: BannerProps) {\n return (\n <div\n role={variant === 'error' || variant === 'warning' ? 'alert' : 'status'}\n className={cx(\n 'magi-banner',\n `magi-banner--${variant}`,\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n );\n}","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cx } from '../../utils/classnames';\n\nexport interface EmptyStateProps extends HTMLAttributes<HTMLDivElement> {\n /** Optional bold title above the description (structured mode). */\n title?: string;\n /** Optional description text — used in structured mode. Defaults to children. */\n description?: ReactNode;\n /** Optional primary call-to-action (e.g. a Button or Link). */\n action?: ReactNode;\n /** Body content. Required in simple mode (when no `description`).\n * In structured mode it is shown only if `description` is not provided. */\n children?: ReactNode;\n}\n\n/**\n * EmptyState — centered placeholder for \"no data yet\" cases.\n *\n * Two patterns:\n *\n * @example Simple (string + inline elements):\n * <EmptyState>\n * No models match. Try loosening the constraints — <Link to=\"/\">edit requirements</Link>.\n * </EmptyState>\n *\n * @example Structured (title + description + action):\n * <EmptyState\n * title=\"Nothing selected\"\n * description=\"Pick models on the Browse page first.\"\n * action={<Button variant=\"primary\">Go to Browse</Button>}\n * />\n */\nexport function EmptyState({\n title,\n description,\n action,\n children,\n className,\n ...rest\n}: EmptyStateProps) {\n const structured = Boolean(title || description || action);\n const body = description ?? children;\n\n return (\n <div\n className={cx(\n 'magi-empty',\n structured && 'magi-empty--structured',\n className,\n )}\n {...rest}\n >\n {structured ? (\n <>\n {title ? <p className=\"magi-empty-title\">{title}</p> : null}\n {body !== undefined && body !== null ? (\n <p className=\"magi-empty-description\">{body}</p>\n ) : null}\n {action ? <div className=\"magi-empty-action\">{action}</div> : null}\n </>\n ) : (\n children\n )}\n </div>\n );\n}","import {\n createContext,\n useContext,\n useInsertionEffect,\n useMemo,\n type ReactNode,\n} from 'react';\n\nexport type ProductAccent =\n | 'green' // default — MAGI core\n | 'cyan' // Token Factory Initializr\n | 'violet' // API product\n | 'amber' // Agent product\n | 'white'; // monochrome MAGI\n\ninterface AccentTokens {\n '--magi-accent': string;\n '--magi-accent-hover': string;\n '--magi-accent-soft': string;\n '--magi-accent-contrast': string;\n}\n\nconst ACCENT_PRESETS: Record<ProductAccent, AccentTokens> = {\n green: {\n '--magi-accent': '#00c853',\n '--magi-accent-hover': '#00e676',\n '--magi-accent-soft': 'rgba(0, 200, 83, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n cyan: {\n '--magi-accent': '#38bdf8',\n '--magi-accent-hover': '#7dd3fc',\n '--magi-accent-soft': 'rgba(56, 189, 248, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n violet: {\n '--magi-accent': '#8b5cf6',\n '--magi-accent-hover': '#a78bfa',\n '--magi-accent-soft': 'rgba(139, 92, 246, 0.08)',\n '--magi-accent-contrast': '#f5f5f7',\n },\n amber: {\n '--magi-accent': '#f59e0b',\n '--magi-accent-hover': '#fbbf24',\n '--magi-accent-soft': 'rgba(245, 158, 11, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n white: {\n '--magi-accent': '#ffffff',\n '--magi-accent-hover': '#f5f5f7',\n '--magi-accent-soft': 'rgba(255, 255, 255, 0.08)',\n '--magi-accent-contrast': '#050505',\n },\n};\n\ninterface ProductThemeContextValue {\n accent: ProductAccent;\n}\n\nconst ProductThemeContext = createContext<ProductThemeContextValue | null>(null);\n\n/**\n * Hook for any JS-aware consumer that needs the current accent.\n * Returns `{ accent: 'green' }` (the default) when used outside a `<ProductTheme>`.\n */\nexport function useProductTheme(): ProductThemeContextValue {\n const ctx = useContext(ProductThemeContext);\n return ctx ?? { accent: 'green' };\n}\n\nexport interface ProductThemeProps {\n /** Accent preset. Default: `green`. */\n accent?: ProductAccent;\n /** Optional product identifier. Sets `data-magi-product=\"<name>\"` on `<html>`. */\n name?: string;\n children?: ReactNode;\n}\n\n/**\n * ProductTheme — overrides the MAGI accent for a subtree.\n *\n * Renders only a React context provider (no DOM wrapper). On mount, sets\n * the four accent CSS variables on `<html>` so all descendants inherit via\n * CSS cascade. For scoped overrides within a subtree, consumers can use:\n *\n * <div data-magi-accent=\"danger\">\n * <Button variant=\"primary\">Delete</Button>\n * </div>\n *\n * SSR: useInsertionEffect does not run on the server, so on SSR pages\n * the default theme applies during the initial render. For SSR theming\n * without FOUC, set `data-magi-accent=\"<name>\"` on `<html>` in your\n * server-side layout — the CSS rule in globals.css picks it up.\n *\n * Nested <ProductTheme>: each instance snapshots the previous accent\n * values on mount and restores them on unmount, so a child mounting\n * and unmounting leaves the outer theme intact. Note that CSS variables\n * are global (set on `<html>`), so siblings outside a child subtree\n * still see the child's accent — use `<div data-magi-accent=\"...\">`\n * for true CSS subtree scope.\n *\n * @example\n * function App() {\n * return (\n * <ProductTheme accent=\"cyan\" name=\"token-factory\">\n * <Routes />\n * </ProductTheme>\n * );\n * }\n */\nexport function ProductTheme({\n accent = 'green',\n name,\n children,\n}: ProductThemeProps) {\n const value = useMemo(() => ({ accent }), [accent]);\n\n useInsertionEffect(() => {\n if (typeof document === 'undefined') return;\n const tokens = ACCENT_PRESETS[accent];\n const root = document.documentElement;\n\n // Snapshot previous values so the cleanup can restore them on unmount\n // or accent change. This makes nested themes work correctly: the inner\n // theme restores the outer theme's values when it unmounts.\n const prev = {\n accent: root.style.getPropertyValue('--magi-accent'),\n accentHover: root.style.getPropertyValue('--magi-accent-hover'),\n accentSoft: root.style.getPropertyValue('--magi-accent-soft'),\n accentContrast: root.style.getPropertyValue('--magi-accent-contrast'),\n product: root.dataset.magiProduct,\n };\n\n root.style.setProperty('--magi-accent', tokens['--magi-accent']);\n root.style.setProperty('--magi-accent-hover', tokens['--magi-accent-hover']);\n root.style.setProperty('--magi-accent-soft', tokens['--magi-accent-soft']);\n root.style.setProperty('--magi-accent-contrast', tokens['--magi-accent-contrast']);\n\n if (name) {\n root.dataset.magiProduct = name;\n } else {\n delete root.dataset.magiProduct;\n }\n\n return () => {\n const restoreOrRemove = (prop: string, prevValue: string) => {\n if (prevValue) root.style.setProperty(prop, prevValue);\n else root.style.removeProperty(prop);\n };\n restoreOrRemove('--magi-accent', prev.accent);\n restoreOrRemove('--magi-accent-hover', prev.accentHover);\n restoreOrRemove('--magi-accent-soft', prev.accentSoft);\n restoreOrRemove('--magi-accent-contrast', prev.accentContrast);\n\n if (prev.product !== undefined) {\n root.dataset.magiProduct = prev.product;\n } else if (root.dataset.magiProduct !== undefined) {\n delete root.dataset.magiProduct;\n }\n };\n }, [accent, name]);\n\n return (\n <ProductThemeContext.Provider value={value}>\n {children}\n </ProductThemeContext.Provider>\n );\n}"],"names":["cx","parts","Container","size","as","className","children","rest","Component","cls","Section","spacing","surface","fullWidth","Stack","direction","gap","align","wrap","style","wrapStyle","jsx","Button","forwardRef","variant","loading","disabled","type","ref","Card","padding","Badge","dot","Checkbox","labelPosition","input","jsxs","Fragment","Input","inputSize","invalid","mergeIds","ids","filtered","id","FormField","label","helper","error","helperId","fieldId","useId","labelId","describedById","hasMessage","enhanced","isValidElement","existing","cloneElement","Segmented","value","options","onChange","accent","ariaLabel","opt","active","isDisabled","onSelect","Banner","EmptyState","title","description","action","structured","body","ACCENT_PRESETS","ProductThemeContext","createContext","ProductTheme","name","useMemo","useInsertionEffect","tokens","root","prev","restoreOrRemove","prop","prevValue"],"mappings":"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"}
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- :root{--magi-bg-base: #000000;--magi-bg-raised: #1d1d1f;--magi-bg-card: rgba(255, 255, 255, .04);--magi-bg-card-hover: rgba(255, 255, 255, .06);--magi-surface: #0a0a0a;--magi-surface-elevated: #171717;--magi-text-primary: #f5f5f7;--magi-text-secondary: #86868b;--magi-text-tertiary: #6e6e73;--magi-text-inverse: #050505;--magi-border: rgba(255, 255, 255, .08);--magi-border-strong: rgba(255, 255, 255, .14);--magi-accent: #00c853;--magi-accent-hover: #00e676;--magi-accent-soft: rgba(0, 200, 83, .08);--magi-accent-contrast: #050505;--magi-selection-bg: rgba(0, 200, 83, .3);--magi-selection-fg: #f5f5f7;--magi-success: #30d158;--magi-warning: #ff9f0a;--magi-error: #ff453a;--magi-scrollbar-thumb: rgba(255, 255, 255, .18);--magi-scrollbar-thumb-hover: rgba(255, 255, 255, .32)}:root{--magi-font-sans: Inter, -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", Arial, system-ui, sans-serif;--magi-font-mono: "SFMono-Regular", "Cascadia Code", "Roboto Mono", Menlo, Consolas, monospace;--magi-font-size-display: 4.5rem;--magi-font-size-h1: 3rem;--magi-font-size-h2: 2.25rem;--magi-font-size-h3: 1.5rem;--magi-font-size-h4: 1.25rem;--magi-font-size-body-lg: 1.125rem;--magi-font-size-body: 1rem;--magi-font-size-body-sm: .875rem;--magi-font-size-label: .8125rem;--magi-font-size-caption: .75rem;--magi-font-size-code: .875rem;--magi-font-weight-light: 300;--magi-font-weight-normal: 400;--magi-font-weight-medium: 500;--magi-font-weight-semibold: 600;--magi-font-weight-bold: 700;--magi-tracking-tightest: -.045em;--magi-tracking-tighter: -.03em;--magi-tracking-tight: -.01em;--magi-tracking-normal: 0;--magi-tracking-wide: .05em;--magi-tracking-widest: .18em;--magi-leading-display: 1.05;--magi-leading-tight: 1.15;--magi-leading-snug: 1.3;--magi-leading-normal: 1.5;--magi-leading-relaxed: 1.625}:root{--magi-space-0: 0;--magi-space-1: .25rem;--magi-space-2: .5rem;--magi-space-3: .75rem;--magi-space-4: 1rem;--magi-space-5: 1.25rem;--magi-space-6: 1.5rem;--magi-space-8: 2rem;--magi-space-10: 2.5rem;--magi-space-12: 3rem;--magi-space-16: 4rem;--magi-space-20: 5rem;--magi-space-24: 6rem;--magi-space-32: 8rem;--magi-space-40: 10rem}:root{--magi-radius-sm: 6px;--magi-radius-md: 10px;--magi-radius-lg: 14px;--magi-radius-xl: 20px;--magi-radius-2xl: 28px;--magi-radius-full: 999px}:root{--magi-duration-fast: .12s;--magi-duration-normal: .2s;--magi-duration-slow: .32s;--magi-ease-standard: cubic-bezier(.2, 0, 0, 1);--magi-ease-emphasized: cubic-bezier(.3, 0, 0, 1);--magi-ease-out: cubic-bezier(0, 0, .2, 1)}@media (prefers-reduced-motion: reduce){:root{--magi-duration-fast: .01ms;--magi-duration-normal: .01ms;--magi-duration-slow: .01ms}}:root{--magi-bp-sm: 640px;--magi-bp-md: 768px;--magi-bp-lg: 1024px;--magi-bp-xl: 1280px;--magi-bp-2xl: 1536px}:root{--magi-z-base: 0;--magi-z-raised: 10;--magi-z-dropdown: 100;--magi-z-sticky: 200;--magi-z-overlay: 300;--magi-z-modal: 400;--magi-z-toast: 500;--magi-container-sm: 640px;--magi-container-md: 768px;--magi-container-lg: 1024px;--magi-container-xl: 1200px;--magi-container-wide: 1400px;--magi-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);--magi-shadow-md: 0 4px 12px rgba(0, 0, 0, .5);--magi-shadow-lg: 0 12px 32px rgba(0, 0, 0, .6);--magi-focus-ring: 0 0 0 2px var(--magi-bg-base), 0 0 0 4px var(--magi-accent)}[data-magi-app]{box-sizing:border-box;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}[data-magi-app],[data-magi-app] *,[data-magi-app] *:before,[data-magi-app] *:after{box-sizing:inherit}body[data-magi-app]{margin:0}[data-magi-app] img,[data-magi-app] svg,[data-magi-app] video{max-width:100%;display:block}[data-magi-app] button{font:inherit;color:inherit;border:0;padding:0;cursor:pointer}[data-magi-app] a{color:inherit;text-decoration:none}[data-magi-app] input,[data-magi-app] textarea,[data-magi-app] select{font:inherit;color:inherit}[data-magi-app]{font-family:var(--magi-font-sans);font-size:var(--magi-font-size-body);font-weight:var(--magi-font-weight-normal);line-height:var(--magi-leading-normal);color:var(--magi-text-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}body[data-magi-app]{background-color:var(--magi-bg-base);background-image:radial-gradient(ellipse 80% 50% at 50% -10%,rgba(255,255,255,.06),transparent 60%),linear-gradient(180deg,var(--magi-bg-raised) 0%,var(--magi-bg-base) 35%);background-attachment:fixed;min-height:100vh}[data-magi-app] ::selection{background:var(--magi-selection-bg);color:var(--magi-selection-fg)}html:has(body[data-magi-app]){scrollbar-width:thin;scrollbar-color:var(--magi-scrollbar-thumb) transparent}body[data-magi-app] ::-webkit-scrollbar{width:6px;height:6px}body[data-magi-app] ::-webkit-scrollbar-track{background:transparent}body[data-magi-app] ::-webkit-scrollbar-thumb{background:#fff0;border-radius:var(--magi-radius-full);transition:background var(--magi-duration-slow) var(--magi-ease-out)}body[data-magi-app]:hover ::-webkit-scrollbar-thumb,body[data-magi-app][data-scrolling] ::-webkit-scrollbar-thumb{background:var(--magi-scrollbar-thumb)}body[data-magi-app]:hover ::-webkit-scrollbar-thumb:hover,body[data-magi-app][data-scrolling] ::-webkit-scrollbar-thumb:hover{background:var(--magi-scrollbar-thumb-hover)}[data-magi-app] a{transition:color var(--magi-duration-normal) var(--magi-ease-standard)}[data-magi-app] :focus-visible{outline:none;box-shadow:var(--magi-focus-ring);border-radius:var(--magi-radius-sm)}@media (prefers-reduced-motion: reduce){[data-magi-app] *,[data-magi-app] *:before,[data-magi-app] *:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}html:has(body[data-magi-app]){scroll-behavior:auto}}[data-magi-app] .magi-display{font-size:var(--magi-font-size-display);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tightest);line-height:var(--magi-leading-display);color:var(--magi-text-primary);text-wrap:balance}[data-magi-app] .magi-h1{font-size:var(--magi-font-size-h1);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tighter);line-height:var(--magi-leading-tight);color:var(--magi-text-primary)}[data-magi-app] .magi-h2{font-size:var(--magi-font-size-h2);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tighter);line-height:var(--magi-leading-tight);color:var(--magi-text-primary)}[data-magi-app] .magi-h3{font-size:var(--magi-font-size-h3);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tight);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-h4{font-size:var(--magi-font-size-h4);font-weight:var(--magi-font-weight-medium);letter-spacing:var(--magi-tracking-tight);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-body-lg{font-size:var(--magi-font-size-body-lg);line-height:var(--magi-leading-relaxed);color:var(--magi-text-secondary)}[data-magi-app] .magi-body{font-size:var(--magi-font-size-body);line-height:var(--magi-leading-normal);color:var(--magi-text-secondary)}[data-magi-app] .magi-body-sm{font-size:var(--magi-font-size-body-sm);line-height:var(--magi-leading-normal);color:var(--magi-text-secondary)}[data-magi-app] .magi-label{font-size:var(--magi-font-size-label);font-weight:var(--magi-font-weight-medium);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-caption{font-size:var(--magi-font-size-caption);line-height:var(--magi-leading-snug);color:var(--magi-text-tertiary)}[data-magi-app] .magi-eyebrow{font-size:var(--magi-font-size-body-sm);font-weight:var(--magi-font-weight-medium);text-transform:uppercase;letter-spacing:var(--magi-tracking-widest);color:var(--magi-accent)}[data-magi-app] .magi-code{font-family:var(--magi-font-mono);font-size:var(--magi-font-size-code);line-height:var(--magi-leading-snug);color:var(--magi-text-primary);background:var(--magi-surface);padding:0 var(--magi-space-1);border-radius:var(--magi-radius-sm);border:1px solid var(--magi-border)}body[data-magi-app] .magi-container{margin-inline:auto;padding-inline:var(--magi-space-6);width:100%}@media (min-width: 768px){.magi-container{padding-inline:var(--magi-space-8)}}body[data-magi-app] .magi-container--sm{max-width:var(--magi-container-sm)}body[data-magi-app] .magi-container--md{max-width:var(--magi-container-md)}body[data-magi-app] .magi-container--lg{max-width:var(--magi-container-lg)}body[data-magi-app] .magi-container--xl{max-width:var(--magi-container-xl)}body[data-magi-app] .magi-container--wide{max-width:var(--magi-container-wide)}body[data-magi-app] .magi-container--full{max-width:100%}body[data-magi-app] .magi-section{width:100%;position:relative}body[data-magi-app] .magi-section--sm{padding-block:var(--magi-space-12)}body[data-magi-app] .magi-section--md{padding-block:var(--magi-space-20)}body[data-magi-app] .magi-section--lg,body[data-magi-app] .magi-section--xl{padding-block:var(--magi-space-32)}@media (min-width: 768px){.magi-section--xl{padding-block:var(--magi-space-40)}}body[data-magi-app] .magi-section--default{background:transparent}body[data-magi-app] .magi-section--raised{background-color:var(--magi-surface);border-block:1px solid var(--magi-border)}body[data-magi-app] .magi-section--elevated{background-color:var(--magi-surface-elevated)}body[data-magi-app] .magi-section--fullWidth{padding-inline:0}body[data-magi-app] .magi-stack{display:flex;flex-direction:column;min-width:0}body[data-magi-app] .magi-stack--row{display:flex;flex-direction:row;flex-wrap:wrap;min-width:0}body[data-magi-app] .magi-stack--gap-0{gap:var(--magi-space-0)}body[data-magi-app] .magi-stack--gap-1{gap:var(--magi-space-1)}body[data-magi-app] .magi-stack--gap-2{gap:var(--magi-space-2)}body[data-magi-app] .magi-stack--gap-3{gap:var(--magi-space-3)}body[data-magi-app] .magi-stack--gap-4{gap:var(--magi-space-4)}body[data-magi-app] .magi-stack--gap-5{gap:var(--magi-space-5)}body[data-magi-app] .magi-stack--gap-6{gap:var(--magi-space-6)}body[data-magi-app] .magi-stack--gap-8{gap:var(--magi-space-8)}body[data-magi-app] .magi-stack--gap-10{gap:var(--magi-space-10)}body[data-magi-app] .magi-stack--gap-12{gap:var(--magi-space-12)}body[data-magi-app] .magi-stack--gap-16{gap:var(--magi-space-16)}body[data-magi-app] .magi-stack--align-start{align-items:flex-start}body[data-magi-app] .magi-stack--align-center{align-items:center}body[data-magi-app] .magi-stack--align-end{align-items:flex-end}body[data-magi-app] .magi-stack--align-stretch{align-items:stretch}body[data-magi-app] .magi-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--magi-space-2);font-family:inherit;font-weight:var(--magi-font-weight-medium);line-height:1;text-align:center;white-space:nowrap;cursor:pointer;border-radius:var(--magi-radius-full);border:1px solid transparent;transition:background-color var(--magi-duration-normal) var(--magi-ease-standard),color var(--magi-duration-normal) var(--magi-ease-standard),border-color var(--magi-duration-normal) var(--magi-ease-standard),transform var(--magi-duration-fast) var(--magi-ease-standard);-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;text-decoration:none;background-color:transparent}.magi-button:disabled,body[data-magi-app] .magi-button[aria-disabled=true]{cursor:not-allowed;opacity:.5;pointer-events:none}body[data-magi-app] .magi-button:active:not(:disabled){transform:scale(.98)}body[data-magi-app] .magi-button--primary{background-color:var(--magi-accent);color:var(--magi-accent-contrast);border-color:var(--magi-accent)}body[data-magi-app] .magi-button--primary:hover:not(:disabled){background-color:var(--magi-accent-hover);border-color:var(--magi-accent-hover)}body[data-magi-app] .magi-button--secondary{background-color:transparent;color:var(--magi-text-primary);border-color:var(--magi-border-strong)}body[data-magi-app] .magi-button--secondary:hover:not(:disabled){background-color:#ffffff0d;border-color:#ffffff4d}body[data-magi-app] .magi-button--ghost{background-color:transparent;color:var(--magi-text-primary);border-color:transparent}body[data-magi-app] .magi-button--ghost:hover:not(:disabled){background-color:#ffffff0f}body[data-magi-app] .magi-button--danger{background-color:var(--magi-error);color:var(--magi-text-primary);border-color:var(--magi-error)}body[data-magi-app] .magi-button--danger:hover:not(:disabled){filter:brightness(1.1)}body[data-magi-app] .magi-button--sm{font-size:var(--magi-font-size-body-sm);padding:var(--magi-space-2) var(--magi-space-4);min-height:32px}body[data-magi-app] .magi-button--md{font-size:var(--magi-font-size-body-sm);padding:var(--magi-space-3) var(--magi-space-6);min-height:40px}body[data-magi-app] .magi-button--lg{font-size:var(--magi-font-size-body);padding:var(--magi-space-4) var(--magi-space-8);min-height:48px}body[data-magi-app] .magi-button--loading{position:relative;color:transparent!important;pointer-events:none}body[data-magi-app] .magi-button--loading:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;width:1em;height:1em;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--magi-radius-full);animation:magiButtonSpin .8s linear infinite;color:var(--magi-accent-contrast)}.magi-button--primary.magi-button--loading:after,body[data-magi-app] .magi-button--danger.magi-button--loading:after{color:var(--magi-text-primary)}@keyframes magiButtonSpin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.magi-button--loading:after{animation-duration:1.6s}}body[data-magi-app] .magi-card{background-color:var(--magi-bg-card);border:1px solid var(--magi-border);border-radius:var(--magi-radius-xl);color:var(--magi-text-primary);transition:background-color var(--magi-duration-slow) var(--magi-ease-standard),border-color var(--magi-duration-slow) var(--magi-ease-standard),transform var(--magi-duration-normal) var(--magi-ease-standard);position:relative}body[data-magi-app] .magi-card--padding-none{padding:0}body[data-magi-app] .magi-card--padding-sm{padding:var(--magi-space-4)}body[data-magi-app] .magi-card--padding-md{padding:var(--magi-space-6)}body[data-magi-app] .magi-card--padding-lg{padding:var(--magi-space-8)}body[data-magi-app] .magi-card--elevated{background-color:var(--magi-surface-elevated);border-color:var(--magi-border);box-shadow:var(--magi-shadow-md)}body[data-magi-app] .magi-card--interactive{cursor:pointer;text-decoration:none}body[data-magi-app] .magi-card--interactive:hover{background-color:var(--magi-bg-card-hover);border-color:var(--magi-border-strong)}body[data-magi-app] .magi-card--interactive:active{transform:translateY(1px)}@media (prefers-reduced-motion: reduce){.magi-card,.magi-card--interactive{transition:none}.magi-card--interactive:active{transform:none}}body[data-magi-app] .magi-badge{display:inline-flex;align-items:center;gap:var(--magi-space-2);font-family:inherit;font-size:var(--magi-font-size-caption);font-weight:var(--magi-font-weight-medium);line-height:1;padding:var(--magi-space-2) var(--magi-space-3);border-radius:var(--magi-radius-full);border:1px solid transparent;white-space:nowrap;-webkit-user-select:none;user-select:none}body[data-magi-app] .magi-badge__dot{display:inline-block;width:6px;height:6px;border-radius:var(--magi-radius-full);background:currentColor;flex-shrink:0}body[data-magi-app] .magi-badge--neutral{background:#ffffff0f;color:var(--magi-text-secondary);border-color:var(--magi-border)}body[data-magi-app] .magi-badge--accent{background:var(--magi-accent-soft);color:var(--magi-accent);border-color:color-mix(in srgb,var(--magi-accent) 25%,transparent)}body[data-magi-app] .magi-badge--success{background:#30d1581f;color:var(--magi-success);border-color:#30d1584d}body[data-magi-app] .magi-badge--warning{background:#ff9f0a1f;color:var(--magi-warning);border-color:#ff9f0a4d}body[data-magi-app] .magi-badge--error{background:#ff453a1f;color:var(--magi-error);border-color:#ff453a4d}body[data-magi-app] .magi-checkbox{-moz-appearance:none;appearance:none;-webkit-appearance:none;width:18px;height:18px;border:1px solid var(--magi-border);border-radius:var(--magi-radius-sm);background:var(--magi-bg-card);cursor:pointer;flex-shrink:0;position:relative;transition:background-color var(--magi-duration-fast) var(--magi-ease-standard),border-color var(--magi-duration-fast) var(--magi-ease-standard);margin:0;vertical-align:middle}body[data-magi-app] .magi-checkbox:hover{border-color:var(--magi-border-strong)}body[data-magi-app] .magi-checkbox:checked{background-color:var(--magi-accent);border-color:var(--magi-accent)}body[data-magi-app] .magi-checkbox:checked:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;width:5px;height:9px;border:solid var(--magi-text-inverse);border-width:0 2px 2px 0;transform:rotate(45deg) translate(-1px,-1px)}body[data-magi-app] .magi-checkbox:focus-visible{outline:none;box-shadow:var(--magi-focus-ring)}body[data-magi-app] .magi-checkbox:disabled{opacity:.4;cursor:not-allowed}body[data-magi-app] .magi-checkbox-label{display:inline-flex;align-items:center;gap:var(--magi-space-2);cursor:pointer;-webkit-user-select:none;user-select:none}body[data-magi-app] .magi-checkbox-label--disabled{cursor:not-allowed;opacity:.5}@media (prefers-reduced-motion: reduce){body[data-magi-app] .magi-checkbox{transition:none}}body[data-magi-app] .magi-input{width:100%;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--magi-surface);border:1px solid var(--magi-border);border-radius:var(--magi-radius-md);color:var(--magi-text-primary);font-family:inherit;font-size:14px;padding:10px 12px;outline:none;transition:border-color var(--magi-duration-fast) var(--magi-ease-standard)}body[data-magi-app] .magi-input:focus{border-color:var(--magi-accent)}body[data-magi-app] .magi-input::placeholder{color:var(--magi-text-tertiary)}body[data-magi-app] .magi-input:disabled{opacity:.5;cursor:not-allowed}body[data-magi-app] .magi-input:focus-visible{outline:none;box-shadow:var(--magi-focus-ring)}body[data-magi-app] .magi-input--sm{padding:6px 10px;font-size:13px}body[data-magi-app] .magi-input--md{padding:10px 12px;font-size:14px}body[data-magi-app] .magi-input--lg{padding:14px 16px;font-size:16px}body[data-magi-app] .magi-input--invalid,body[data-magi-app] .magi-input--invalid:focus{border-color:var(--magi-error)}@media (prefers-reduced-motion: reduce){body[data-magi-app] .magi-input{transition:none}}body[data-magi-app] .magi-field{display:flex;flex-direction:column;gap:var(--magi-space-2);min-width:0}body[data-magi-app] .magi-field-label{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--magi-text-tertiary);font-weight:500}body[data-magi-app] .magi-field-helper{font-size:var(--magi-font-size-caption);color:var(--magi-text-tertiary)}body[data-magi-app] .magi-field-helper--error{color:var(--magi-error)}body[data-magi-app] .magi-segmented{display:inline-flex;border:1px solid var(--magi-border);border-radius:var(--magi-radius-md);background-color:var(--magi-surface);padding:2px;gap:2px}body[data-magi-app] .magi-segmented-item{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;color:var(--magi-text-secondary);font-size:13px;font-family:inherit;font-weight:500;padding:6px 12px;border-radius:5px;cursor:pointer;transition:background-color var(--magi-duration-fast) var(--magi-ease-standard),color var(--magi-duration-fast) var(--magi-ease-standard)}body[data-magi-app] .magi-segmented-item:hover{color:var(--magi-text-primary)}body[data-magi-app] .magi-segmented-item--active{background-color:var(--magi-surface-elevated);color:var(--magi-text-primary);box-shadow:inset 0 0 0 1px var(--magi-border)}body[data-magi-app] .magi-segmented-item--accent.magi-segmented-item--active{background-color:var(--magi-accent-soft);color:var(--magi-accent);box-shadow:inset 0 0 0 1px var(--magi-accent)}body[data-magi-app] .magi-segmented-item:focus-visible{outline:none;box-shadow:var(--magi-focus-ring)}body[data-magi-app] .magi-segmented-item:disabled,body[data-magi-app] .magi-segmented--disabled .magi-segmented-item{cursor:not-allowed;opacity:.5}body[data-magi-app] .magi-segmented--sm .magi-segmented-item{padding:4px 10px;font-size:12px}body[data-magi-app] .magi-segmented--lg .magi-segmented-item{padding:8px 14px;font-size:14px}@media (prefers-reduced-motion: reduce){body[data-magi-app] .magi-segmented-item{transition:none}}body[data-magi-app] .magi-banner{background-color:var(--magi-surface);border:1px solid var(--magi-border);border-left:2px solid var(--magi-warning);border-radius:var(--magi-radius-md);color:var(--magi-text-primary);padding:var(--magi-space-3) var(--magi-space-4);font-size:13px;line-height:var(--magi-leading-snug)}body[data-magi-app] .magi-banner--warning{border-left-color:var(--magi-warning)}body[data-magi-app] .magi-banner--error{border-left-color:var(--magi-error)}body[data-magi-app] .magi-banner--success{border-left-color:var(--magi-success)}body[data-magi-app] .magi-banner--info{border-left-color:var(--magi-accent)}body[data-magi-app] .magi-banner a{color:var(--magi-accent);text-decoration:underline;text-underline-offset:2px}body[data-magi-app] .magi-empty{padding:var(--magi-space-7);text-align:center;color:var(--magi-text-secondary);background-color:var(--magi-surface);border:1px dashed var(--magi-border);border-radius:var(--magi-radius-lg);font-size:14px;line-height:var(--magi-leading-snug)}body[data-magi-app] .magi-empty--structured{display:flex;flex-direction:column;align-items:center;gap:var(--magi-space-3)}body[data-magi-app] .magi-empty-title{color:var(--magi-text-primary);font-size:var(--magi-font-size-body-lg);font-weight:var(--magi-font-weight-medium);margin:0}body[data-magi-app] .magi-empty-description{color:var(--magi-text-secondary);margin:0;max-width:480px}body[data-magi-app] .magi-empty-action{margin-top:var(--magi-space-2)}body[data-magi-app] .magi-empty a{color:var(--magi-accent);text-decoration:underline;text-underline-offset:2px}
1
+ @layer magi.reset,magi.tokens,magi.foundation,magi.layout,magi.components;@layer magi.tokens{:root{--magi-bg-base: #000000;--magi-bg-raised: #1d1d1f;--magi-bg-card: rgba(255, 255, 255, .04);--magi-bg-card-hover: rgba(255, 255, 255, .06);--magi-surface: #0a0a0a;--magi-surface-elevated: #171717;--magi-text-primary: #f5f5f7;--magi-text-secondary: #86868b;--magi-text-tertiary: #6e6e73;--magi-text-inverse: #050505;--magi-border: rgba(255, 255, 255, .08);--magi-border-strong: rgba(255, 255, 255, .14);--magi-accent: #00c853;--magi-accent-hover: #00e676;--magi-accent-soft: rgba(0, 200, 83, .08);--magi-accent-contrast: #050505;--magi-selection-bg: rgba(0, 200, 83, .3);--magi-selection-fg: #f5f5f7;--magi-success: #30d158;--magi-warning: #ff9f0a;--magi-error: #ff453a;--magi-scrollbar-thumb: rgba(255, 255, 255, .18);--magi-scrollbar-thumb-hover: rgba(255, 255, 255, .32)}}@layer magi.tokens{:root{--magi-font-sans: Inter, -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", Arial, system-ui, sans-serif;--magi-font-mono: "SFMono-Regular", "Cascadia Code", "Roboto Mono", Menlo, Consolas, monospace;--magi-font-size-display: 4.5rem;--magi-font-size-h1: 3rem;--magi-font-size-h2: 2.25rem;--magi-font-size-h3: 1.5rem;--magi-font-size-h4: 1.25rem;--magi-font-size-body-lg: 1.125rem;--magi-font-size-body: 1rem;--magi-font-size-body-sm: .875rem;--magi-font-size-label: .8125rem;--magi-font-size-caption: .75rem;--magi-font-size-code: .875rem;--magi-font-weight-light: 300;--magi-font-weight-normal: 400;--magi-font-weight-medium: 500;--magi-font-weight-semibold: 600;--magi-font-weight-bold: 700;--magi-tracking-tightest: -.045em;--magi-tracking-tighter: -.03em;--magi-tracking-tight: -.01em;--magi-tracking-normal: 0;--magi-tracking-wide: .05em;--magi-tracking-widest: .18em;--magi-leading-display: 1.05;--magi-leading-tight: 1.15;--magi-leading-snug: 1.3;--magi-leading-normal: 1.5;--magi-leading-relaxed: 1.625}}@layer magi.tokens{:root{--magi-space-0: 0;--magi-space-1: .25rem;--magi-space-2: .5rem;--magi-space-3: .75rem;--magi-space-4: 1rem;--magi-space-5: 1.25rem;--magi-space-6: 1.5rem;--magi-space-8: 2rem;--magi-space-10: 2.5rem;--magi-space-12: 3rem;--magi-space-16: 4rem;--magi-space-20: 5rem;--magi-space-24: 6rem;--magi-space-32: 8rem;--magi-space-40: 10rem}}@layer magi.tokens{:root{--magi-radius-sm: 6px;--magi-radius-md: 10px;--magi-radius-lg: 14px;--magi-radius-xl: 20px;--magi-radius-2xl: 28px;--magi-radius-full: 999px}}@layer magi.tokens{:root{--magi-duration-fast: .12s;--magi-duration-normal: .2s;--magi-duration-slow: .32s;--magi-ease-standard: cubic-bezier(.2, 0, 0, 1);--magi-ease-emphasized: cubic-bezier(.3, 0, 0, 1);--magi-ease-out: cubic-bezier(0, 0, .2, 1)}}@media (prefers-reduced-motion: reduce){:root{--magi-duration-fast: .01ms;--magi-duration-normal: .01ms;--magi-duration-slow: .01ms}}@layer magi.tokens{:root{--magi-bp-sm: 640px;--magi-bp-md: 768px;--magi-bp-lg: 1024px;--magi-bp-xl: 1280px;--magi-bp-2xl: 1536px}}@layer magi.tokens{:root{--magi-z-base: 0;--magi-z-raised: 10;--magi-z-dropdown: 100;--magi-z-sticky: 200;--magi-z-overlay: 300;--magi-z-modal: 400;--magi-z-toast: 500;--magi-container-sm: 640px;--magi-container-md: 768px;--magi-container-lg: 1024px;--magi-container-xl: 1200px;--magi-container-wide: 1400px;--magi-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);--magi-shadow-md: 0 4px 12px rgba(0, 0, 0, .5);--magi-shadow-lg: 0 12px 32px rgba(0, 0, 0, .6);--magi-focus-ring: 0 0 0 2px var(--magi-bg-base), 0 0 0 4px var(--magi-accent)}}@layer magi.reset{[data-magi-app]{box-sizing:border-box;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}[data-magi-app],[data-magi-app] *,[data-magi-app] *:before,[data-magi-app] *:after{box-sizing:inherit}body[data-magi-app]{margin:0}[data-magi-app] img,[data-magi-app] svg,[data-magi-app] video{max-width:100%;display:block}[data-magi-app] button{font:inherit;color:inherit;border:0;padding:0;cursor:pointer}[data-magi-app] a{color:inherit;text-decoration:none}[data-magi-app] input,[data-magi-app] textarea,[data-magi-app] select{font:inherit;color:inherit}}@layer magi.foundation{[data-magi-app]{font-family:var(--magi-font-sans);font-size:var(--magi-font-size-body);font-weight:var(--magi-font-weight-normal);line-height:var(--magi-leading-normal);color:var(--magi-text-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}body[data-magi-app]{background-color:var(--magi-bg-base);background-image:radial-gradient(ellipse 80% 50% at 50% -10%,color-mix(in srgb,var(--magi-text-primary) 6%,transparent),transparent 60%),linear-gradient(180deg,var(--magi-bg-raised) 0%,var(--magi-bg-base) 35%);background-attachment:fixed;min-height:100vh}[data-magi-app] ::selection{background:var(--magi-selection-bg);color:var(--magi-selection-fg)}html:has(body[data-magi-app]){scrollbar-width:thin;scrollbar-color:var(--magi-scrollbar-thumb) transparent}body[data-magi-app] ::-webkit-scrollbar{width:6px;height:6px}body[data-magi-app] ::-webkit-scrollbar-track{background:transparent}body[data-magi-app] ::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--magi-text-primary) 0%,transparent);border-radius:var(--magi-radius-full);transition:background var(--magi-duration-slow) var(--magi-ease-out)}body[data-magi-app]:hover ::-webkit-scrollbar-thumb,body[data-magi-app][data-scrolling] ::-webkit-scrollbar-thumb{background:var(--magi-scrollbar-thumb)}body[data-magi-app]:hover ::-webkit-scrollbar-thumb:hover,body[data-magi-app][data-scrolling] ::-webkit-scrollbar-thumb:hover{background:var(--magi-scrollbar-thumb-hover)}[data-magi-app] a{transition:color var(--magi-duration-normal) var(--magi-ease-standard)}[data-magi-app] :focus-visible{outline:none;box-shadow:var(--magi-focus-ring);border-radius:var(--magi-radius-sm)}[data-magi-app] [data-magi-accent=green]{--magi-accent: #00c853;--magi-accent-hover: #00e676}[data-magi-app] [data-magi-accent=cyan]{--magi-accent: #38bdf8;--magi-accent-hover: #7dd3fc}[data-magi-app] [data-magi-accent=violet]{--magi-accent: #8b5cf6;--magi-accent-hover: #a78bfa}[data-magi-app] [data-magi-accent=amber]{--magi-accent: #f59e0b;--magi-accent-hover: #fbbf24}[data-magi-app] [data-magi-accent=white]{--magi-accent: #ffffff;--magi-accent-hover: #f5f5f7}[data-magi-app] [data-magi-accent=danger]{--magi-accent: var(--magi-error)}[data-magi-app] [data-magi-accent=warning]{--magi-accent: var(--magi-warning)}[data-magi-app] [data-magi-accent=success]{--magi-accent: var(--magi-success)}@media (prefers-reduced-motion: reduce){[data-magi-app] *,[data-magi-app] *:before,[data-magi-app] *:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}html:has(body[data-magi-app]){scroll-behavior:auto}}}@layer magi.foundation{[data-magi-app] .magi-display{font-size:var(--magi-font-size-display);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tightest);line-height:var(--magi-leading-display);color:var(--magi-text-primary);text-wrap:balance}[data-magi-app] .magi-h1{font-size:var(--magi-font-size-h1);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tighter);line-height:var(--magi-leading-tight);color:var(--magi-text-primary)}[data-magi-app] .magi-h2{font-size:var(--magi-font-size-h2);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tighter);line-height:var(--magi-leading-tight);color:var(--magi-text-primary)}[data-magi-app] .magi-h3{font-size:var(--magi-font-size-h3);font-weight:var(--magi-font-weight-semibold);letter-spacing:var(--magi-tracking-tight);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-h4{font-size:var(--magi-font-size-h4);font-weight:var(--magi-font-weight-medium);letter-spacing:var(--magi-tracking-tight);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-body-lg{font-size:var(--magi-font-size-body-lg);line-height:var(--magi-leading-relaxed);color:var(--magi-text-secondary)}[data-magi-app] .magi-body{font-size:var(--magi-font-size-body);line-height:var(--magi-leading-normal);color:var(--magi-text-secondary)}[data-magi-app] .magi-body-sm{font-size:var(--magi-font-size-body-sm);line-height:var(--magi-leading-normal);color:var(--magi-text-secondary)}[data-magi-app] .magi-label{font-size:var(--magi-font-size-label);font-weight:var(--magi-font-weight-medium);line-height:var(--magi-leading-snug);color:var(--magi-text-primary)}[data-magi-app] .magi-caption{font-size:var(--magi-font-size-caption);line-height:var(--magi-leading-snug);color:var(--magi-text-tertiary)}[data-magi-app] .magi-eyebrow{font-size:var(--magi-font-size-body-sm);font-weight:var(--magi-font-weight-medium);text-transform:uppercase;letter-spacing:var(--magi-tracking-widest);color:var(--magi-accent)}[data-magi-app] .magi-code{font-family:var(--magi-font-mono);font-size:var(--magi-font-size-code);line-height:var(--magi-leading-snug);color:var(--magi-text-primary);background:var(--magi-surface);padding:0 var(--magi-space-1);border-radius:var(--magi-radius-sm);border:1px solid var(--magi-border)}}@layer magi.layout{body[data-magi-app] .magi-container{margin-inline:auto;padding-inline:var(--magi-space-6);width:100%}@media (min-width: 768px){.magi-container{padding-inline:var(--magi-space-8)}}body[data-magi-app] .magi-container--sm{max-width:var(--magi-container-sm)}body[data-magi-app] .magi-container--md{max-width:var(--magi-container-md)}body[data-magi-app] .magi-container--lg{max-width:var(--magi-container-lg)}body[data-magi-app] .magi-container--xl{max-width:var(--magi-container-xl)}body[data-magi-app] .magi-container--wide{max-width:var(--magi-container-wide)}body[data-magi-app] .magi-container--full{max-width:100%}}@layer magi.layout{body[data-magi-app] .magi-section{width:100%;position:relative}body[data-magi-app] .magi-section--sm{padding-block:var(--magi-space-12)}body[data-magi-app] .magi-section--md{padding-block:var(--magi-space-20)}body[data-magi-app] .magi-section--lg,body[data-magi-app] .magi-section--xl{padding-block:var(--magi-space-32)}@media (min-width: 768px){.magi-section--xl{padding-block:var(--magi-space-40)}}body[data-magi-app] .magi-section--default{background:transparent}body[data-magi-app] .magi-section--raised{background-color:var(--magi-surface);border-block:1px solid var(--magi-border)}body[data-magi-app] .magi-section--elevated{background-color:var(--magi-surface-elevated)}body[data-magi-app] .magi-section--fullWidth{padding-inline:0}}@layer magi.layout{body[data-magi-app] .magi-stack{display:flex;flex-direction:column;min-width:0}body[data-magi-app] .magi-stack--row{display:flex;flex-direction:row;flex-wrap:wrap;min-width:0}body[data-magi-app] .magi-stack--gap-0{gap:var(--magi-space-0)}body[data-magi-app] .magi-stack--gap-1{gap:var(--magi-space-1)}body[data-magi-app] .magi-stack--gap-2{gap:var(--magi-space-2)}body[data-magi-app] .magi-stack--gap-3{gap:var(--magi-space-3)}body[data-magi-app] .magi-stack--gap-4{gap:var(--magi-space-4)}body[data-magi-app] .magi-stack--gap-5{gap:var(--magi-space-5)}body[data-magi-app] .magi-stack--gap-6{gap:var(--magi-space-6)}body[data-magi-app] .magi-stack--gap-8{gap:var(--magi-space-8)}body[data-magi-app] .magi-stack--gap-10{gap:var(--magi-space-10)}body[data-magi-app] .magi-stack--gap-12{gap:var(--magi-space-12)}body[data-magi-app] .magi-stack--gap-16{gap:var(--magi-space-16)}body[data-magi-app] .magi-stack--align-start{align-items:flex-start}body[data-magi-app] .magi-stack--align-center{align-items:center}body[data-magi-app] .magi-stack--align-end{align-items:flex-end}body[data-magi-app] .magi-stack--align-stretch{align-items:stretch}}@layer magi.components{body[data-magi-app] .magi-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--magi-space-2);font-family:inherit;font-weight:var(--magi-font-weight-medium);line-height:1;text-align:center;white-space:nowrap;cursor:pointer;border-radius:var(--magi-radius-full);border:1px solid transparent;transition:background-color var(--magi-duration-normal) var(--magi-ease-standard),color var(--magi-duration-normal) var(--magi-ease-standard),border-color var(--magi-duration-normal) var(--magi-ease-standard),transform var(--magi-duration-fast) var(--magi-ease-standard);-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;text-decoration:none;background-color:transparent}.magi-button:disabled,body[data-magi-app] .magi-button[aria-disabled=true]{cursor:not-allowed;opacity:.5;pointer-events:none}body[data-magi-app] .magi-button:active:not(:disabled){transform:scale(.98)}body[data-magi-app] .magi-button--primary{background-color:var(--magi-accent);color:var(--magi-accent-contrast);border-color:var(--magi-accent)}body[data-magi-app] .magi-button--primary:hover:not(:disabled){background-color:var(--magi-accent-hover);border-color:var(--magi-accent-hover)}body[data-magi-app] .magi-button--secondary{background-color:transparent;color:var(--magi-text-primary);border-color:var(--magi-border-strong)}body[data-magi-app] .magi-button--secondary:hover:not(:disabled){background-color:color-mix(in srgb,var(--magi-text-primary) 5%,transparent);border-color:color-mix(in srgb,var(--magi-text-primary) 30%,transparent)}body[data-magi-app] .magi-button--ghost{background-color:transparent;color:var(--magi-text-primary);border-color:transparent}body[data-magi-app] .magi-button--ghost:hover:not(:disabled){background-color:color-mix(in srgb,var(--magi-text-primary) 6%,transparent)}body[data-magi-app] .magi-button--danger{background-color:var(--magi-error);color:var(--magi-text-primary);border-color:var(--magi-error)}body[data-magi-app] .magi-button--danger:hover:not(:disabled){filter:brightness(1.1)}body[data-magi-app] .magi-button--sm{font-size:var(--magi-font-size-body-sm);padding:var(--magi-space-2) var(--magi-space-4);min-height:32px}body[data-magi-app] .magi-button--md{font-size:var(--magi-font-size-body-sm);padding:var(--magi-space-3) var(--magi-space-6);min-height:40px}body[data-magi-app] .magi-button--lg{font-size:var(--magi-font-size-body);padding:var(--magi-space-4) var(--magi-space-8);min-height:48px}body[data-magi-app] .magi-button--loading{position:relative;color:transparent!important;pointer-events:none}body[data-magi-app] .magi-button--loading:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;width:1em;height:1em;border:2px solid currentColor;border-top-color:transparent;border-radius:var(--magi-radius-full);animation:magiButtonSpin .8s linear infinite;color:var(--magi-accent-contrast)}.magi-button--primary.magi-button--loading:after,body[data-magi-app] .magi-button--danger.magi-button--loading:after{color:var(--magi-text-primary)}@keyframes magiButtonSpin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.magi-button--loading:after{animation-duration:1.6s}}}@layer magi.components{body[data-magi-app] .magi-card{background-color:var(--magi-bg-card);border:1px solid var(--magi-border);border-radius:var(--magi-radius-xl);color:var(--magi-text-primary);transition:background-color var(--magi-duration-slow) var(--magi-ease-standard),border-color var(--magi-duration-slow) var(--magi-ease-standard),transform var(--magi-duration-normal) var(--magi-ease-standard);position:relative}body[data-magi-app] .magi-card--padding-none{padding:0}body[data-magi-app] .magi-card--padding-sm{padding:var(--magi-space-4)}body[data-magi-app] .magi-card--padding-md{padding:var(--magi-space-6)}body[data-magi-app] .magi-card--padding-lg{padding:var(--magi-space-8)}body[data-magi-app] .magi-card--elevated{background-color:var(--magi-surface-elevated);border-color:var(--magi-border);box-shadow:var(--magi-shadow-md)}body[data-magi-app] .magi-card--interactive{cursor:pointer;text-decoration:none}body[data-magi-app] .magi-card--interactive:hover{background-color:var(--magi-bg-card-hover);border-color:var(--magi-border-strong)}body[data-magi-app] .magi-card--interactive:active{transform:translateY(1px)}@media (prefers-reduced-motion: reduce){.magi-card,.magi-card--interactive{transition:none}.magi-card--interactive:active{transform:none}}}@layer magi.components{body[data-magi-app] .magi-badge{display:inline-flex;align-items:center;gap:var(--magi-space-2);font-family:inherit;font-size:var(--magi-font-size-caption);font-weight:var(--magi-font-weight-medium);line-height:1;padding:var(--magi-space-2) var(--magi-space-3);border-radius:var(--magi-radius-full);border:1px solid transparent;white-space:nowrap;-webkit-user-select:none;user-select:none}body[data-magi-app] .magi-badge__dot{display:inline-block;width:6px;height:6px;border-radius:var(--magi-radius-full);background:currentColor;flex-shrink:0}body[data-magi-app] .magi-badge--neutral{background:color-mix(in srgb,var(--magi-text-primary) 6%,transparent);color:var(--magi-text-secondary);border-color:var(--magi-border)}body[data-magi-app] .magi-badge--accent{background:var(--magi-accent-soft);color:var(--magi-accent);border-color:color-mix(in srgb,var(--magi-accent) 25%,transparent)}body[data-magi-app] .magi-badge--success{background:color-mix(in srgb,var(--magi-success) 12%,transparent);color:var(--magi-success);border-color:color-mix(in srgb,var(--magi-success) 30%,transparent)}body[data-magi-app] .magi-badge--warning{background:color-mix(in srgb,var(--magi-warning) 12%,transparent);color:var(--magi-warning);border-color:color-mix(in srgb,var(--magi-warning) 30%,transparent)}body[data-magi-app] .magi-badge--error{background:color-mix(in srgb,var(--magi-error) 12%,transparent);color:var(--magi-error);border-color:color-mix(in srgb,var(--magi-error) 30%,transparent)}}@layer magi.components{body[data-magi-app] .magi-checkbox{-moz-appearance:none;appearance:none;-webkit-appearance:none;width:18px;height:18px;border:1px solid var(--magi-border);border-radius:var(--magi-radius-sm);background:var(--magi-bg-card);cursor:pointer;flex-shrink:0;position:relative;transition:background-color var(--magi-duration-fast) var(--magi-ease-standard),border-color var(--magi-duration-fast) var(--magi-ease-standard);margin:0;vertical-align:middle}body[data-magi-app] .magi-checkbox:hover{border-color:var(--magi-border-strong)}body[data-magi-app] .magi-checkbox:checked{background-color:var(--magi-accent);border-color:var(--magi-accent)}body[data-magi-app] .magi-checkbox:checked:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;width:5px;height:9px;border:solid var(--magi-text-inverse);border-width:0 2px 2px 0;transform:rotate(45deg) translate(-1px,-1px)}body[data-magi-app] .magi-checkbox:focus-visible{outline:none;box-shadow:var(--magi-focus-ring)}body[data-magi-app] .magi-checkbox:disabled{opacity:.4;cursor:not-allowed}body[data-magi-app] .magi-checkbox-label{display:inline-flex;align-items:center;gap:var(--magi-space-2);cursor:pointer;-webkit-user-select:none;user-select:none}body[data-magi-app] .magi-checkbox-label--disabled{cursor:not-allowed;opacity:.5}@media (prefers-reduced-motion: reduce){body[data-magi-app] .magi-checkbox{transition:none}}}@layer magi.components{body[data-magi-app] .magi-input{width:100%;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--magi-surface);border:1px solid var(--magi-border);border-radius:var(--magi-radius-md);color:var(--magi-text-primary);font-family:inherit;font-size:var(--magi-font-size-body-sm);padding:10px 12px;outline:none;transition:border-color var(--magi-duration-fast) var(--magi-ease-standard)}body[data-magi-app] .magi-input:focus{border-color:var(--magi-accent)}body[data-magi-app] .magi-input::placeholder{color:var(--magi-text-tertiary)}body[data-magi-app] .magi-input:disabled{opacity:.5;cursor:not-allowed}body[data-magi-app] .magi-input:focus-visible{outline:none;box-shadow:var(--magi-focus-ring)}body[data-magi-app] .magi-input--sm{padding:6px 10px;font-size:var(--magi-font-size-label)}body[data-magi-app] .magi-input--md{padding:10px 12px;font-size:var(--magi-font-size-body-sm)}body[data-magi-app] .magi-input--lg{padding:14px 16px;font-size:var(--magi-font-size-body)}body[data-magi-app] .magi-input--invalid,body[data-magi-app] .magi-input--invalid:focus{border-color:var(--magi-error)}@media (prefers-reduced-motion: reduce){body[data-magi-app] .magi-input{transition:none}}}@layer magi.components{body[data-magi-app] .magi-field{display:flex;flex-direction:column;gap:var(--magi-space-2);min-width:0}body[data-magi-app] .magi-field-label{font-size:var(--magi-font-size-label);text-transform:uppercase;letter-spacing:.08em;color:var(--magi-text-tertiary);font-weight:500}body[data-magi-app] .magi-field-helper{font-size:var(--magi-font-size-caption);color:var(--magi-text-tertiary)}body[data-magi-app] .magi-field-helper--error{color:var(--magi-error)}}@layer magi.components{body[data-magi-app] .magi-segmented{display:inline-flex;border:1px solid var(--magi-border);border-radius:var(--magi-radius-md);background-color:var(--magi-surface);padding:2px;gap:2px}body[data-magi-app] .magi-segmented-item{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:transparent;color:var(--magi-text-secondary);font-size:var(--magi-font-size-label);font-family:inherit;font-weight:500;padding:6px 12px;border-radius:5px;cursor:pointer;transition:background-color var(--magi-duration-fast) var(--magi-ease-standard),color var(--magi-duration-fast) var(--magi-ease-standard)}body[data-magi-app] .magi-segmented-item:hover{color:var(--magi-text-primary)}body[data-magi-app] .magi-segmented-item--active{background-color:var(--magi-surface-elevated);color:var(--magi-text-primary);box-shadow:inset 0 0 0 1px var(--magi-border)}body[data-magi-app] .magi-segmented-item--accent.magi-segmented-item--active{background-color:var(--magi-accent-soft);color:var(--magi-accent);box-shadow:inset 0 0 0 1px var(--magi-accent)}body[data-magi-app] .magi-segmented-item:focus-visible{outline:none;box-shadow:var(--magi-focus-ring)}body[data-magi-app] .magi-segmented-item:disabled,body[data-magi-app] .magi-segmented--disabled .magi-segmented-item{cursor:not-allowed;opacity:.5}body[data-magi-app] .magi-segmented--sm .magi-segmented-item{padding:4px 10px;font-size:var(--magi-font-size-caption)}body[data-magi-app] .magi-segmented--lg .magi-segmented-item{padding:8px 14px;font-size:var(--magi-font-size-body-sm)}@media (prefers-reduced-motion: reduce){body[data-magi-app] .magi-segmented-item{transition:none}}}@layer magi.components{body[data-magi-app] .magi-banner{background-color:var(--magi-surface);border:1px solid var(--magi-border);border-left:2px solid var(--magi-warning);border-radius:var(--magi-radius-md);color:var(--magi-text-primary);padding:var(--magi-space-3) var(--magi-space-4);font-size:var(--magi-font-size-label);line-height:var(--magi-leading-snug)}body[data-magi-app] .magi-banner--warning{border-left-color:var(--magi-warning)}body[data-magi-app] .magi-banner--error{border-left-color:var(--magi-error)}body[data-magi-app] .magi-banner--success{border-left-color:var(--magi-success)}body[data-magi-app] .magi-banner--info{border-left-color:var(--magi-accent)}body[data-magi-app] .magi-banner a{color:var(--magi-accent);text-decoration:underline;text-underline-offset:2px}}@layer magi.components{body[data-magi-app] .magi-empty{padding:var(--magi-space-7);text-align:center;color:var(--magi-text-secondary);background-color:var(--magi-surface);border:1px dashed var(--magi-border);border-radius:var(--magi-radius-lg);font-size:var(--magi-font-size-body-sm);line-height:var(--magi-leading-snug)}body[data-magi-app] .magi-empty--structured{display:flex;flex-direction:column;align-items:center;gap:var(--magi-space-3)}body[data-magi-app] .magi-empty-title{color:var(--magi-text-primary);font-size:var(--magi-font-size-body-lg);font-weight:var(--magi-font-weight-medium);margin:0}body[data-magi-app] .magi-empty-description{color:var(--magi-text-secondary);margin:0;max-width:480px}body[data-magi-app] .magi-empty-action{margin-top:var(--magi-space-2)}body[data-magi-app] .magi-empty a{color:var(--magi-accent);text-decoration:underline;text-underline-offset:2px}}
package/dist/theme.d.ts CHANGED
@@ -1,37 +1,52 @@
1
+ import { type ReactNode } from 'react';
2
+ export type ProductAccent = 'green' | 'cyan' | 'violet' | 'amber' | 'white';
3
+ interface ProductThemeContextValue {
4
+ accent: ProductAccent;
5
+ }
1
6
  /**
2
- * ProductTheme — allows a product to override the accent (and accent-muted
3
- * / accent-soft / accent-contrast) without touching typography, spacing, or
4
- * base surfaces. Implemented as CSS custom properties on a scoped selector;
5
- * components consume the variables and re-render automatically.
6
- *
7
- * Usage:
8
- * <ProductTheme accent="cyan" name="token-factory">
9
- * <App />
10
- * </ProductTheme>
11
- *
12
- * Or set them manually in CSS:
13
- * [data-magi-product='token-factory'] {
14
- * --magi-accent: #38bdf8;
15
- * --magi-accent-hover: #7dd3fc;
16
- * --magi-accent-soft: rgba(56, 189, 248, 0.08);
17
- * }
7
+ * Hook for any JS-aware consumer that needs the current accent.
8
+ * Returns `{ accent: 'green' }` (the default) when used outside a `<ProductTheme>`.
18
9
  */
19
- import type { CSSProperties, ReactNode } from 'react';
20
- export type ProductAccent = 'green' | 'cyan' | 'violet' | 'amber' | 'white';
10
+ export declare function useProductTheme(): ProductThemeContextValue;
21
11
  export interface ProductThemeProps {
22
12
  /** Accent preset. Default: `green`. */
23
13
  accent?: ProductAccent;
24
- /** Optional product identifier. Sets `data-magi-product="<name>"`. */
14
+ /** Optional product identifier. Sets `data-magi-product="<name>"` on `<html>`. */
25
15
  name?: string;
26
- /** Override individual token values; merged with the preset. */
27
- tokens?: Partial<CSSProperties>;
28
16
  children?: ReactNode;
29
17
  }
30
18
  /**
31
19
  * ProductTheme — overrides the MAGI accent for a subtree.
32
20
  *
33
- * Renders a `<div>` with `data-magi-product` and the accent tokens applied as
34
- * inline custom properties. All children consume the new accent automatically.
21
+ * Renders only a React context provider (no DOM wrapper). On mount, sets
22
+ * the four accent CSS variables on `<html>` so all descendants inherit via
23
+ * CSS cascade. For scoped overrides within a subtree, consumers can use:
24
+ *
25
+ * <div data-magi-accent="danger">
26
+ * <Button variant="primary">Delete</Button>
27
+ * </div>
28
+ *
29
+ * SSR: useInsertionEffect does not run on the server, so on SSR pages
30
+ * the default theme applies during the initial render. For SSR theming
31
+ * without FOUC, set `data-magi-accent="<name>"` on `<html>` in your
32
+ * server-side layout — the CSS rule in globals.css picks it up.
33
+ *
34
+ * Nested <ProductTheme>: each instance snapshots the previous accent
35
+ * values on mount and restores them on unmount, so a child mounting
36
+ * and unmounting leaves the outer theme intact. Note that CSS variables
37
+ * are global (set on `<html>`), so siblings outside a child subtree
38
+ * still see the child's accent — use `<div data-magi-accent="...">`
39
+ * for true CSS subtree scope.
40
+ *
41
+ * @example
42
+ * function App() {
43
+ * return (
44
+ * <ProductTheme accent="cyan" name="token-factory">
45
+ * <Routes />
46
+ * </ProductTheme>
47
+ * );
48
+ * }
35
49
  */
36
- export declare function ProductTheme({ accent, name, tokens, children, }: ProductThemeProps): import("react").JSX.Element;
50
+ export declare function ProductTheme({ accent, name, children, }: ProductThemeProps): import("react").JSX.Element;
51
+ export {};
37
52
  //# sourceMappingURL=theme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,MAAM,GACN,QAAQ,GACR,OAAO,GACP,OAAO,CAAC;AA0CZ,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAgB,EAChB,IAAI,EACJ,MAAM,EACN,QAAQ,GACT,EAAE,iBAAiB,+BASnB"}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,MAAM,GACN,QAAQ,GACR,OAAO,GACP,OAAO,CAAC;AA0CZ,UAAU,wBAAwB;IAChC,MAAM,EAAE,aAAa,CAAC;CACvB;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,wBAAwB,CAG1D;AAED,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAgB,EAChB,IAAI,EACJ,QAAQ,GACT,EAAE,iBAAiB,+BAqDnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokyo3rdhq/magi-design-system",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Shared visual foundation for the MAGI product family — dark-first, near-monochrome, restrained.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -2,11 +2,20 @@
2
2
  *
3
3
  * import '@tokyo3rdhq/magi-design-system/styles.css';
4
4
  *
5
- * Imports tokens + foundation + all component styles. Place on the application
6
- * root. Components reference CSS variables only — they do not introduce new
7
- * global class names.
5
+ * Layer order (declared by the next line) determines cascade priority:
6
+ * consumer unlayered styles always win over our layered rules.
7
+ *
8
+ * browser defaults
9
+ * ↓ @layer magi.reset
10
+ * ↓ @layer magi.tokens
11
+ * ↓ @layer magi.foundation
12
+ * ↓ @layer magi.layout
13
+ * ↓ @layer magi.components
14
+ * ↓ consumer unlayered styles (always win)
8
15
  */
9
16
 
17
+ @layer magi.reset, magi.tokens, magi.foundation, magi.layout, magi.components;
18
+
10
19
  @import "../tokens/index.css";
11
20
  @import "../foundation/index.css";
12
21
  @import "../layout/Container.css";