{
  "name": "LafLabs Web Design",
  "version": "2026.10.3",
  "updatedAt": "2026-10-07",
  "canonicalUrl": "https://www.laflabs.co/design/context.json",
  "instructions": [
    "Treat this bundle as the source of truth for LafLabs public web design work.",
    "Use only the guide, tokens, Skill, and references relevant to the requested work.",
    "Do not invent product claims, official assets, or unsupported components."
  ],
  "sourceUrls": {
    "guide": "https://www.laflabs.co/design/guide.md",
    "tokens": "https://www.laflabs.co/design/tokens.json",
    "skill": "https://www.laflabs.co/design/skill/SKILL.md",
    "archive": "https://www.laflabs.co/design/skill.zip"
  },
  "guide": "# LafLabs Web Design\n\nSystem version: 2026.10.3 · Updated: 2026-10-07\n\nUse this provider-neutral guide for LafLabs public websites and branded web surfaces. It does not redefine dense Admin workflows or unrelated third-party products.\n\nThe active system uses Paper and Ink surfaces, Primary Blue as its sole accent, square geometry, restrained motion, and equivalent Korean and English content. Preserve factual product content and official assets; never invent claims or substitute fake product imagery.\n\n## Core principles\n\n### Accessibility\n\nVerify keyboard access, contrast, names, and states together.\n\n- Every action must work by keyboard and show a visible focus indicator.\n- Give icon controls and groups names that explain their purpose.\n- Keep a 44px target area on small screens.\n- Communicate loading, empty, and error states in text.\n\n### Factual claims\n\nPublish only claims that can be verified.\n\n- Mention customers, metrics, product status, or hiring only when a source verifies it.\n- Mark unverified material unavailable or omit it.\n- Never fill an empty surface with invented numbers or examples.\n\n### Color\n\nUse Paper and Ink by default, with Primary Blue as the sole accent.\n\n- Reserve blue for key actions, selected states, and direction.\n- Route-era colors are legacy references, not defaults for new surfaces.\n- Never communicate state or meaning with color alone.\n\n### Iconography\n\nUse the Phosphor family consistently for new interface icons.\n\n- Choose a meaningful Phosphor icon instead of drawing decorative SVGs.\n- Give icon-only controls an accessible name.\n- Use the current 15px icon size inside a 34px compact control.\n\n### Brand identity\n\nKeep the official logo shape and proportions intact.\n\n- Use the official PNG asset; do not crop or redraw it.\n- Give the logo clear space and strong contrast against its surface.\n- Do not add shadows, outlines, or color effects to the logo.\n\n### Motion\n\nMotion explains entry, progress, and state changes only.\n\n- The Segmented Control uses the shared spring at stiffness 520 and damping 38.\n- Do not move layout position or padding on hover.\n- Under prefers-reduced-motion, show the final state immediately.\n\n### Shape\n\nUse zero-radius corners and one-pixel rules to reveal structure.\n\n- Keep controls, surfaces, and indicators square.\n- Prefer surface contrast and rules to card shadows.\n- Use circles only when the product meaning requires one.\n\n### Spacing and layout\n\nA 1280px shell and responsive gutter establish horizontal rhythm.\n\n- The current shell is min(1280px, calc(100% - 64px)).\n- Use --gutter for full-width sections instead of adding ad hoc inline space.\n- Stack complex layouts at 1080px and move to a one-column flow at 720px.\n- Keep generous vertical section space between 80px and 150px.\n\n### Typography\n\nSans carries meaning; Mono carries compact system information.\n\n- Pair Geist Sans with Pretendard to balance Korean and Latin text.\n- Keep large headings short and body measures easy to scan.\n- Do not introduce 9px text in new UI.\n- Check Korean line breaks so phrases remain intact.\n\n### Voice\n\nWrite briefly and concretely while preserving technical terms.\n\n- Do not expand an explanation when one sentence is enough.\n- Keep technical terms such as API and token, and preserve English identifiers.\n- Keep Korean and English equivalent without forcing identical word order.\n\n## Design tokens\n\nThe production shell is `min(1280px, calc(100% - 64px))`. Treat tokens marked legacy as reference values, not defaults for new surfaces.\n\n| Token | Group | Value | Status | Purpose |\n| --- | --- | --- | --- | --- |\n| `color.blue-grey` | color | `#8ba7d9` | Legacy reference | Legacy supporting copy and unavailable-state color. |\n| `color.blue-light` | color | `#60a5fa` | Current | Short highlights inside dark contrast bands. |\n| `color.blue-pale` | color | `#dbeafe` | Current | Large passive marks and supporting text on blue surfaces. |\n| `color.border-blue` | color | `#263d68` | Legacy reference | Legacy one-pixel rule color from the route-era interface. |\n| `color.border-blue-strong` | color | `#385a91` | Legacy reference | Legacy emphasized rule and outline-action border color. |\n| `color.button-ink` | color | `#0a0e18` | Legacy reference | Legacy text color for the light contact action. |\n| `color.error` | color | `#ef4444` | Current | Reserved for error and danger status. |\n| `color.error-deep` | color | `#b91c1c` | Current | High-contrast background for destructive actions with a white foreground. |\n| `color.info` | color | `#0ea5e9` | Current | Reserved for informational status. |\n| `color.ink` | color | `#0f172a` | Current | The default text, rule, and dark contrast-band color. |\n| `color.inverse-navy` | color | `#071022` | Legacy reference | Legacy contact-section surface from the route-era interface. |\n| `color.line` | color | `#cbd5e1` | Current | Quiet dividers and inactive outlines. |\n| `color.mask-black` | color | `#000` | Legacy reference | Legacy opaque mask stop, not a visible surface color. |\n| `color.muted` | color | `#64748b` | Current | Supporting copy and lower-priority metadata. |\n| `color.off-white` | color | `#f4f7fb` | Legacy reference | Legacy text and light-control color from the route-era interface. |\n| `color.page-navy` | color | `#0b1328` | Legacy reference | Legacy default page surface from the route-era interface. |\n| `color.paper` | color | `#f8fafc` | Current | The default page and control surface. |\n| `color.primary` | color | `#2563eb` | Current | The primary accent for key actions, selected states, and structure. |\n| `color.primary-deep` | color | `#1e40af` | Current | The hover and pressed color for Primary Blue actions. |\n| `color.pure-white` | color | `#fff` | Current | Foreground color on Ink, Primary Blue, and Error Deep surfaces. |\n| `color.raised-navy` | color | `#101c35` | Legacy reference | Legacy raised dark detail from the route-era interface. |\n| `color.route-blue` | color | `#165dff` | Legacy reference | Legacy fill and structural accent from the route-era interface. |\n| `color.route-blue-deep` | color | `#0f4bd8` | Legacy reference | Legacy primary-button hover color from the route-era interface. |\n| `color.route-blue-soft` | color | `#112b5d` | Legacy reference | Legacy quiet active surface from the route-era interface. |\n| `color.route-endpoint` | color | `#5e8fe8` | Legacy reference | Legacy route-endpoint stroke color. |\n| `color.route-line` | color | `#8fb6ff` | Legacy reference | Legacy route, metadata, and focus color. |\n| `color.slate-detail` | color | `#475569` | Current | Compact editorial detail on light surfaces. |\n| `color.slate-soft` | color | `#94a3b8` | Current | Metadata on dark contrast bands. |\n| `color.subtle-navy` | color | `#0e1931` | Legacy reference | Legacy alternating section surface from the route-era interface. |\n| `color.success` | color | `#10b981` | Current | Reserved for successful status. |\n| `color.warning` | color | `#f59e0b` | Current | Reserved for warning status. |\n| `layout.breakpoint-mobile` | layout | `720px` | Current | The small-screen breakpoint for collapsed navigation and one-column layout. |\n| `layout.breakpoint-stack` | layout | `1080px` | Current | The breakpoint where complex desktop arrangements begin to stack. |\n| `layout.compact-control` | layout | `34px` | Current | The desktop visual size for language and icon controls. |\n| `layout.gutter` | layout | `max(32px, calc((100vw - 1280px) / 2))` | Current | Responsive inline space for full-width sections. |\n| `layout.shell` | layout | `min(1280px, calc(100% - 64px))` | Current | The current public-shell maximum width and inline space. |\n| `motion.reduced` | motion | `0ms` | Current | State transitions complete immediately when reduced motion is requested. |\n| `motion.segmented-control` | motion | `spring(stiffness: 520, damping: 38)` | Current | The shared spring for the Segmented Control selection surface. |\n| `shape.radius` | shape | `0px` | Current | The default corner radius for controls, surfaces, and indicators. |\n| `shape.rule` | shape | `1px` | Current | The default rule width for sections, rows, and controls. |\n| `spacing.section-vertical` | spacing | `80px–150px` | Current | Responsive vertical section space, adjusted to content and viewport width. |\n| `typography.body-default` | typography | `16px` | Current | Default body size, with contextual sizes ranging from 14px to 17px. |\n| `typography.compact-title` | typography | `22px` | Current | Compact list and repository titles at weight 700. |\n| `typography.company-statement` | typography | `clamp(52px, 5.6vw, 72px)` | Current | Dark-band company statement at weight 700, line-height 1.04, and -0.04em tracking. |\n| `typography.family-mono` | typography | `Geist Mono, monospace` | Current | Reserved for status, indices, and technical metadata. |\n| `typography.family-sans` | typography | `Geist Sans, Pretendard, sans-serif` | Current | The default family stack for headings and body copy. |\n| `typography.hero-field-mark` | typography | `clamp(116px, 14vw, 210px)` | Current | The large homepage hero field mark only, at weight 850 and line-height 0.75. |\n| `typography.homepage-hero` | typography | `clamp(64px, 6.2vw, 80px)` | Current | Homepage proposition at weight 780, line-height 0.98, and -0.04em tracking. |\n| `typography.method-mark` | typography | `clamp(88px, 10.5vw, 154px)` | Current | Graphic ASK, BUILD, and RUN marks only, at weight 850 and line-height 0.75. |\n| `typography.mobile-company` | typography | `clamp(36px, 10.8vw, 44px)` | Current | Company statements on small screens. |\n| `typography.mobile-homepage-hero` | typography | `clamp(40px, 11.6vw, 48px)` | Current | The homepage proposition on small screens. |\n| `typography.mobile-method-mark` | typography | `clamp(94px, 33vw, 136px)` | Current | ASK, BUILD, and RUN marks on small screens. |\n| `typography.mobile-search-input` | typography | `clamp(30px, 9vw, 38px)` | Current | Search input on small screens. |\n| `typography.mobile-search-result` | typography | `clamp(18px, 5.6vw, 22px)` | Current | Search-result headings on small screens. |\n| `typography.mobile-section` | typography | `clamp(32px, 9.6vw, 40px)` | Current | Major section headings on small screens. |\n| `typography.mono-label` | typography | `10–11px` | Current | Indices, metadata, states, and compact navigation labels. |\n| `typography.panel-title` | typography | `clamp(27px, 2.5vw, 36px)` | Current | Titles inside bounded modules at weight 710 and line-height 1.08. |\n| `typography.search-input` | typography | `clamp(42px, 4.5vw, 64px)` | Current | Search-overlay input at weight 760 and line-height 1. |\n| `typography.search-result` | typography | `clamp(20px, 1.8vw, 26px)` | Current | Search-result headings at weight 720 and line-height 1.12. |\n| `typography.section-heading` | typography | `clamp(44px, 4.5vw, 60px)` | Current | Major section headings at weight 720, line-height 1.06, and -0.04em tracking. |\n| `typography.work-title` | typography | `clamp(32px, 3.4vw, 44px)` | Current | Selected-work titles at weight 720 and line-height 1. |\n\n## Components\n\n### Accordion (`accordion`)\n\nMaturity: **candidate** · Category: **disclosure**\n\nExpands and collapses longer content by heading.\n\n- Use: Use it for FAQs or supporting detail that need not be visible at once.\n- Avoid: Do not hide essential information or short primary copy by default.\n- Accessibility: Preserves real headings, buttons, aria-expanded, and arrow-key movement.\n- States: `closed` (fixture), `open` (fixture), `disabled` (fixture)\n- Related components: `tabs`, `separator`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n\n### Alert (`alert`)\n\nMaturity: **candidate** · Category: **feedback**\n\nExplains a persistent inline state and its next action.\n\n- Use: Use it when information, success, warning, or error must remain with the task.\n- Avoid: Use Toast for brief outcomes and Alert Dialog for decisions.\n- Accessibility: Labels the region from a visible title and reserves live for new urgent errors.\n- States: `info` (fixture), `warning` (fixture), `error` (fixture), `live` (fixture)\n- Related components: `toast`, `alert-dialog`, `button`\n- Dependencies: `@phosphor-icons/react`\n\n### Alert Dialog (`alert-dialog`)\n\nMaturity: **candidate** · Category: **overlay**\n\nRequests an explicit decision before a consequential action.\n\n- Use: Use it for immediate actions such as deletion or permission changes.\n- Avoid: Use Dialog or Alert for general information or reversible actions.\n- Accessibility: Requires cancel or action, ignores outside dismissal, and restores focus.\n- States: `closed` (fixture), `open` (interactive), `destructive` (interactive)\n- Related components: `dialog`, `alert`, `button`\n- Dependencies: `radix-ui`\n\n### Breadcrumb (`breadcrumb`)\n\nMaturity: **candidate** · Category: **navigation**\n\nShows where the current page sits in the information hierarchy.\n\n- Use: Use it in documents or admin views more than one level deep.\n- Avoid: Do not use it on a single-level page or as a progress indicator.\n- Accessibility: Uses a named nav, ordered list, current-page state, and hidden separators.\n- States: `default` (fixture), `collapsed` (fixture)\n- Related components: `text-link`, `dropdown-menu`\n- Dependencies: `@phosphor-icons/react`\n\n### Button (`button`)\n\nMaturity: **stable** · Category: **action**\n\nRuns an action in the current interface.\n\n- Use: Use it for immediate actions such as save, submit, and confirm.\n- Avoid: Use Button Link or Text Link for navigation.\n- Accessibility: Keep an action-specific name, expose busy and disabled states, and name icon buttons with aria-label.\n- States: `primary` (fixture), `secondary` (fixture), `outline` (fixture), `inverse` (fixture), `ghost` (fixture), `icon` (fixture), `disabled` (fixture), `loading` (fixture), `danger` (fixture)\n- Related components: `button-link`, `button-group`\n\n### Button Group (`button-group`)\n\nMaturity: **candidate** · Category: **action**\n\nComposes related actions and supporting parts in one connected frame.\n\n- Use: Use it for related actions, split actions, or an input paired with its action.\n- Avoid: Do not force unrelated actions or long explanations into one row.\n- Accessibility: Name the group while preserving a specific name for every control.\n- States: `horizontal` (fixture), `vertical` (fixture), `split` (fixture), `input` (fixture)\n- Related components: `button`, `button-link`, `dropdown-menu`, `input-group`\n\n### Button Link (`button-link`)\n\nMaturity: **stable** · Category: **action**\n\nUses Button's appearance while preserving a native anchor for navigation.\n\n- Use: Use it only when a prominent CTA navigates to another page or address.\n- Avoid: Use Button for in-place actions such as save, submit, or opening a dialog.\n- Accessibility: Do not replace it with Button; preserve native anchor semantics and a destination-specific name.\n- States: `primary` (fixture), `secondary` (fixture), `outline` (fixture), `inverse` (fixture), `ghost` (fixture), `icon` (fixture)\n- Related components: `button`, `text-link`\n\n### Checkbox (`checkbox`)\n\nMaturity: **candidate** · Category: **selection**\n\nTurns an independent selection on or off.\n\n- Use: Use it for independent consent, list, or multi-select values.\n- Avoid: Use Switch for a single setting that changes immediately.\n- Accessibility: Preserve the native checkbox and expose mixed state through aria-checked.\n- States: `unchecked` (fixture), `checked` (fixture), `indeterminate` (fixture), `disabled` (fixture)\n- Related components: `radio-group`, `switch`\n\n### Code Block (`code-block`)\n\nMaturity: **stable** · Category: **content**\n\nA readable code region with a language label and copy action.\n\n- Use: Use it to present multiline code or commands verbatim in documentation.\n- Avoid: Do not use it for short inline identifiers or as an executable editor.\n- Accessibility: The copy button names the language, and the source remains selectable after a copy failure.\n- States: `idle` (fixture), `copied` (interactive), `error` (environment)\n- Related components: `button`\n\n### Combobox (`combobox`)\n\nMaturity: **candidate** · Category: **form**\n\nSelects one value from a searchable list.\n\n- Use: Use it when the option list is long or labels may be unfamiliar.\n- Avoid: Use Native Select or Select for short, fixed option lists.\n- Accessibility: Exposes combobox/listbox relationships, active option, selection, and arrow-key operation.\n- States: `closed` (fixture), `open` (interactive), `empty` (interactive)\n- Related components: `field`, `select`, `input`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n\n### Data Table (`data-table`)\n\nMaturity: **candidate** · Category: **content**\n\nDisplays structured data with sorting and an explicit empty state.\n\n- Use: Use it for operational lists that people need to reorder by column.\n- Avoid: Use Table for static comparison and Item for editorial browsing.\n- Accessibility: Connects sort buttons with aria-sort while preserving real Table semantics.\n- States: `default` (fixture), `sorted` (interactive), `empty` (fixture)\n- Related components: `table`, `pagination`, `empty-state`\n- Dependencies: `@phosphor-icons/react`\n\n### Dialog (`dialog`)\n\nMaturity: **candidate** · Category: **overlay**\n\nOpens a focused, short task above the current flow.\n\n- Use: Use it for settings or a short form without leaving context.\n- Avoid: Do not use it for long documents or consequential decisions.\n- Accessibility: Preserves naming, focus trapping, Escape dismissal, and trigger focus restoration.\n- States: `closed` (fixture), `open` (interactive), `body-scroll` (interactive)\n- Related components: `alert-dialog`, `button`, `field`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n\n### Dropdown Menu (`dropdown-menu`)\n\nMaturity: **candidate** · Category: **navigation**\n\nOpens related commands and settings from one trigger.\n\n- Use: Use it to group related, secondary commands in one place.\n- Avoid: Do not hide primary actions or replace straightforward page navigation.\n- Accessibility: Preserves arrow keys, typeahead, Escape, submenus, and trigger focus restoration.\n- States: `default` (fixture), `open` (interactive), `disabled` (fixture)\n- Related components: `button`, `select`, `dialog`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n\n### Empty State (`empty-state`)\n\nMaturity: **candidate** · Category: **feedback**\n\nExplains why no content is present and what can happen next.\n\n- Use: Use it for a genuinely empty result, document, or collection.\n- Avoid: Do not invent example data or use it as a promotional card.\n- Accessibility: Make the state understandable from title and description, with recovery when available.\n- States: `default` (fixture), `action` (fixture)\n- Related components: `button`, `text-link`, `skeleton`\n\n### Field (`field`)\n\nMaturity: **candidate** · Category: **form**\n\nComposes labels, controls, descriptions, and errors into complete form sections with FieldGroup and FieldSet.\n\n- Use: Use Field for one control and FieldGroup with FieldSet for related form sections.\n- Avoid: Do not group read-only content or unrelated controls under one label.\n- Accessibility: Links nested FieldContent descriptions and errors to the control and names groups with FieldLegend.\n- States: `default` (fixture), `required` (fixture), `invalid` (fixture)\n- Related components: `label`, `input`, `textarea`, `native-select`\n\n### Input (`input`)\n\nMaturity: **candidate** · Category: **form**\n\nA native input for single-line values.\n\n- Use: Use it for single-line values such as email, title, or search.\n- Avoid: Use Textarea for multiline copy and Native Select for fixed choices.\n- Accessibility: Provide a name through Field or Label and choose the correct native type.\n- States: `default` (fixture), `focus-visible` (interactive), `invalid` (fixture), `disabled` (fixture)\n- Related components: `field`, `label`, `textarea`, `native-select`\n\n### Input Group (`input-group`)\n\nMaturity: **candidate** · Category: **form**\n\nGroups an input with a unit, prefix, or compact action.\n\n- Use: Use it for prefixes, units, or actions directly tied to an input.\n- Avoid: Do not place independent fields or several primary actions inside one boundary.\n- Accessibility: Keeps one native control in DOM order; the start and end aliases normalize to inline placements.\n- States: `default` (fixture), `focus-visible` (interactive), `invalid` (fixture)\n- Related components: `field`, `input`, `button`\n\n### Item (`item`)\n\nMaturity: **candidate** · Category: **structure**\n\nComposes media, copy, metadata, and actions into one row.\n\n- Use: Use it for repeated entities such as repositories, documents, or people without card grids.\n- Avoid: Use Table for column comparison and Panel for a standalone region.\n- Accessibility: Chooses article, div, or li for the surrounding structure and labels the item from its title.\n- States: `default` (fixture), `subtle` (fixture), `inverse` (fixture)\n- Related components: `panel`, `table`, `status-label`\n\n### Label (`label`)\n\nMaturity: **candidate** · Category: **form**\n\nProvides a concise name for a form control.\n\n- Use: Use it to explicitly name a native control outside Field.\n- Avoid: Do not use a label element for help text or decoration.\n- Accessibility: Keep htmlFor equal to the target control ID.\n- States: `default` (fixture), `required` (fixture)\n- Related components: `field`, `input`, `textarea`, `native-select`\n\n### Logo (`logo`)\n\nMaturity: **stable** · Category: **brand**\n\nDisplays the official symbol with the LafLabs wordmark.\n\n- Use: Use it where the LafLabs identity must be explicit, such as the site header and footer.\n- Avoid: Do not use it as a decorative background or repeating motif.\n- Accessibility: The component exposes the LafLabs name; check that an enclosing link does not create a redundant label.\n- States: `default` (fixture), `compact` (fixture)\n- Dependencies: `next`\n\n### Native Select (`native-select`)\n\nMaturity: **candidate** · Category: **form**\n\nA select that preserves native browser selection behavior.\n\n- Use: Use it to choose one value from a short, fixed list.\n- Avoid: Do not use it for long searchable lists or multi-selection.\n- Accessibility: Keep the native select as the only interactive element and hide its decorative icon.\n- States: `default` (fixture), `focus-visible` (interactive), `disabled` (fixture)\n- Related components: `field`, `label`, `input`\n- Dependencies: `@phosphor-icons/react`\n\n### Pagination (`pagination`)\n\nMaturity: **candidate** · Category: **navigation**\n\nNavigates a collection from one connected page rail.\n\n- Use: Use it when a collection has multiple URL-addressable pages.\n- Avoid: Do not use it for slides or in-page tabs.\n- Accessibility: Uses a named nav, real links, aria-current, and disabled boundaries.\n- States: `default` (fixture), `current` (fixture), `boundary` (fixture), `collapsed` (fixture)\n- Related components: `data-table`, `breadcrumb`, `text-link`\n- Dependencies: `@phosphor-icons/react`\n\n### Panel (`panel`)\n\nMaturity: **candidate** · Category: **structure**\n\nStructures related information and actions within one clear boundary.\n\n- Use: Use it when a settings group or summary module needs a genuine independent boundary.\n- Avoid: Do not wrap every section or list row, and do not nest Panels inside Panels.\n- Accessibility: Name independent regions with aria-label or aria-labelledby and keep heading levels consistent with the document.\n- States: `default` (fixture), `subtle` (fixture), `inverse` (fixture), `action` (fixture)\n- Related components: `separator`, `button`, `status-label`\n\n### Popover (`popover`)\n\nMaturity: **candidate** · Category: **overlay**\n\nOpens compact information or controls beside the current context.\n\n- Use: Use it for supporting tasks such as filters or compact settings.\n- Avoid: Use Dialog, Alert Dialog, or Dropdown Menu for long forms, confirmations, or command lists.\n- Accessibility: Names the supporting surface and preserves Escape dismissal and focus restoration.\n- States: `closed` (fixture), `open` (interactive)\n- Related components: `dropdown-menu`, `dialog`, `tooltip`\n- Dependencies: `radix-ui`\n\n### Progress (`progress`)\n\nMaturity: **candidate** · Category: **feedback**\n\nShows measurable completion or an indeterminate connection state.\n\n- Use: Use it for uploads, processing, or synchronization that takes time.\n- Avoid: Do not use it for instant actions or final success status.\n- Accessibility: Connects native progress with a visible label and never invents a numeric value.\n- States: `determinate` (fixture), `indeterminate` (fixture), `reduced-motion` (environment)\n- Related components: `spinner`, `skeleton`, `status-label`\n\n### Radio Group (`radio-group`)\n\nMaturity: **candidate** · Category: **selection**\n\nSelects exactly one value from a named group.\n\n- Use: Use it when a short list of options should stay visible for comparison.\n- Avoid: Use Native Select when space is tight or the list is long.\n- Accessibility: Keeps a named native radio set and communicates selection with square outer and inner indicators.\n- States: `default` (fixture), `selected` (fixture), `controlled` (interactive), `disabled` (fixture)\n- Related components: `checkbox`, `native-select`\n\n### Segmented Control (`segmented-control`)\n\nMaturity: **candidate** · Category: **selection**\n\nSelects one value from two or more short options.\n\n- Use: Use it to switch short peer values such as locale, view, or status.\n- Avoid: Use Radio Group or Select for verbose or numerous options.\n- Accessibility: Provides radiogroup and radio semantics, aria-checked, and arrow-key roving focus.\n- States: `default` (fixture), `three-options` (fixture), `focus-visible` (interactive), `selected` (fixture), `disabled` (fixture), `reduced-motion` (environment)\n- Related components: `radio-group`, `tabs`\n- Dependencies: `motion`\n\n### Select (`select`)\n\nMaturity: **candidate** · Category: **form**\n\nNavigates a longer option list by keyboard or pointer.\n\n- Use: Use it when options need richer states and controlled popup placement.\n- Avoid: Use Native Select for short lists or when the platform picker is preferable.\n- Accessibility: Provide a label and preserve arrow selection, disabled options, Escape dismissal, and focus return.\n- States: `default` (fixture), `open` (interactive), `disabled` (fixture)\n- Related components: `field`, `native-select`, `dropdown-menu`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n\n### Separator (`separator`)\n\nMaturity: **candidate** · Category: **structure**\n\nCreates a visual or semantic boundary between content.\n\n- Use: Use it when spacing alone cannot distinguish rows or sections.\n- Avoid: Do not box every element or repeat rules as decoration.\n- Accessibility: Hide it by default and expose a separator only when the boundary carries meaning.\n- States: `decorative` (fixture), `horizontal` (fixture), `vertical` (fixture)\n- Related components: `empty-state`\n\n### Side Panel (`side-panel`)\n\nMaturity: **candidate** · Category: **overlay**\n\nOpens a larger workspace from a viewport edge without leaving the page.\n\n- Use: Use it for settings, details, or editing that need more room than a Popover.\n- Avoid: Do not confine a primary page flow or complex multi-step task to a panel.\n- Accessibility: Preserves Dialog title, description, focus trap, Escape dismissal, and focus restoration.\n- States: `closed` (fixture), `open` (interactive)\n- Related components: `dialog`, `popover`, `panel`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n\n### Skeleton (`skeleton`)\n\nMaturity: **candidate** · Category: **feedback**\n\nReserves content structure while data is loading.\n\n- Use: Use it for brief loading when the final layout shape is known.\n- Avoid: Do not replace progress feedback or an empty state with a skeleton.\n- Accessibility: Always hide it from assistive technology and announce loading separately.\n- States: `loading` (fixture), `reduced-motion` (environment)\n- Related components: `empty-state`\n\n### Spinner (`spinner`)\n\nMaturity: **candidate** · Category: **feedback**\n\nSignals indeterminate progress as one gap travels around a stationary square perimeter.\n\n- Use: Use it inside a button or compact inline task.\n- Avoid: Use Progress for measurable work and Skeleton for page loading.\n- Accessibility: Provides a named status and hides the stationary square track as presentation.\n- States: `compact` (fixture), `default` (fixture), `reduced-motion` (environment)\n- Related components: `button`, `progress`, `skeleton`\n\n### Status Label (`status-label`)\n\nMaturity: **candidate** · Category: **feedback**\n\nShows a real entity state with a small color square and concise text.\n\n- Use: Use it for static document or media lifecycle metadata.\n- Avoid: Do not use it as an action, filter, long explanation, or live error.\n- Accessibility: Always provide explicit status text that remains clear without color.\n- States: `neutral` (fixture), `info` (fixture), `success` (fixture), `warning` (fixture), `error` (fixture)\n- Related components: `alert`, `panel`, `toast`\n\n### Switch (`switch`)\n\nMaturity: **candidate** · Category: **selection**\n\nTurns one immediately applied setting on or off.\n\n- Use: Use it for a binary setting that takes effect immediately.\n- Avoid: Use Checkbox when consent is only committed on form submission.\n- Accessibility: Preserves native checkbox behavior and a stable label; tone applies only to the checked surface.\n- States: `off` (fixture), `on` (fixture), `focus-visible` (interactive), `disabled` (fixture)\n- Related components: `checkbox`, `segmented-control`\n\n### Table (`table`)\n\nMaturity: **candidate** · Category: **content**\n\nPresents information that must be compared across native table rows and columns.\n\n- Use: Use it to compare the same attributes, such as status, name, or date, across records.\n- Avoid: Use Item for one record's details or a list whose sequence matters more than column comparison.\n- Accessibility: Preserves native caption, thead, tbody, and scoped header semantics.\n- States: `default` (fixture), `overflow` (environment)\n- Related components: `data-table`, `item`, `separator`\n\n### Tabs (`tabs`)\n\nMaturity: **candidate** · Category: **disclosure**\n\nSwitches between peer panels within one context.\n\n- Use: Use it for quickly switching between a few peer views.\n- Avoid: Do not use it for sequential steps or independent page navigation.\n- Accessibility: Preserves tablist, tab, tabpanel relationships and arrow-key roving focus.\n- States: `default` (fixture), `selected` (fixture), `disabled` (fixture)\n- Related components: `segmented-control`, `accordion`\n- Dependencies: `radix-ui`\n\n### Text Link (`text-link`)\n\nMaturity: **stable** · Category: **navigation**\n\nA reusable link that pairs text with an arrow toward the next destination.\n\n- Use: Use it at the end of a section or row for lightweight onward navigation.\n- Avoid: Do not use it for primary submission actions or icon-only controls.\n- Accessibility: The link text must identify its destination; treat the arrow as decorative.\n- States: `default` (fixture), `hover` (interactive), `focus-visible` (interactive), `visited` (interactive)\n- Related components: `button-link`\n- Dependencies: `@phosphor-icons/react`\n\n### Textarea (`textarea`)\n\nMaturity: **candidate** · Category: **form**\n\nAccepts longer multiline text.\n\n- Use: Use it for values that need line breaks, such as inquiries or summaries.\n- Avoid: Do not use it as a code editor or for single-line values.\n- Accessibility: Associate a visible label and expose length guidance as a description when needed.\n- States: `default` (fixture), `focus-visible` (interactive), `invalid` (fixture)\n- Related components: `field`, `label`, `input`\n\n### Toast (`toast`)\n\nMaturity: **candidate** · Category: **feedback**\n\nReports a brief result through one application-wide queue.\n\n- Use: Use it for brief save, upload, or undo outcomes.\n- Avoid: Use Alert or Alert Dialog for persistent errors or required decisions.\n- Accessibility: Announces routine results as status, errors as alert, and localizes dismissal.\n- States: `success` (interactive), `error` (interactive), `action` (interactive), `queued` (interactive), `persistent` (interactive)\n- Related components: `alert`, `status-label`, `spinner`\n- Dependencies: `radix-ui`\n\n### Tooltip (`tooltip`)\n\nMaturity: **candidate** · Category: **overlay**\n\nProvides a short supporting description on hover and focus.\n\n- Use: Use it to clarify controls whose visible name, such as an icon, is insufficient.\n- Avoid: Do not rely on it for essential information, long copy, or touch-only actions.\n- Accessibility: Opens on keyboard focus as well as hover and is associated as the trigger description.\n- States: `closed` (fixture), `open` (interactive)\n- Related components: `button`\n- Dependencies: `radix-ui`\n\n## Recipes\n\n### Collection state surface (`collection-state-surface`)\n\nCategory: **system-state**\n\nExplains loading, results, empty, and error states consistently in one collection surface.\n\n- Use: Use when a table or list waits for asynchronous data and has multiple outcomes.\n- Avoid: Do not use for immediate static content or one form-submission result.\n- Accessibility: Name the state and next action in text without announcing loading or errors twice.\n- Components: `panel`, `table`, `item`, `pagination`, `skeleton`, `empty-state`, `alert`, `status-label`, `button`\n- Related Patterns: `collection-row`, `system-states`, `responsive-collapse`\n- States: `loading` (fixture), `populated` (fixture), `empty` (fixture), `error` (fixture)\n- Responsive behavior:\n  - On small screens, keep essential comparisons and reflow the rest into Item rows.\n  - Never hide the state title or retry action behind horizontal overflow.\n\n```tsx\nimport {\n  Item,\n  ItemActions,\n  ItemContent,\n  ItemTitle,\n} from \"@/components/ui/item\"\nimport {\n  Pagination,\n  PaginationContent,\n  PaginationItem,\n  PaginationLink,\n} from \"@/components/ui/pagination\"\nimport { Panel, PanelContent, PanelHeader, PanelTitle } from \"@/components/ui/panel\"\nimport { StatusLabel } from \"@/components/ui/status-label\"\nimport { Table, TableBody, TableCell, TableRow } from \"@/components/ui/table\"\n\n<Panel aria-label=\"populated document collection\">\n  <PanelHeader>\n    <PanelTitle>Documents</PanelTitle>\n  </PanelHeader>\n  <PanelContent>\n    <Table>\n      <TableBody>\n        <TableRow>\n          <TableCell>Operations policy</TableCell>\n          <TableCell>\n            <StatusLabel tone=\"success\">Published</StatusLabel>\n          </TableCell>\n        </TableRow>\n      </TableBody>\n    </Table>\n    <Item>\n      <ItemContent>\n        <ItemTitle>Operations policy</ItemTitle>\n      </ItemContent>\n      <ItemActions>\n        <StatusLabel tone=\"success\">Published</StatusLabel>\n      </ItemActions>\n    </Item>\n    <Pagination aria-label=\"Document pages\">\n      <PaginationContent>\n        <PaginationItem>\n          <PaginationLink href=\"#\" isCurrent>1</PaginationLink>\n        </PaginationItem>\n      </PaginationContent>\n    </Pagination>\n  </PanelContent>\n</Panel>\n```\n\n### Document publishing toolbar (`document-publishing-toolbar`)\n\nCategory: **action**\n\nCombines document status, saving, and publishing into one predictable workflow.\n\n- Use: Use for document work with a clear order and priority, such as saving and publishing.\n- Avoid: Do not use for unrelated actions or a form with one simple submit action.\n- Accessibility: Expose status in text and preserve keyboard order across save, publish, and more options.\n- Components: `button-group`, `button`, `dropdown-menu`, `status-label`\n- Related Patterns: `document-surface`, `responsive-collapse`\n- States: `draft` (fixture), `publish-options` (interactive), `publishing` (fixture)\n- Responsive behavior:\n  - On small screens, place status above a full-width action group.\n  - Keep save, publish, and more-options order at every viewport size.\n\n```tsx\nimport { Button } from \"@/components/ui/button\"\nimport { ButtonGroup, ButtonGroupSeparator } from \"@/components/ui/button-group\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport { StatusLabel } from \"@/components/ui/status-label\"\n\n<div>\n  <StatusLabel tone=\"neutral\">Draft</StatusLabel>\n  <DropdownMenu>\n    <ButtonGroup label=\"Document publishing\">\n      <Button variant=\"secondary\">Save draft</Button>\n      <Button>Publish document</Button>\n      <ButtonGroupSeparator />\n      <DropdownMenuTrigger asChild>\n        <Button aria-label=\"Open publishing options\" size=\"icon\">...</Button>\n      </DropdownMenuTrigger>\n    </ButtonGroup>\n    <DropdownMenuContent align=\"end\">\n      <DropdownMenuItem>Schedule publication</DropdownMenuItem>\n      <DropdownMenuItem>Copy preview link</DropdownMenuItem>\n    </DropdownMenuContent>\n  </DropdownMenu>\n</div>\n```\n\n### Document settings form (`document-settings-form`)\n\nCategory: **form**\n\nConnects document metadata and publishing settings in one meaningful form structure.\n\n- Use: Use when editing related fields and immediately applied settings as one task.\n- Avoid: Do not group unrelated settings or use it as a read-only summary.\n- Accessibility: Name the task with fieldset and legend, and connect all guidance and errors to their fields.\n- Components: `field`, `input`, `native-select`, `checkbox`, `switch`, `alert`\n- Related Patterns: `document-surface`, `responsive-collapse`\n- States: `default` (fixture), `invalid` (fixture), `disabled` (fixture), `saving` (fixture)\n- Responsive behavior:\n  - On small screens, collapse horizontal fields into one label-then-input column.\n  - Keep descriptions and errors immediately below their related input.\n\n```tsx\nimport { Checkbox } from \"@/components/ui/checkbox\"\nimport {\n  Field,\n  FieldGroup,\n  FieldLabel,\n  FieldLegend,\n  FieldSet,\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport { NativeSelect } from \"@/components/ui/native-select\"\nimport { Switch } from \"@/components/ui/switch\"\n\n<FieldSet>\n  <FieldLegend>Document settings</FieldLegend>\n  <FieldGroup>\n    <Field>\n      <FieldLabel>Title</FieldLabel>\n      <Input />\n    </Field>\n    <Field>\n      <FieldLabel>Category</FieldLabel>\n      <NativeSelect defaultValue=\"notice\">\n        <option value=\"notice\">Notice</option>\n        <option value=\"disclosure\">Disclosure</option>\n      </NativeSelect>\n    </Field>\n    <Checkbox label=\"Pin document\" />\n    <Switch label=\"Publish immediately\" />\n  </FieldGroup>\n</FieldSet>\n```\n\n### Search and filter field (`search-filter-field`)\n\nCategory: **form**\n\nCombines a query and structured filters into one named discovery task.\n\n- Use: Use to search a document or record collection and narrow it with a small filter set.\n- Avoid: Do not use for a form field that selects one fixed value without search.\n- Accessibility: Connect label, description, and error to the query while preserving popup keyboard navigation.\n- Components: `field`, `input-group`, `combobox`, `alert`, `button`\n- Related Patterns: `collection-row`, `responsive-collapse`\n- States: `default` (fixture), `filters-open` (interactive), `empty` (fixture), `invalid` (fixture)\n- Responsive behavior:\n  - On small screens, move filters below the query as a full-width row.\n  - Keep the label and error associated with the same input after reflow.\n\n```tsx\nimport { Alert, AlertAction } from \"@/components/ui/alert\"\nimport { Button } from \"@/components/ui/button\"\nimport { Combobox } from \"@/components/ui/combobox\"\nimport { Field, FieldDescription, FieldLabel } from \"@/components/ui/field\"\nimport { InputGroup, InputGroupInput } from \"@/components/ui/input-group\"\n\nconst statusOptions = [\n  { value: \"all\", label: \"All statuses\" },\n  { value: \"draft\", label: \"Draft\" },\n  { value: \"published\", label: \"Published\" },\n]\n\n<div>\n  <Field>\n    <FieldLabel>Search documents</FieldLabel>\n    <FieldDescription>Search titles and content.</FieldDescription>\n    <InputGroup><InputGroupInput type=\"search\" /></InputGroup>\n  </Field>\n  <Field>\n    <FieldLabel>Filter by document status</FieldLabel>\n    <Combobox\n      defaultValue=\"all\"\n      emptyText=\"No matching status.\"\n      options={statusOptions}\n    />\n  </Field>\n  <Alert title=\"No documents match this search.\">\n    Clear the query or adjust the status filter.\n      <AlertAction>\n        <Button variant=\"secondary\">Clear search</Button>\n      </AlertAction>\n    </Alert>\n  </div>\n```\n\n## Composition and responsive patterns\n\n### Collection row (`collection-row`)\n\nA full-width row separated by space and one-pixel rules.\n\n- Keep rules and spacing between items instead of wrapping each item in a card.\n- Align name, description, and status or action to shared columns.\n- Do not animate padding on hover.\n- Related components: `button`, `separator`, `status-label`, `text-link`\n\n### Contrast band (`contrast-band`)\n\nA restrained Ink surface divides the flow of the light public theme.\n\n- Use a dark band only for a clear content shift, such as the company statement.\n- Use white for primary text and Blue Light for short highlights.\n- Do not restore legacy Page Navy as the default surface for new public pages.\n- Related components: `logo`, `button-link`, `text-link`\n\n### Document surface (`document-surface`)\n\nA shared shell and reading rhythm connect document indices and detail pages.\n\n- Keep body measure, heading levels, dates, and metadata placement consistent.\n- Use Code Block for multiline code and distinguish it from inline identifiers.\n- Use direct links between document indices and reading surfaces.\n- Related components: `field`, `code-block`, `panel`, `separator`, `text-link`\n\n### Editorial heading (`editorial-heading`)\n\nA short heading and only the necessary copy establish a section's purpose.\n\n- Do not stack an eyebrow, number, and subtitle by default.\n- Constrain heading and description measures separately to clarify hierarchy.\n- Add a Text Link only when the section needs an onward destination.\n- Related components: `text-link`\n\n### Responsive collapse (`responsive-collapse`)\n\nDesktop relationships become a one-column reading order on small screens.\n\n- Stack complex grids at 1080px and simplify navigation and actions at 720px.\n- Reorder the same content for reading instead of shrinking a desktop diagram.\n- Keep a 44px target area on small screens.\n- Related components: `button`, `button-group`, `field`, `segmented-control`\n\n### Selected work (`selected-work`)\n\nAn editorial module pairing a real image with verified project copy.\n\n- Use real images from public and never fabricate a product screen.\n- Show product status and destinations only when current data provides them.\n- Provide previous and next actions as named, keyboard-operable buttons.\n- Related components: `button`, `segmented-control`, `text-link`\n\n### Site chrome (`site-chrome`)\n\nThe existing Site Header and Footer frame every public surface.\n\n- Do not add a second fixed navbar inside a page.\n- Keep logo, locale, search, and document navigation in their established chrome positions.\n- Place page-local navigation inside the content shell.\n- Related components: `logo`, `segmented-control`, `button`, `text-link`\n\n### System states (`system-states`)\n\nLoading, empty, and error states share one visual and verbal grammar.\n\n- Name the state and the next available action in short copy.\n- Provide a retry action for errors when recovery is available.\n- Do not fill empty states with invented example data.\n- Related components: `alert`, `button`, `empty-state`, `panel`, `skeleton`, `status-label`, `text-link`\n\n## Public machine resources\n\n- AI context bundle: https://www.laflabs.co/design/context.json\n- Provider-neutral guide: https://www.laflabs.co/design/guide.md\n- Versioned tokens: https://www.laflabs.co/design/tokens.json\n- Skill entry point: https://www.laflabs.co/design/skill/SKILL.md\n- Skill foundations: https://www.laflabs.co/design/skill/references/foundations.md\n- Skill components: https://www.laflabs.co/design/skill/references/components.md\n- Skill patterns: https://www.laflabs.co/design/skill/references/patterns.md\n- Skill tokens: https://www.laflabs.co/design/skill/references/tokens.json\n- Skill archive: https://www.laflabs.co/design/skill.zip\n- Source repository: https://github.com/laflabs-inc/homepage\n",
  "tokens": {
    "name": "LafLabs Web Design",
    "version": "2026.10.3",
    "updatedAt": "2026-10-07",
    "canonicalPath": "/design",
    "locales": [
      "ko",
      "en"
    ],
    "tokens": [
      {
        "id": "color.blue-grey",
        "group": "color",
        "value": "#8ba7d9",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 보조 글자와 unavailable 상태에 쓰던 색입니다.",
          "en": "Legacy supporting copy and unavailable-state color."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.blue-light",
        "group": "color",
        "value": "#60a5fa",
        "cssVariable": null,
        "purpose": {
          "ko": "어두운 대비 구간에서 짧은 강조에 씁니다.",
          "en": "Short highlights inside dark contrast bands."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.blue-pale",
        "group": "color",
        "value": "#dbeafe",
        "cssVariable": null,
        "purpose": {
          "ko": "큰 비활성 마크와 파란 면의 보조 텍스트에 씁니다.",
          "en": "Large passive marks and supporting text on blue surfaces."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.border-blue",
        "group": "color",
        "value": "#263d68",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 기본 1px 선 색입니다.",
          "en": "Legacy one-pixel rule color from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.border-blue-strong",
        "group": "color",
        "value": "#385a91",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 강조 선과 outline 버튼에 쓰던 색입니다.",
          "en": "Legacy emphasized rule and outline-action border color."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.button-ink",
        "group": "color",
        "value": "#0a0e18",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 밝은 문의 버튼 글자색입니다.",
          "en": "Legacy text color for the light contact action."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.error",
        "group": "color",
        "value": "#ef4444",
        "cssVariable": "--error",
        "purpose": {
          "ko": "오류와 위험 상태에만 씁니다.",
          "en": "Reserved for error and danger status."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.error-deep",
        "group": "color",
        "value": "#b91c1c",
        "cssVariable": "--error-deep",
        "purpose": {
          "ko": "흰색 전경이 필요한 파괴적 동작의 배경색입니다.",
          "en": "High-contrast background for destructive actions with a white foreground."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.info",
        "group": "color",
        "value": "#0ea5e9",
        "cssVariable": "--info",
        "purpose": {
          "ko": "정보 상태에만 씁니다.",
          "en": "Reserved for informational status."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.ink",
        "group": "color",
        "value": "#0f172a",
        "cssVariable": "--ink",
        "purpose": {
          "ko": "기본 텍스트와 선, 어두운 대비 구간에 씁니다.",
          "en": "The default text, rule, and dark contrast-band color."
        },
        "contrast": {
          "ko": "Paper 위에서는 텍스트와 선에 쓰고 넓은 면에서는 흰색을 올립니다.",
          "en": "Use it for text and rules on Paper, or pair an Ink surface with white."
        },
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.inverse-navy",
        "group": "color",
        "value": "#071022",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 문의 구간 바탕색입니다.",
          "en": "Legacy contact-section surface from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.line",
        "group": "color",
        "value": "#cbd5e1",
        "cssVariable": "--line",
        "purpose": {
          "ko": "눈에 덜 띄는 구분선과 비활성 외곽선에 씁니다.",
          "en": "Quiet dividers and inactive outlines."
        },
        "contrast": {
          "ko": "정보를 색이나 선만으로 구분하지 않습니다.",
          "en": "Never rely on color or a rule alone to convey information."
        },
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.mask-black",
        "group": "color",
        "value": "#000",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 기술 목록 마스크의 불투명 지점이며 화면 색으로 쓰지 않습니다.",
          "en": "Legacy opaque mask stop, not a visible surface color."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.muted",
        "group": "color",
        "value": "#64748b",
        "cssVariable": "--muted",
        "purpose": {
          "ko": "보조 설명과 덜 중요한 메타데이터에 씁니다.",
          "en": "Supporting copy and lower-priority metadata."
        },
        "contrast": {
          "ko": "작은 글자나 어두운 바탕에는 사용하지 않습니다.",
          "en": "Do not use it for small text or on dark surfaces."
        },
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.off-white",
        "group": "color",
        "value": "#f4f7fb",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 기본 글자와 밝은 컨트롤 색입니다.",
          "en": "Legacy text and light-control color from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.page-navy",
        "group": "color",
        "value": "#0b1328",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 기본 바탕색입니다.",
          "en": "Legacy default page surface from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.paper",
        "group": "color",
        "value": "#f8fafc",
        "cssVariable": "--paper",
        "purpose": {
          "ko": "페이지와 기본 컨트롤의 바탕색입니다.",
          "en": "The default page and control surface."
        },
        "contrast": {
          "ko": "본문은 Ink, 보조 설명은 Muted를 사용합니다.",
          "en": "Use Ink for body copy and Muted for supporting copy."
        },
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.primary",
        "group": "color",
        "value": "#2563eb",
        "cssVariable": "--blue",
        "purpose": {
          "ko": "주요 동작과 선택 상태, 구조를 표시하는 기본 강조색입니다.",
          "en": "The primary accent for key actions, selected states, and structure."
        },
        "contrast": {
          "ko": "넓은 파란 면에는 흰색을 쓰고 작은 글자에는 대비를 다시 확인합니다.",
          "en": "Use white on broad blue surfaces and recheck contrast for small text."
        },
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.primary-deep",
        "group": "color",
        "value": "#1e40af",
        "cssVariable": "--deep",
        "purpose": {
          "ko": "Primary Blue 동작의 hover와 pressed 상태에 씁니다.",
          "en": "The hover and pressed color for Primary Blue actions."
        },
        "contrast": {
          "ko": "흰색 텍스트와 함께 사용합니다.",
          "en": "Pair it with white text."
        },
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.pure-white",
        "group": "color",
        "value": "#fff",
        "cssVariable": "--pure-white",
        "purpose": {
          "ko": "Ink, Primary Blue, Error Deep 위의 전경색입니다.",
          "en": "Foreground color on Ink, Primary Blue, and Error Deep surfaces."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.raised-navy",
        "group": "color",
        "value": "#101c35",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면에서 기본 배경보다 밝게 띄운 요소에 쓰던 색입니다.",
          "en": "Legacy raised dark detail from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.route-blue",
        "group": "color",
        "value": "#165dff",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 채운 버튼과 구조 강조에 쓰던 색입니다.",
          "en": "Legacy fill and structural accent from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.route-blue-deep",
        "group": "color",
        "value": "#0f4bd8",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 주요 버튼 hover 색입니다.",
          "en": "Legacy primary-button hover color from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.route-blue-soft",
        "group": "color",
        "value": "#112b5d",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면에서 눈에 덜 띄는 활성 배경입니다.",
          "en": "Legacy quiet active surface from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.route-endpoint",
        "group": "color",
        "value": "#5e8fe8",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 경로 끝점 선 색입니다.",
          "en": "Legacy route-endpoint stroke color."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.route-line",
        "group": "color",
        "value": "#8fb6ff",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면의 경로와 focus 표시 색입니다.",
          "en": "Legacy route, metadata, and focus color."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.slate-detail",
        "group": "color",
        "value": "#475569",
        "cssVariable": null,
        "purpose": {
          "ko": "밝은 바탕의 작은 편집 정보에 씁니다.",
          "en": "Compact editorial detail on light surfaces."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.slate-soft",
        "group": "color",
        "value": "#94a3b8",
        "cssVariable": null,
        "purpose": {
          "ko": "어두운 대비 구간의 메타데이터에 씁니다.",
          "en": "Metadata on dark contrast bands."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.subtle-navy",
        "group": "color",
        "value": "#0e1931",
        "cssVariable": null,
        "purpose": {
          "ko": "이전 route 화면에서 번갈아 배치한 구간의 바탕색입니다.",
          "en": "Legacy alternating section surface from the route-era interface."
        },
        "contrast": null,
        "legacy": true,
        "specimen": null
      },
      {
        "id": "color.success",
        "group": "color",
        "value": "#10b981",
        "cssVariable": "--success",
        "purpose": {
          "ko": "완료와 성공 상태에만 씁니다.",
          "en": "Reserved for successful status."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "color.warning",
        "group": "color",
        "value": "#f59e0b",
        "cssVariable": "--warning",
        "purpose": {
          "ko": "주의가 필요한 상태에만 씁니다.",
          "en": "Reserved for warning status."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "layout.breakpoint-mobile",
        "group": "layout",
        "value": "720px",
        "cssVariable": null,
        "purpose": {
          "ko": "탐색과 다단 구성을 한 열로 바꾸는 작은 화면 기준입니다.",
          "en": "The small-screen breakpoint for collapsed navigation and one-column layout."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "layout.breakpoint-stack",
        "group": "layout",
        "value": "1080px",
        "cssVariable": null,
        "purpose": {
          "ko": "복잡한 데스크톱 구성을 쌓기 시작하는 기준입니다.",
          "en": "The breakpoint where complex desktop arrangements begin to stack."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "layout.compact-control",
        "group": "layout",
        "value": "34px",
        "cssVariable": null,
        "purpose": {
          "ko": "데스크톱의 언어 선택과 아이콘 Button에 쓰는 시각 크기입니다.",
          "en": "The desktop visual size for language and icon controls."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "layout.gutter",
        "group": "layout",
        "value": "max(32px, calc((100vw - 1280px) / 2))",
        "cssVariable": "--gutter",
        "purpose": {
          "ko": "전체 폭 구간의 반응형 양쪽 여백입니다.",
          "en": "Responsive inline space for full-width sections."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "layout.shell",
        "group": "layout",
        "value": "min(1280px, calc(100% - 64px))",
        "cssVariable": "--shell",
        "purpose": {
          "ko": "현재 공개 화면의 최대 콘텐츠 폭과 양쪽 여백을 정합니다.",
          "en": "The current public-shell maximum width and inline space."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "motion.reduced",
        "group": "motion",
        "value": "0ms",
        "cssVariable": null,
        "purpose": {
          "ko": "reduced motion 환경에서는 상태 전환을 즉시 끝냅니다.",
          "en": "State transitions complete immediately when reduced motion is requested."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "motion.segmented-control",
        "group": "motion",
        "value": "spring(stiffness: 520, damping: 38)",
        "cssVariable": null,
        "purpose": {
          "ko": "Segmented Control의 선택 표시가 이동할 때 쓰는 공통 spring입니다.",
          "en": "The shared spring for the Segmented Control selection surface."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "shape.radius",
        "group": "shape",
        "value": "0px",
        "cssVariable": null,
        "purpose": {
          "ko": "컨트롤, 면, 표시 요소의 기본 모서리 값입니다.",
          "en": "The default corner radius for controls, surfaces, and indicators."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "shape.rule",
        "group": "shape",
        "value": "1px",
        "cssVariable": null,
        "purpose": {
          "ko": "구간과 목록, 컨트롤을 나누는 기본 선 두께입니다.",
          "en": "The default rule width for sections, rows, and controls."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "spacing.section-vertical",
        "group": "spacing",
        "value": "80px–150px",
        "cssVariable": null,
        "purpose": {
          "ko": "콘텐츠 양과 화면 폭에 따라 구간 위아래 여백을 조절합니다.",
          "en": "Responsive vertical section space, adjusted to content and viewport width."
        },
        "contrast": null,
        "legacy": false,
        "specimen": null
      },
      {
        "id": "typography.body-default",
        "group": "typography",
        "value": "16px",
        "cssVariable": null,
        "purpose": {
          "ko": "기본 본문 크기입니다. 문맥에 따라 14px에서 17px 사이를 사용합니다.",
          "en": "Default body size, with contextual sizes ranging from 14px to 17px."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "16px",
          "fontWeight": 400,
          "lineHeight": 1.7,
          "letterSpacing": "0em"
        }
      },
      {
        "id": "typography.compact-title",
        "group": "typography",
        "value": "22px",
        "cssVariable": null,
        "purpose": {
          "ko": "작은 목록과 저장소 제목에 씁니다. weight 700입니다.",
          "en": "Compact list and repository titles at weight 700."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "22px",
          "fontWeight": 700,
          "lineHeight": 1.2,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.company-statement",
        "group": "typography",
        "value": "clamp(52px, 5.6vw, 72px)",
        "cssVariable": null,
        "purpose": {
          "ko": "어두운 회사 소개 구간에 씁니다. weight 700, line-height 1.04, tracking -0.04em입니다.",
          "en": "Dark-band company statement at weight 700, line-height 1.04, and -0.04em tracking."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(52px, 5.6vw, 72px)",
          "fontWeight": 700,
          "lineHeight": 1.04,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.family-mono",
        "group": "typography",
        "value": "Geist Mono, monospace",
        "cssVariable": null,
        "purpose": {
          "ko": "상태, 인덱스, 기술 메타데이터에만 씁니다.",
          "en": "Reserved for status, indices, and technical metadata."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "mono",
          "fontSize": "11px",
          "fontWeight": 600,
          "lineHeight": 1.45,
          "letterSpacing": "0em"
        }
      },
      {
        "id": "typography.family-sans",
        "group": "typography",
        "value": "Geist Sans, Pretendard, sans-serif",
        "cssVariable": null,
        "purpose": {
          "ko": "제목과 본문에 쓰는 기본 글꼴 묶음입니다.",
          "en": "The default family stack for headings and body copy."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "16px",
          "fontWeight": 400,
          "lineHeight": 1.5,
          "letterSpacing": "0em"
        }
      },
      {
        "id": "typography.hero-field-mark",
        "group": "typography",
        "value": "clamp(116px, 14vw, 210px)",
        "cssVariable": null,
        "purpose": {
          "ko": "홈페이지 hero 영역의 큰 필드 마크에만 씁니다. weight 850, line-height 0.75입니다.",
          "en": "The large homepage hero field mark only, at weight 850 and line-height 0.75."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(116px, 14vw, 210px)",
          "fontWeight": 850,
          "lineHeight": 0.75,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.homepage-hero",
        "group": "typography",
        "value": "clamp(64px, 6.2vw, 80px)",
        "cssVariable": null,
        "purpose": {
          "ko": "홈페이지 핵심 문장에 씁니다. weight 780, line-height 0.98, tracking -0.04em입니다.",
          "en": "Homepage proposition at weight 780, line-height 0.98, and -0.04em tracking."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(64px, 6.2vw, 80px)",
          "fontWeight": 780,
          "lineHeight": 0.98,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.method-mark",
        "group": "typography",
        "value": "clamp(88px, 10.5vw, 154px)",
        "cssVariable": null,
        "purpose": {
          "ko": "ASK, BUILD, RUN 그래픽 문자에만 씁니다. weight 850, line-height 0.75입니다.",
          "en": "Graphic ASK, BUILD, and RUN marks only, at weight 850 and line-height 0.75."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(88px, 10.5vw, 154px)",
          "fontWeight": 850,
          "lineHeight": 0.75,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.mobile-company",
        "group": "typography",
        "value": "clamp(36px, 10.8vw, 44px)",
        "cssVariable": null,
        "purpose": {
          "ko": "작은 화면의 회사 소개 문장에 씁니다.",
          "en": "Company statements on small screens."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(36px, 10.8vw, 44px)",
          "fontWeight": 700,
          "lineHeight": 1.04,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.mobile-homepage-hero",
        "group": "typography",
        "value": "clamp(40px, 11.6vw, 48px)",
        "cssVariable": null,
        "purpose": {
          "ko": "작은 화면의 홈페이지 핵심 문장에 씁니다.",
          "en": "The homepage proposition on small screens."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(40px, 11.6vw, 48px)",
          "fontWeight": 780,
          "lineHeight": 0.98,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.mobile-method-mark",
        "group": "typography",
        "value": "clamp(94px, 33vw, 136px)",
        "cssVariable": null,
        "purpose": {
          "ko": "작은 화면의 ASK, BUILD, RUN 마크에 씁니다.",
          "en": "ASK, BUILD, and RUN marks on small screens."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(94px, 33vw, 136px)",
          "fontWeight": 850,
          "lineHeight": 0.75,
          "letterSpacing": "-0.08em"
        }
      },
      {
        "id": "typography.mobile-search-input",
        "group": "typography",
        "value": "clamp(30px, 9vw, 38px)",
        "cssVariable": null,
        "purpose": {
          "ko": "작은 화면의 검색 입력에 씁니다.",
          "en": "Search input on small screens."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(30px, 9vw, 38px)",
          "fontWeight": 760,
          "lineHeight": 1,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.mobile-search-result",
        "group": "typography",
        "value": "clamp(18px, 5.6vw, 22px)",
        "cssVariable": null,
        "purpose": {
          "ko": "작은 화면의 검색 결과 제목에 씁니다.",
          "en": "Search-result headings on small screens."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(18px, 5.6vw, 22px)",
          "fontWeight": 720,
          "lineHeight": 1.12,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.mobile-section",
        "group": "typography",
        "value": "clamp(32px, 9.6vw, 40px)",
        "cssVariable": null,
        "purpose": {
          "ko": "작은 화면의 주요 구간 제목에 씁니다.",
          "en": "Major section headings on small screens."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(32px, 9.6vw, 40px)",
          "fontWeight": 720,
          "lineHeight": 1.06,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.mono-label",
        "group": "typography",
        "value": "10–11px",
        "cssVariable": null,
        "purpose": {
          "ko": "인덱스, 메타데이터, 상태, 짧은 내비게이션 label에 씁니다.",
          "en": "Indices, metadata, states, and compact navigation labels."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "mono",
          "fontSize": "clamp(10px, 0.8vw, 11px)",
          "fontWeight": 600,
          "lineHeight": 1.45,
          "letterSpacing": "0em"
        }
      },
      {
        "id": "typography.panel-title",
        "group": "typography",
        "value": "clamp(27px, 2.5vw, 36px)",
        "cssVariable": null,
        "purpose": {
          "ko": "경계가 있는 모듈의 제목에 씁니다. weight 710, line-height 1.08입니다.",
          "en": "Titles inside bounded modules at weight 710 and line-height 1.08."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(27px, 2.5vw, 36px)",
          "fontWeight": 710,
          "lineHeight": 1.08,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.search-input",
        "group": "typography",
        "value": "clamp(42px, 4.5vw, 64px)",
        "cssVariable": null,
        "purpose": {
          "ko": "검색 overlay 입력에 씁니다. weight 760, line-height 1입니다.",
          "en": "Search-overlay input at weight 760 and line-height 1."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(42px, 4.5vw, 64px)",
          "fontWeight": 760,
          "lineHeight": 1,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.search-result",
        "group": "typography",
        "value": "clamp(20px, 1.8vw, 26px)",
        "cssVariable": null,
        "purpose": {
          "ko": "검색 결과 제목에 씁니다. weight 720, line-height 1.12입니다.",
          "en": "Search-result headings at weight 720 and line-height 1.12."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(20px, 1.8vw, 26px)",
          "fontWeight": 720,
          "lineHeight": 1.12,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.section-heading",
        "group": "typography",
        "value": "clamp(44px, 4.5vw, 60px)",
        "cssVariable": null,
        "purpose": {
          "ko": "주요 구간 제목에 씁니다. weight 720, line-height 1.06, tracking -0.04em입니다.",
          "en": "Major section headings at weight 720, line-height 1.06, and -0.04em tracking."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(44px, 4.5vw, 60px)",
          "fontWeight": 720,
          "lineHeight": 1.06,
          "letterSpacing": "-0.04em"
        }
      },
      {
        "id": "typography.work-title",
        "group": "typography",
        "value": "clamp(32px, 3.4vw, 44px)",
        "cssVariable": null,
        "purpose": {
          "ko": "선택한 작업의 제목에 씁니다. weight 720, line-height 1입니다.",
          "en": "Selected-work titles at weight 720 and line-height 1."
        },
        "contrast": null,
        "legacy": false,
        "specimen": {
          "fontFamily": "sans",
          "fontSize": "clamp(32px, 3.4vw, 44px)",
          "fontWeight": 720,
          "lineHeight": 1,
          "letterSpacing": "-0.04em"
        }
      }
    ]
  },
  "skill": {
    "entry": "---\nname: laflabs-web-design\ndescription: Apply LafLabs public web branding when creating or modifying LafLabs websites and branded web surfaces. Do not use for backend-only work, unrelated third-party products, or dense Admin workflows unless the user explicitly requests the public brand.\n---\n\n# LafLabs Web Design\n\nUse the LafLabs public design language without inventing product facts, assets, or component availability.\n\n## Essential constraints\n\n- Preserve official assets, Paper and Ink surfaces, Primary Blue as the sole accent, square geometry, and visible one-pixel rules.\n- Keep Korean and English content equivalent, with natural line breaks in both locales.\n- Reuse installed LafLabs components when their contracts fit; do not imitate them with lookalikes.\n- Keep every action keyboard-accessible, visibly focused, and understandable without color alone.\n- Honor reduced motion and show a complete static state.\n- Publish only verified claims. Omit or mark unavailable anything the target repository cannot support.\n\n## Workflow\n\n1. Inspect the target repository, its real components, official assets, and factual product content.\n2. Read only the references relevant to the requested work.\n3. Choose a published Recipe before composing a common documented task; preserve its declared component semantics and task order.\n4. Reuse supported components and tokens when available; preserve the target repository's established architecture.\n5. Verify desktop and mobile layout, visible copy, keyboard access, focus, and reduced motion before completion.\n\n## References\n\n- Read [references/foundations.md](references/foundations.md) for identity, color, typography, layout, accessibility, motion, voice, and claims.\n- Read [references/components.md](references/components.md) when selecting or using LafLabs interface components.\n- Read [references/patterns.md](references/patterns.md) when composing page sections or responsive structures.\n- Read [references/tokens.json](references/tokens.json) when exact semantic values are required.\n",
    "references": {
      "foundations": "# Foundations\n\nLafLabs Web Design 2026.10.3. English rules are paired with focused Korean copy guidance.\n\n## Accessibility (`accessibility`)\n\nVerify keyboard access, contrast, names, and states together. / 키보드, 대비, 이름, 상태를 함께 확인합니다.\n\n- Every action must work by keyboard and show a visible focus indicator. / 모든 동작 요소는 키보드로 쓸 수 있어야 하며 focus 표시가 보여야 합니다.\n- Give icon controls and groups names that explain their purpose. / 아이콘 컨트롤과 그룹에는 용도를 알 수 있는 이름을 제공합니다.\n- Keep a 44px target area on small screens. / 작은 화면의 조작 영역은 44px를 확보합니다.\n- Communicate loading, empty, and error states in text. / loading, empty, error 상태를 글로도 알립니다.\n\n## Factual claims (`claims`)\n\nPublish only claims that can be verified. / 출처로 확인한 사실만 공개 문서에 씁니다.\n\n- Mention customers, metrics, product status, or hiring only when a source verifies it. / 고객, 지표, 제품 상태, 채용 정보는 출처를 확인한 뒤에만 씁니다.\n- Mark unverified material unavailable or omit it. / 확인하지 못한 내용은 unavailable로 표시하거나 문서에서 뺍니다.\n- Never fill an empty surface with invented numbers or examples. / 빈 화면을 그럴듯한 수치나 사례로 채우지 않습니다.\n\n## Color (`color`)\n\nUse Paper and Ink by default, with Primary Blue as the sole accent. / Paper와 Ink를 기본으로 두고 Primary Blue만 강조색으로 씁니다.\n\n- Reserve blue for key actions, selected states, and direction. / 파란색은 주요 동작, 선택 상태, 진행 방향에만 사용합니다.\n- Route-era colors are legacy references, not defaults for new surfaces. / 이전 route 색상은 legacy 참고값이며 새 화면의 기본색으로 쓰지 않습니다.\n- Never communicate state or meaning with color alone. / 상태나 의미를 색 하나로만 전달하지 않습니다.\n\n## Iconography (`iconography`)\n\nUse the Phosphor family consistently for new interface icons. / 새 인터페이스 아이콘은 Phosphor 한 세트로 맞춥니다.\n\n- Choose a meaningful Phosphor icon instead of drawing decorative SVGs. / 장식용 SVG를 직접 그리지 말고 의미가 맞는 Phosphor 아이콘을 고릅니다.\n- Give icon-only controls an accessible name. / 아이콘만 있는 컨트롤에는 접근성 이름을 제공합니다.\n- Use the current 15px icon size inside a 34px compact control. / 34px compact control 안의 아이콘은 현재 기준인 15px로 맞춥니다.\n\n## Brand identity (`identity`)\n\nKeep the official logo shape and proportions intact. / 공식 로고의 형태와 비율을 그대로 유지합니다.\n\n- Use the official PNG asset; do not crop or redraw it. / 공식 PNG 에셋을 사용하고 자르거나 다시 그리지 않습니다.\n- Give the logo clear space and strong contrast against its surface. / 로고 둘레에 충분한 여백을 두고 바탕과 선명하게 구분합니다.\n- Do not add shadows, outlines, or color effects to the logo. / 로고에 그림자, 윤곽선, 색 효과를 더하지 않습니다.\n\n## Motion (`motion`)\n\nMotion explains entry, progress, and state changes only. / 모션은 진입, 진행, 상태 변화만 설명합니다.\n\n- The Segmented Control uses the shared spring at stiffness 520 and damping 38. / Segmented Control은 stiffness 520, damping 38의 공통 spring을 씁니다.\n- Do not move layout position or padding on hover. / hover에서 레이아웃 위치나 padding을 움직이지 않습니다.\n- Under prefers-reduced-motion, show the final state immediately. / prefers-reduced-motion에서는 최종 상태를 즉시 보여줍니다.\n\n## Shape (`shape`)\n\nUse zero-radius corners and one-pixel rules to reveal structure. / 0px 모서리와 1px 선으로 구조를 드러냅니다.\n\n- Keep controls, surfaces, and indicators square. / 컨트롤, 면, 표시 요소는 사각형으로 만듭니다.\n- Prefer surface contrast and rules to card shadows. / 카드 그림자보다 면의 대비와 선을 먼저 사용합니다.\n- Use circles only when the product meaning requires one. / 원은 제품 의미가 분명할 때만 사용합니다.\n\n## Spacing and layout (`spacing-layout`)\n\nA 1280px shell and responsive gutter establish horizontal rhythm. / 1280px shell과 반응형 gutter로 수평 리듬을 맞춥니다.\n\n- The current shell is min(1280px, calc(100% - 64px)). / 기본 shell은 min(1280px, calc(100% - 64px))입니다.\n- Use --gutter for full-width sections instead of adding ad hoc inline space. / 전체 폭 구간은 --gutter를 사용하고 임의의 양쪽 여백을 더하지 않습니다.\n- Stack complex layouts at 1080px and move to a one-column flow at 720px. / 1080px에서 복잡한 구성을 쌓고 720px에서 한 열 흐름으로 정리합니다.\n- Keep generous vertical section space between 80px and 150px. / 구간 위아래에는 80px에서 150px 사이의 넉넉한 여백을 둡니다.\n\n## Typography (`typography`)\n\nSans carries meaning; Mono carries compact system information. / Sans는 내용을, Mono는 짧은 시스템 정보를 맡습니다.\n\n- Pair Geist Sans with Pretendard to balance Korean and Latin text. / Geist Sans에 Pretendard를 이어 한글과 영문 밀도를 맞춥니다.\n- Keep large headings short and body measures easy to scan. / 큰 제목은 짧게 쓰고 본문 폭은 한눈에 읽을 수 있게 제한합니다.\n- Do not introduce 9px text in new UI. / 새 UI에서 9px 글자를 사용하지 않습니다.\n- Check Korean line breaks so phrases remain intact. / 한글 문장은 의미 단위가 깨지지 않도록 줄바꿈을 확인합니다.\n\n## Voice (`voice`)\n\nWrite briefly and concretely while preserving technical terms. / 짧고 구체적으로 쓰며 기술 용어는 원형을 유지합니다.\n\n- Do not expand an explanation when one sentence is enough. / 한 문장으로 충분한 설명은 늘리지 않습니다.\n- Keep technical terms such as API and token, and preserve English identifiers. / API, token 같은 기술 용어와 영어 식별자는 그대로 둡니다.\n- Keep Korean and English equivalent without forcing identical word order. / 한글과 영문은 같은 정보를 담되 문장 순서를 억지로 맞추지 않습니다.\n\n## Official public assets\n\n### Official logo (`official-logo`)\n\n- URL: https://www.laflabs.co/laflabs-logo.png\n- Format: PNG · 460 × 460 px\n- Use: Use at its original proportions wherever the LafLabs logo is required on a public surface. / LafLabs 로고가 필요한 공개 화면에서 원본 비율로 사용합니다.\n\n### System loop motion (`system-loop-mp4`)\n\n- URL: https://www.laflabs.co/laf-system-loop.mp4\n- Format: MP4 · 1080 × 1080 px\n- Use: Use as the MP4 fallback source for the System loop. / System loop의 MP4 대체 소스로 사용합니다.\n\n### System loop poster (`system-loop-poster`)\n\n- URL: https://www.laflabs.co/laf-system-loop-poster.png\n- Format: PNG · 1080 × 1080 px\n- Use: Use as the poster before the System loop video plays or when it remains still. / System loop 영상이 재생되기 전이나 정지 상태일 때 표시합니다.\n\n### System loop motion (`system-loop-webm`)\n\n- URL: https://www.laflabs.co/laf-system-loop.webm\n- Format: WebM · 1080 × 1080 px\n- Use: Use as the WebM source for the System loop in supporting browsers. / 지원하는 브라우저에서 System loop의 WebM 소스로 사용합니다.\n\nIf an official asset is unavailable in the target project, report that limitation instead of recreating it.\n",
      "components": "# Components\n\nLafLabs Web Design 2026.10.3. A stable component has a supported public contract; a candidate API can change.\n\n## Accordion (`accordion`)\n\n- Maturity: **candidate**\n- Category: **disclosure**\n- Purpose: Expands and collapses longer content by heading. / 긴 설명을 제목 단위로 펼치고 접습니다.\n- Use: Use it for FAQs or supporting detail that need not be visible at once. / 모든 내용을 동시에 볼 필요가 없는 FAQ나 보조 설명에 씁니다.\n- Avoid: Do not hide essential information or short primary copy by default. / 핵심 정보나 짧은 본문을 기본으로 숨기지 않습니다.\n- Accessibility: Preserves real headings, buttons, aria-expanded, and arrow-key movement. / 실제 heading과 button, aria-expanded 관계 및 방향키 이동을 유지합니다.\n- Related components: `tabs`, `separator`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n- States and inspection:\n  - `closed` [fixture]: Confirm the heading predicts the hidden content. / 제목만으로 숨은 내용을 예측할 수 있는지 확인합니다.\n  - `open` [fixture]: Confirm expanded state and caret direction change together. / 확장 상태와 캐럿 방향이 함께 바뀌는지 확인합니다.\n  - `disabled` [fixture]: Confirm disabled items are removed from the focus sequence. / 비활성 항목이 초점 순서에서 제외되는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | `\"single\" \\| \"multiple\"` | Yes | Controls whether one or many items may be open. / 동시에 열 수 있는 항목 수를 정합니다. |\n| `collapsible` | `boolean` | No | Allows all items to close in single mode. / single 모드에서 모두 닫을 수 있게 합니다. |\n| `value` | `string \\| string[]` | No | The controlled open item value. / 제어되는 열린 항목 값입니다. |\n\n### Usage shape\n\n```tsx\n<Accordion type=\"single\" collapsible>\n  <AccordionItem value=\"one\">\n    <AccordionTrigger>Question</AccordionTrigger>\n    <AccordionContent>Answer</AccordionContent>\n  </AccordionItem>\n</Accordion>\n```\n\n## Alert (`alert`)\n\n- Maturity: **candidate**\n- Category: **feedback**\n- Purpose: Explains a persistent inline state and its next action. / 본문 흐름 안에 계속 남아 있는 상태와 다음 행동을 설명합니다.\n- Use: Use it when information, success, warning, or error must remain with the task. / 정보, 성공, 주의, 오류가 다음 작업과 함께 남아야 할 때 씁니다.\n- Avoid: Use Toast for brief outcomes and Alert Dialog for decisions. / 짧게 끝난 결과나 명시적 결정에는 Toast나 Alert Dialog를 씁니다.\n- Accessibility: Labels the region from a visible title and reserves live for new urgent errors. / 보이는 제목으로 영역을 이름 붙이고 새 긴급 오류에만 live를 사용합니다.\n- Related components: `toast`, `alert-dialog`, `button`\n- Dependencies: `@phosphor-icons/react`\n- States and inspection:\n  - `info` [fixture]: Distinguish information with the left status signal and title. / 왼쪽 상태 신호와 제목으로 정보를 구분합니다.\n  - `warning` [fixture]: State the caution and next action concretely. / 주의 상태와 다음 행동을 구체적으로 적습니다.\n  - `error` [fixture]: Provide the error reason and an available recovery action. / 오류 원인과 가능한 복구 동작을 함께 제공합니다.\n  - `live` [fixture]: Announce only a newly created urgent state as an alert. / 새 긴급 상태만 alert로 발표합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `title` | `ReactNode` | No | Compatibility shorthand for a visible title. / 기존 사용법을 위한 단축 제목입니다. |\n| `variant` | `\"info\" \\| \"success\" \\| \"warning\" \\| \"error\"` | No | Sets the feedback meaning. / 상태의 의미입니다. |\n| `live` | `boolean` | No | Announces a newly rendered urgent state. / 새 긴급 상태를 즉시 발표합니다. |\n\n### Usage shape\n\n```tsx\n<Alert variant=\"error\">\n  <AlertContent>\n    <AlertTitle>Save failed</AlertTitle>\n    <AlertDescription>Review the title.</AlertDescription>\n  </AlertContent>\n  <AlertAction>Retry</AlertAction>\n</Alert>\n```\n\n## Alert Dialog (`alert-dialog`)\n\n- Maturity: **candidate**\n- Category: **overlay**\n- Purpose: Requests an explicit decision before a consequential action. / 되돌리기 어려운 행동 전에 명시적인 결정을 받습니다.\n- Use: Use it for immediate actions such as deletion or permission changes. / 삭제나 권한 변경처럼 결과가 즉시 적용되는 행동에 씁니다.\n- Avoid: Use Dialog or Alert for general information or reversible actions. / 일반 안내나 쉽게 되돌릴 수 있는 행동에는 Dialog나 Alert를 씁니다.\n- Accessibility: Requires cancel or action, ignores outside dismissal, and restores focus. / 바깥 클릭으로 닫지 않고 취소와 실행을 명확히 제공하며 초점을 복귀합니다.\n- Related components: `dialog`, `alert`, `button`\n- Dependencies: `radix-ui`\n- States and inspection:\n  - `closed` [fixture]: Confirm the trigger names the consequence. / 트리거가 결과를 구체적으로 설명하는지 확인합니다.\n  - `open` [interactive]: Inspect action hierarchy, initial focus, and focus restoration. / 취소와 실행의 위계, 초기 초점과 초점 복귀를 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `destructive` [interactive]: Use Error Deep with a white foreground for a destructive action. / 위험 동작은 Error Deep 면과 흰색 글자를 사용합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `variant` | `\"primary\" \\| \"destructive\"` | No | Sets the confirmation action intent. / 확인 동작의 의미입니다. |\n| `children` | `ReactNode` | No | Composes Header, Body, and Footer. / Header, Body와 Footer를 조합합니다. |\n\n### Usage shape\n\n```tsx\n<AlertDialog>\n  <AlertDialogContent>\n    <AlertDialogBody>This cannot be undone.</AlertDialogBody>\n    <AlertDialogCancel>Cancel</AlertDialogCancel>\n    <AlertDialogAction variant=\"destructive\">Archive</AlertDialogAction>\n  </AlertDialogContent>\n</AlertDialog>\n```\n\n## Breadcrumb (`breadcrumb`)\n\n- Maturity: **candidate**\n- Category: **navigation**\n- Purpose: Shows where the current page sits in the information hierarchy. / 현재 페이지가 정보 구조에서 어디에 있는지 보여줍니다.\n- Use: Use it in documents or admin views more than one level deep. / 두 단계 이상 깊은 문서나 관리 화면에서 상위 경로를 제공할 때 씁니다.\n- Avoid: Do not use it on a single-level page or as a progress indicator. / 단일 단계 페이지나 진행 단계를 설명하는 용도로 쓰지 않습니다.\n- Accessibility: Uses a named nav, ordered list, current-page state, and hidden separators. / 이름 있는 nav, 순서 목록, 현재 페이지와 숨겨진 구분자를 사용합니다.\n- Related components: `text-link`, `dropdown-menu`\n- Dependencies: `@phosphor-icons/react`\n- States and inspection:\n  - `default` [fixture]: Distinguish the current page from navigable ancestors. / 현재 페이지와 이동 가능한 상위 경로를 구분합니다.\n  - `collapsed` [fixture]: Collapse long intermediate paths with a named Ellipsis. / 긴 중간 경로는 이름 있는 Ellipsis로 축약합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `aria-label` | `string` | No | A name that distinguishes this navigation region. / 여러 탐색 영역을 구분하는 이름입니다. |\n| `label` | `string` | Yes | The accessible name for BreadcrumbEllipsis. / BreadcrumbEllipsis의 접근 가능한 이름입니다. |\n\n### Usage shape\n\n```tsx\n<Breadcrumb>\n  <BreadcrumbList>\n    <BreadcrumbItem>\n      <BreadcrumbLink href=\"/\">Home</BreadcrumbLink>\n    </BreadcrumbItem>\n    <BreadcrumbSeparator />\n    <BreadcrumbItem>\n      <BreadcrumbPage>Design</BreadcrumbPage>\n    </BreadcrumbItem>\n  </BreadcrumbList>\n</Breadcrumb>\n```\n\n## Button (`button`)\n\n- Maturity: **stable**\n- Category: **action**\n- Purpose: Runs an action in the current interface. / 현재 화면에서 동작을 실행합니다.\n- Use: Use it for immediate actions such as save, submit, and confirm. / 저장, 제출, 확인처럼 즉시 실행되는 동작에 씁니다.\n- Avoid: Use Button Link or Text Link for navigation. / 다른 주소로 이동할 때는 Button Link나 Text Link를 씁니다.\n- Accessibility: Keep an action-specific name, expose busy and disabled states, and name icon buttons with aria-label. / 동작을 설명하는 이름을 유지하고 busy와 disabled 상태를 함께 알립니다. 아이콘 버튼에는 aria-label이 필요합니다.\n- Related components: `button-link`, `button-group`\n- States and inspection:\n  - `primary` [fixture]: Reserve the blue surface for the most important action in a view. / 한 화면의 가장 중요한 동작에만 파란 면을 씁니다.\n  - `secondary` [fixture]: Render secondary actions with a Paper surface and one-pixel rule. / 보조 동작은 Paper 면과 1px 선으로 표시합니다.\n  - `outline` [fixture]: Use an Ink outline to distinguish an action without a filled surface. / 채운 면 없이 Ink 경계로 동작을 분명히 구분합니다.\n  - `inverse` [fixture]: Confirm the boundary and label remain clear on dark surfaces. / 어두운 면 위에서 경계와 이름이 선명한지 확인합니다.\n  - `ghost` [fixture]: Keep the target and focus indicator even at low visual emphasis. / 시각적 무게가 낮아도 조작 영역과 초점 표시는 유지합니다.\n  - `icon` [fixture]: For icon-only controls, verify the accessible name and 44px mobile target. / 아이콘만 보일 때 접근성 이름과 모바일 44px 조작 영역을 확인합니다.\n  - `disabled` [fixture]: Confirm the disabled action cannot run. / 비활성 상태에서 실행되지 않는지 확인합니다.\n  - `loading` [fixture]: Confirm busy state is exposed without replacing the label. / 이름을 유지하면서 busy 상태를 알리는지 확인합니다.\n  - `danger` [fixture]: Use Error Deep with a white foreground only for destructive actions. / 파괴적 동작에만 Error Deep과 흰색 전경을 씁니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `variant` | `\"primary\" \\| \"secondary\" \\| \"outline\" \\| \"inverse\" \\| \"danger\" \\| \"ghost\"` | No | Sets action hierarchy and semantics. / 동작의 위계와 의미를 정합니다. |\n| `size` | `\"compact\" \\| \"default\" \\| \"icon\"` | No | Sets control density, including the icon-only size. / 컨트롤 밀도와 아이콘 전용 크기를 정합니다. |\n| `loading` | `boolean` | No | Prevents duplicate activation and exposes busy state. / 중복 실행을 막고 busy 상태를 알립니다. |\n| `type` | `\"button\" \\| \"submit\" \\| \"reset\"` | No | Defaults to button. / 기본값은 button입니다. |\n| `children` | `ReactNode` | Yes | The action label or icon. / 동작 이름 또는 아이콘입니다. |\n\n### Usage shape\n\n```tsx\n<Button type=\"submit\">Save</Button>\n```\n\n## Button Group (`button-group`)\n\n- Maturity: **candidate**\n- Category: **action**\n- Purpose: Composes related actions and supporting parts in one connected frame. / 관련 동작과 보조 요소를 하나의 연결된 틀로 묶습니다.\n- Use: Use it for related actions, split actions, or an input paired with its action. / 저장과 발행, 분할 동작, 입력과 실행처럼 같은 맥락의 요소를 묶을 때 씁니다.\n- Avoid: Do not force unrelated actions or long explanations into one row. / 서로 무관한 동작이나 긴 설명을 한 줄에 억지로 넣지 않습니다.\n- Accessibility: Name the group while preserving a specific name for every control. / 그룹 이름으로 관계를 알리고 각 컨트롤의 고유 이름도 유지합니다.\n- Related components: `button`, `button-link`, `dropdown-menu`, `input-group`\n- States and inspection:\n  - `horizontal` [fixture]: Check adjacent one-pixel borders read as one structure. / 인접 요소의 1px 선이 하나의 구조로 읽히는지 확인합니다.\n  - `vertical` [fixture]: Check naming and action order in the vertical layout. / 세로 배치에서도 이름과 조작 순서를 확인합니다.\n  - `split` [fixture]: Inspect the boundary and names of the main action and options menu. / 주요 동작과 옵션 메뉴의 경계와 이름을 확인합니다.\n  - `input` [fixture]: Confirm the input and action read as one composed field. / 입력과 실행 버튼이 하나의 필드처럼 연결되는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `label` | `string` | No | The accessible name for the related controls. / 관련 요소 전체의 접근성 이름입니다. |\n| `orientation` | `\"horizontal\" \\| \"vertical\"` | No | The direction used to arrange controls. / 요소를 배치할 방향입니다. |\n| `children` | `ReactNode` | Yes | Buttons, inputs, text, separators, or nested groups to compose. / Button, 입력, 텍스트, 구분선 등 함께 배치할 요소입니다. |\n\n### Usage shape\n\n```tsx\n<ButtonGroup label=\"Document actions\">\n  <Button>Save</Button>\n  <ButtonGroupSeparator />\n  <Button>Publish</Button>\n</ButtonGroup>\n```\n\n## Button Link (`button-link`)\n\n- Maturity: **stable**\n- Category: **action**\n- Purpose: Uses Button's appearance while preserving a native anchor for navigation. / Button과 같은 모양을 쓰되 native anchor로 다른 주소에 이동합니다.\n- Use: Use it only when a prominent CTA navigates to another page or address. / 강한 CTA가 페이지나 주소 이동일 때만 씁니다.\n- Avoid: Use Button for in-place actions such as save, submit, or opening a dialog. / 저장, 제출, 모달 열기처럼 현재 화면에서 실행되는 동작에는 Button을 씁니다.\n- Accessibility: Do not replace it with Button; preserve native anchor semantics and a destination-specific name. / Button으로 대체하지 말고 native anchor 의미와 목적지가 드러나는 이름을 유지합니다.\n- Related components: `button`, `text-link`\n- States and inspection:\n  - `primary` [fixture]: Present the primary destination on a blue surface. / 주요 이동 목적지를 파란 면으로 표시합니다.\n  - `secondary` [fixture]: Present supporting navigation with Paper and a one-pixel rule. / 보조 이동은 Paper 면과 1px 선으로 표시합니다.\n  - `outline` [fixture]: Use an Ink outline for navigation that needs button emphasis without a fill. / 채운 면 없이 Ink 경계로 이동 동작을 구분합니다.\n  - `inverse` [fixture]: Confirm the destination remains clear on dark surfaces. / 어두운 면에서도 링크 목적지가 선명한지 확인합니다.\n  - `ghost` [fixture]: Keep link focus visible at low hierarchy. / 낮은 위계의 이동에도 링크 초점 표시를 유지합니다.\n  - `icon` [fixture]: Icon links require an aria-label that names the destination. / 아이콘 링크에는 목적지를 설명하는 aria-label이 필요합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `href` | `string` | Yes | The navigation destination. / 이동할 주소입니다. |\n| `variant` | `\"primary\" \\| \"secondary\" \\| \"outline\" \\| \"inverse\" \\| \"danger\" \\| \"ghost\"` | No | Sets the link's visual hierarchy. / 링크의 시각 위계를 정합니다. |\n| `size` | `\"compact\" \\| \"default\" \\| \"icon\"` | No | Sets the control density. / 컨트롤 밀도를 정합니다. |\n| `children` | `ReactNode` | Yes | The destination label or icon. / 목적지를 설명하는 이름 또는 아이콘입니다. |\n\n### Usage shape\n\n```tsx\n<ButtonLink href=\"/design\">Design guide</ButtonLink>\n```\n\n## Checkbox (`checkbox`)\n\n- Maturity: **candidate**\n- Category: **selection**\n- Purpose: Turns an independent selection on or off. / 서로 독립적인 선택을 켜고 끕니다.\n- Use: Use it for independent consent, list, or multi-select values. / 복수 선택, 동의, 목록 선택처럼 각 값이 독립적일 때 씁니다.\n- Avoid: Use Switch for a single setting that changes immediately. / 즉시 설정을 바꾸는 단일 동작에는 Switch를 씁니다.\n- Accessibility: Preserve the native checkbox and expose mixed state through aria-checked. / native checkbox를 유지하고 mixed 상태는 aria-checked로 함께 알립니다.\n- Related components: `radio-group`, `switch`\n- States and inspection:\n  - `unchecked` [fixture]: Inspect the label and unchecked square control. / 이름과 선택되지 않은 사각 컨트롤을 확인합니다.\n  - `checked` [fixture]: Confirm the inner square shared with Radio Group communicates selection alongside color. / Radio Group과 같은 안쪽 사각형으로 선택 상태가 함께 드러나는지 확인합니다.\n  - `indeterminate` [fixture]: Confirm partial selection is exposed as mixed. / 부분 선택이 mixed 상태로 전달되는지 확인합니다.\n  - `disabled` [fixture]: Confirm the disabled control cannot change. / 비활성 컨트롤이 실행되지 않는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `label` | `ReactNode` | Yes | The visible name of the selection. / 선택값을 설명하는 보이는 이름입니다. |\n| `description` | `ReactNode` | No | Supporting copy that explains the consequence. / 선택 결과를 설명하는 보조 문구입니다. |\n| `indeterminate` | `boolean` | No | The mixed state for a partial selection. / 일부만 선택된 mixed 상태입니다. |\n\n### Usage shape\n\n```tsx\n<Checkbox label=\"Select all\" indeterminate />\n```\n\n## Code Block (`code-block`)\n\n- Maturity: **stable**\n- Category: **content**\n- Purpose: A readable code region with a language label and copy action. / 언어 이름과 복사 동작을 갖춘 코드 읽기 영역입니다.\n- Use: Use it to present multiline code or commands verbatim in documentation. / 문서에서 여러 줄의 코드나 명령을 원문 그대로 보여줄 때 씁니다.\n- Avoid: Do not use it for short inline identifiers or as an executable editor. / 짧은 inline 식별자나 실행 가능한 편집기에는 쓰지 않습니다.\n- Accessibility: The copy button names the language, and the source remains selectable after a copy failure. / 복사 버튼 이름에는 언어를 넣습니다. 실패해도 원문을 선택할 수 있어야 합니다.\n- Related components: `button`\n- States and inspection:\n  - `idle` [fixture]: Inspect the real source, language name, and copy action in the idle state. / 실제 코드 원문, 언어 이름, 복사 버튼을 초기 상태에서 확인합니다.\n  - `copied` [interactive]: Use the real copy action and inspect its COPIED label and polite status message. / 실제 복사 버튼을 눌러 COPIED label과 polite 상태 안내를 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `error` [environment]: Deny clipboard access, then inspect the real RETRY label while the source remains selectable. / 클립보드 권한을 거부한 뒤 실제 복사 버튼의 RETRY label과 선택 가능한 원문을 확인합니다. Inspection: Change the relevant system or browser setting to inspect this state. / 운영체제나 브라우저 설정을 바꾼 뒤 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `children` | `ReactNode` | Yes | The rendered code content placed inside the pre element. / pre 안에 표시할 코드 내용입니다. |\n| `language` | `string` | No | The language identifier shown in the toolbar. / toolbar에 표시할 언어 식별자입니다. |\n| `source` | `string` | Yes | The exact source copied to the clipboard. / 클립보드에 복사할 원문입니다. |\n\n### Usage shape\n\n```tsx\n<CodeBlock language=\"ts\" source={source}>{highlightedCode}</CodeBlock>\n```\n\n## Combobox (`combobox`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: Selects one value from a searchable list. / 검색 가능한 긴 목록에서 하나의 값을 고릅니다.\n- Use: Use it when the option list is long or labels may be unfamiliar. / 선택지가 많거나 사용자가 정확한 이름을 모를 수 있을 때 씁니다.\n- Avoid: Use Native Select or Select for short, fixed option lists. / 짧고 고정된 목록에는 Native Select나 Select를 씁니다.\n- Accessibility: Exposes combobox/listbox relationships, active option, selection, and arrow-key operation. / combobox와 listbox 관계, 활성 항목, 선택 상태와 방향키 조작을 제공합니다.\n- Related components: `field`, `select`, `input`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n- States and inspection:\n  - `closed` [fixture]: Confirm the selected value and input purpose are both readable. / 선택값과 입력 목적이 함께 읽히는지 확인합니다.\n  - `open` [interactive]: Distinguish active, selected, and disabled options. / 활성 항목, 선택 항목, 비활성 항목을 구분합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `empty` [interactive]: State an empty search result in concise text. / 검색 결과가 없음을 짧은 문장으로 알립니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `options` | `readonly ComboboxOption[]` | Yes | The options available for search and selection. / 검색하고 선택할 항목입니다. |\n| `value` | `string` | No | The controlled selected value. / 제어되는 선택값입니다. |\n| `onValueChange` | `(value: string) => void` | No | Called when selection or query editing changes the current value. / 선택하거나 기존 선택을 편집해 값이 바뀔 때 호출됩니다. |\n| `onValueCommit` | `(value: string) => void` | No | Called only when the user commits an option from the list. / 사용자가 목록의 항목을 확정했을 때만 호출됩니다. |\n| `emptyText` | `string` | Yes | Copy shown when no option matches. / 검색 결과가 없을 때 표시할 문구입니다. |\n\n### Usage shape\n\n```tsx\n<Combobox\n  aria-label=\"Framework\"\n  options={options}\n  value={value}\n  onValueChange={setValue}\n  emptyText=\"No results\"\n/>\n```\n\n## Data Table (`data-table`)\n\n- Maturity: **candidate**\n- Category: **content**\n- Purpose: Displays structured data with sorting and an explicit empty state. / 정렬과 빈 상태가 필요한 구조화 데이터를 보여줍니다.\n- Use: Use it for operational lists that people need to reorder by column. / 관리 목록처럼 사용자가 열 기준으로 데이터를 다시 정렬해야 할 때 씁니다.\n- Avoid: Use Table for static comparison and Item for editorial browsing. / 정적 비교에는 Table을, 카드형 탐색에는 Item을 씁니다.\n- Accessibility: Connects sort buttons with aria-sort while preserving real Table semantics. / 정렬 버튼과 aria-sort를 연결하고 실제 Table 구조를 유지합니다.\n- Related components: `table`, `pagination`, `empty-state`\n- Dependencies: `@phosphor-icons/react`\n- States and inspection:\n  - `default` [fixture]: Distinguish sortable columns from static columns. / 정렬 가능한 열과 정적 열을 구분합니다.\n  - `sorted` [interactive]: Confirm the active column and direction appear visually and in the accessibility tree. / 현재 정렬 열과 방향이 아이콘과 접근성 트리에 함께 나타나는지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `empty` [fixture]: Confirm the empty state spans the table with concise copy. / 빈 상태가 모든 열을 가로질러 짧게 설명되는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `columns` | `readonly DataTableColumn<Row>[]` | Yes | Defines cell rendering and optional sort values. / 셀 렌더링과 선택적 정렬값을 정의합니다. |\n| `rows` | `readonly Row[]` | Yes | The real records displayed by the table. / 표에 표시할 실제 데이터입니다. |\n| `getRowKey` | `(row: Row) => string` | Yes | Returns a stable identifier for each row. / 각 행의 안정적인 식별자를 반환합니다. |\n| `emptyText` | `string` | Yes | Copy shown when there are no rows. / 표시할 행이 없을 때의 안내입니다. |\n\n### Usage shape\n\n```tsx\n<DataTable\n  aria-label=\"Services\"\n  columns={columns}\n  rows={rows}\n  getRowKey={(row) => row.id}\n  emptyText=\"No services\"\n/>\n```\n\n## Dialog (`dialog`)\n\n- Maturity: **candidate**\n- Category: **overlay**\n- Purpose: Opens a focused, short task above the current flow. / 현재 흐름 위에서 집중이 필요한 짧은 작업을 엽니다.\n- Use: Use it for settings or a short form without leaving context. / 설정이나 짧은 폼을 현재 맥락 안에서 처리할 때 씁니다.\n- Avoid: Do not use it for long documents or consequential decisions. / 긴 문서나 되돌리기 어려운 결정에는 쓰지 않습니다.\n- Accessibility: Preserves naming, focus trapping, Escape dismissal, and trigger focus restoration. / 제목과 설명, 초점 가두기, Escape 닫기와 트리거 초점 복귀를 유지합니다.\n- Related components: `alert-dialog`, `button`, `field`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n- States and inspection:\n  - `closed` [fixture]: Confirm the trigger names the task it opens. / 트리거가 열릴 작업을 구체적으로 설명하는지 확인합니다.\n  - `open` [interactive]: Inspect the title, body, actions, and close boundary. / 제목, 본문, 동작과 닫기 경계가 분명한지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `body-scroll` [interactive]: Confirm only the long body scrolls while title and actions remain reachable. / 긴 본문만 스크롤되고 제목과 동작은 접근 가능한지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `size` | `\"small\" \\| \"medium\" \\| \"large\" \\| \"full\"` | No | Sets the dialog width for the task. / 작업에 맞는 대화상자 너비입니다. |\n| `scroll` | `\"content\" \\| \"body\"` | No | Chooses the content or DialogBody scrolling boundary. / 전체 또는 DialogBody의 스크롤 경계입니다. |\n| `closeLabel` | `string` | No | Adds the compatibility close icon; new work composes DialogClose. / 호환용 닫기 아이콘을 추가합니다. 새 작업은 DialogClose를 조합합니다. |\n\n### Usage shape\n\n```tsx\n<Dialog>\n  <DialogTrigger>Settings</DialogTrigger>\n  <DialogContent size=\"medium\" scroll=\"body\">\n    <DialogBody>...</DialogBody>\n    <DialogFooter>\n      <DialogClose>Done</DialogClose>\n    </DialogFooter>\n  </DialogContent>\n</Dialog>\n```\n\n## Dropdown Menu (`dropdown-menu`)\n\n- Maturity: **candidate**\n- Category: **navigation**\n- Purpose: Opens related commands and settings from one trigger. / 한 트리거에서 관련 명령과 설정을 엽니다.\n- Use: Use it to group related, secondary commands in one place. / 자주 쓰지 않는 관련 동작을 한곳에 묶을 때 씁니다.\n- Avoid: Do not hide primary actions or replace straightforward page navigation. / 주요 행동을 숨기거나 단순한 페이지 이동 목록을 대신하지 않습니다.\n- Accessibility: Preserves arrow keys, typeahead, Escape, submenus, and trigger focus restoration. / 방향키, typeahead, Escape, 하위 메뉴와 트리거 초점 복귀를 유지합니다.\n- Related components: `button`, `select`, `dialog`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n- States and inspection:\n  - `default` [fixture]: Confirm the trigger clearly names the menu purpose. / 트리거가 메뉴의 목적을 분명히 말하는지 확인합니다.\n  - `open` [interactive]: Confirm the current item and keyboard focus are clear. / 현재 항목과 키보드 초점이 명확한지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `disabled` [fixture]: Confirm disabled commands are skipped while their state remains clear. / 비활성 명령을 건너뛰면서 상태는 전달하는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `open` | `boolean` | No | The controlled open state. / 제어되는 열림 상태입니다. |\n| `onOpenChange` | `(open: boolean) => void` | No | Called when open state changes. / 열림 상태가 바뀔 때 호출됩니다. |\n| `modal` | `boolean` | No | Whether the menu limits outside interaction. / 메뉴가 바깥 상호작용을 제한할지 정합니다. |\n\n### Usage shape\n\n```tsx\n<DropdownMenu>\n  <DropdownMenuTrigger>More</DropdownMenuTrigger>\n  <DropdownMenuContent>\n    <DropdownMenuItem>Edit</DropdownMenuItem>\n  </DropdownMenuContent>\n</DropdownMenu>\n```\n\n## Empty State (`empty-state`)\n\n- Maturity: **candidate**\n- Category: **feedback**\n- Purpose: Explains why no content is present and what can happen next. / 표시할 내용이 없을 때 이유와 다음 행동을 안내합니다.\n- Use: Use it for a genuinely empty result, document, or collection. / 검색 결과, 문서, 목록이 비어 있는 실제 상태에 씁니다.\n- Avoid: Do not invent example data or use it as a promotional card. / 예시 데이터를 꾸며 빈 공간을 채우거나 일반 홍보 영역으로 쓰지 않습니다.\n- Accessibility: Make the state understandable from title and description, with recovery when available. / 제목과 설명만으로 상태를 이해할 수 있고 가능할 때 복구 동작을 제공합니다.\n- Related components: `button`, `text-link`, `skeleton`\n- States and inspection:\n  - `default` [fixture]: Confirm title and description state the reason concretely. / 제목과 설명이 원인을 구체적으로 말하는지 확인합니다.\n  - `action` [fixture]: Confirm one clear next action is provided when recovery is possible. / 가능한 다음 행동이 하나의 명확한 버튼으로 제공되는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `title` | `ReactNode` | Yes | A title that summarizes the empty state. / 빈 상태를 요약하는 제목입니다. |\n| `description` | `ReactNode` | Yes | Explains the reason or next step. / 이유나 다음 단계를 설명합니다. |\n| `action` | `ReactNode` | No | An action for recovery or creation. / 복구나 생성으로 이어지는 동작입니다. |\n\n### Usage shape\n\n```tsx\n<EmptyState\n  title=\"No documents\"\n  description=\"Create the first document.\"\n  action={<Button>Create</Button>}\n/>\n```\n\n## Field (`field`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: Composes labels, controls, descriptions, and errors into complete form sections with FieldGroup and FieldSet. / FieldGroup과 FieldSet으로 레이블, 입력, 설명, 오류를 완전한 폼 구역으로 구성합니다.\n- Use: Use Field for one control and FieldGroup with FieldSet for related form sections. / 하나의 입력은 Field로, 관련 입력 묶음은 FieldGroup과 FieldSet으로 구성합니다.\n- Avoid: Do not group read-only content or unrelated controls under one label. / 읽기 전용 정보나 관련 없는 입력을 하나의 레이블로 묶지 않습니다.\n- Accessibility: Links nested FieldContent descriptions and errors to the control and names groups with FieldLegend. / 중첩된 FieldContent 안의 설명과 오류도 컨트롤에 연결하고 FieldLegend로 그룹 목적을 알립니다.\n- Related components: `label`, `input`, `textarea`, `native-select`\n- States and inspection:\n  - `default` [fixture]: Confirm label and control are exposed as one field. / 레이블과 입력이 하나의 항목으로 읽히는지 확인합니다.\n  - `required` [fixture]: Check the visible marker and native required state together. / 필수 표시와 native required 상태를 함께 확인합니다.\n  - `invalid` [fixture]: Check error copy and aria-invalid linkage. / 오류 문구와 aria-invalid 연결을 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `required` | `boolean` | No | Sets the required state for the nested control. / 중첩 컨트롤의 필수 상태입니다. |\n| `invalid` | `boolean` | No | Enables invalid state and error relationships. / 오류 상태와 오류 설명 연결을 활성화합니다. |\n| `orientation` | `\"vertical\" \\| \"horizontal\" \\| \"responsive\"` | No | Controls how label content and the control are arranged. / 레이블 영역과 컨트롤의 배치 방식입니다. |\n| `children` | `ReactNode` | No | A composition of FieldContent, labels, descriptions, errors, and one control. / FieldContent, 레이블, 설명, 오류와 하나의 컨트롤 조합입니다. |\n\n### Usage shape\n\n```tsx\n<FieldSet>\n  <FieldLegend>Document settings</FieldLegend>\n  <FieldGroup>\n    <Field orientation=\"responsive\">\n      <FieldContent>\n        <FieldTitle>Publishing</FieldTitle>\n        <FieldLabel>Slug</FieldLabel>\n        <FieldDescription>Public identifier</FieldDescription>\n      </FieldContent>\n      <Input />\n    </Field>\n  </FieldGroup>\n</FieldSet>\n```\n\n## Input (`input`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: A native input for single-line values. / 한 줄 값을 입력받는 native input입니다.\n- Use: Use it for single-line values such as email, title, or search. / 이메일, 제목, 검색어처럼 한 줄로 끝나는 값에 씁니다.\n- Avoid: Use Textarea for multiline copy and Native Select for fixed choices. / 여러 줄 문장에는 Textarea를, 정해진 선택에는 Native Select를 씁니다.\n- Accessibility: Provide a name through Field or Label and choose the correct native type. / Field나 Label로 이름을 제공하고 입력 목적에 맞는 type을 지정합니다.\n- Related components: `field`, `label`, `textarea`, `native-select`\n- States and inspection:\n  - `default` [fixture]: Inspect Paper surface, Ink text, and Line border. / Paper 바탕, Ink 텍스트, Line 경계를 확인합니다.\n  - `focus-visible` [interactive]: Inspect the two-pixel Primary focus outline. / 2px Primary 초점선을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `invalid` [fixture]: Inspect the Error border and associated error copy. / Error 경계와 연결된 오류 문구를 확인합니다.\n  - `disabled` [fixture]: Confirm input is blocked with disabled cursor and opacity. / 입력이 막히고 커서와 불투명도가 바뀌는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `type` | `HTMLInputTypeAttribute` | No | The native input type for the value. / 값의 native 입력 형식입니다. |\n| `name` | `string` | No | The name used for form submission. / 폼 제출에 쓰는 이름입니다. |\n| `placeholder` | `string` | No | A short example that never replaces the label. / 레이블을 대신하지 않는 짧은 예시입니다. |\n\n### Usage shape\n\n```tsx\n<Input name=\"email\" type=\"email\" autoComplete=\"email\" />\n```\n\n## Input Group (`input-group`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: Groups an input with a unit, prefix, or compact action. / 입력과 단위, 접두어, 짧은 동작을 하나의 컨트롤로 묶습니다.\n- Use: Use it for prefixes, units, or actions directly tied to an input. / URL 접두어, 단위, 검증 버튼처럼 입력과 직접 연결된 요소에 씁니다.\n- Avoid: Do not place independent fields or several primary actions inside one boundary. / 서로 독립적인 입력이나 여러 주요 행동을 한 경계 안에 넣지 않습니다.\n- Accessibility: Keeps one native control in DOM order; the start and end aliases normalize to inline placements. / 실제 입력은 하나만 두고 DOM 순서를 유지합니다. 기존 start와 end 별칭은 inline 위치로 정규화됩니다.\n- Related components: `field`, `input`, `button`\n- States and inspection:\n  - `default` [fixture]: Confirm prefixes and actions remain visibly connected to the value. / 접두어와 동작이 입력값과 시각적으로 연결되는지 확인합니다.\n  - `focus-visible` [interactive]: Confirm the shared boundary communicates focus. / 그룹 전체 경계가 초점 상태를 보여주는지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `invalid` [fixture]: Confirm Field error copy and group border communicate the same state. / Field 오류와 그룹 경계가 같은 상태를 전달하는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `placement` | `\"inline-start\" \\| \"inline-end\" \\| \"block-start\" \\| \"block-end\"` | No | The logical addon position. start and end remain compatibility aliases. / Addon의 논리적 위치입니다. start와 end는 호환 별칭입니다. |\n| `children` | `ReactNode` | No | A composition of Input or Textarea with Addon, Text, and Button parts. / Input 또는 Textarea와 Addon, Text, Button 조합입니다. |\n\n### Usage shape\n\n```tsx\n<InputGroup>\n  <InputGroupAddon placement=\"block-start\">\n    <InputGroupText>Markdown supported</InputGroupText>\n  </InputGroupAddon>\n  <InputGroupTextarea aria-label=\"Guidance\" />\n  <InputGroupAddon placement=\"block-end\">\n    <InputGroupText>0 / 240</InputGroupText>\n  </InputGroupAddon>\n</InputGroup>\n```\n\n## Item (`item`)\n\n- Maturity: **candidate**\n- Category: **structure**\n- Purpose: Composes media, copy, metadata, and actions into one row. / 미디어, 본문, 메타데이터와 동작을 하나의 행으로 구성합니다.\n- Use: Use it for repeated entities such as repositories, documents, or people without card grids. / 저장소, 문서, 사람처럼 반복되는 개체를 카드 없이 나열할 때 씁니다.\n- Avoid: Use Table for column comparison and Panel for a standalone region. / 열 비교가 핵심이면 Table을, 독립된 영역이면 Panel을 씁니다.\n- Accessibility: Chooses article, div, or li for the surrounding structure and labels the item from its title. / 주변 목록에 맞는 article, div, li 요소를 선택하고 제목으로 이름을 연결합니다.\n- Related components: `panel`, `table`, `status-label`\n- States and inspection:\n  - `default` [fixture]: Inspect the reading order of title, description, metadata, and actions. / 제목, 설명, 메타데이터와 동작의 읽기 순서를 확인합니다.\n  - `subtle` [fixture]: Confirm the quiet surface does not overpower adjacent row structure. / 조용한 면이 인접 행 경계보다 강해지지 않는지 확인합니다.\n  - `inverse` [fixture]: Verify primary and supporting copy contrast on the Ink surface. / Ink 면에서 본문과 보조 문구 대비를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `as` | `\"article\" \\| \"div\" \\| \"li\"` | No | The HTML element that fits the surrounding document structure. / 주변 문서 구조에 맞는 HTML 요소입니다. |\n| `tone` | `\"default\" \\| \"subtle\" \\| \"inverse\"` | No | The surface contrast of the row. / 행의 표면 대비입니다. |\n\n### Usage shape\n\n```tsx\n<Item as=\"li\">\n  <ItemMedia>LF</ItemMedia>\n  <ItemContent>\n    <ItemTitle>lafetch</ItemTitle>\n    <ItemDescription>Typed fetch utilities.</ItemDescription>\n  </ItemContent>\n  <ItemActions>Open</ItemActions>\n</Item>\n```\n\n## Label (`label`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: Provides a concise name for a form control. / 입력 요소의 목적을 짧게 설명합니다.\n- Use: Use it to explicitly name a native control outside Field. / Field 밖에서 native 입력과 명시적으로 연결할 때 씁니다.\n- Avoid: Do not use a label element for help text or decoration. / 설명 문구나 시각 장식만을 위해 label 요소를 쓰지 않습니다.\n- Accessibility: Keep htmlFor equal to the target control ID. / htmlFor와 입력 id를 같은 값으로 유지합니다.\n- Related components: `field`, `input`, `textarea`, `native-select`\n- States and inspection:\n  - `default` [fixture]: Confirm activating the label focuses its control. / 레이블 선택 시 연결된 입력으로 초점이 이동하는지 확인합니다.\n  - `required` [fixture]: Confirm FieldLabel's required marker does not obscure its name. / FieldLabel의 필수 표시가 텍스트 의미를 방해하지 않는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `htmlFor` | `string` | No | The ID of the associated control. / 연결할 컨트롤의 id입니다. |\n| `children` | `ReactNode` | No | A concise name for the control. / 컨트롤을 설명하는 짧은 이름입니다. |\n\n### Usage shape\n\n```tsx\n<>\n  <Label htmlFor=\"query\">Search</Label>\n  <Input id=\"query\" />\n</>\n```\n\n## Logo (`logo`)\n\n- Maturity: **stable**\n- Category: **brand**\n- Purpose: Displays the official symbol with the LafLabs wordmark. / 공식 심볼과 LafLabs 워드마크를 함께 표시합니다.\n- Use: Use it where the LafLabs identity must be explicit, such as the site header and footer. / 사이트 헤더와 푸터처럼 LafLabs임을 분명히 밝혀야 할 때 씁니다.\n- Avoid: Do not use it as a decorative background or repeating motif. / 장식 배경이나 반복 무늬로 사용하지 않습니다.\n- Accessibility: The component exposes the LafLabs name; check that an enclosing link does not create a redundant label. / Logo 단독 사용 시 LafLabs로 읽힙니다. 링크 안에서는 이름을 한 번만 제공합니다.\n- Dependencies: `next`\n- States and inspection:\n  - `default` [fixture]: Inspect the 24px symbol and full wordmark together on one baseline. / 24px 심볼과 전체 워드마크가 기준선에서 함께 정렬되는지 확인합니다.\n  - `compact` [fixture]: Inspect the 16px symbol for preserved proportions and wordmark spacing. / 16px 심볼에서도 원본 비율과 워드마크 간격이 유지되는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `size` | `number` | No | The width and height of the official symbol. Defaults to 24. / 공식 심볼의 가로와 세로 크기입니다. 기본값은 24입니다. |\n\n### Usage shape\n\n```tsx\n<Logo size={24} />\n```\n\n## Native Select (`native-select`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: A select that preserves native browser selection behavior. / 브라우저 기본 선택 동작을 유지하는 select입니다.\n- Use: Use it to choose one value from a short, fixed list. / 짧고 고정된 선택지를 하나 고를 때 씁니다.\n- Avoid: Do not use it for long searchable lists or multi-selection. / 검색이 필요한 긴 목록이나 여러 값을 고르는 UI에는 쓰지 않습니다.\n- Accessibility: Keep the native select as the only interactive element and hide its decorative icon. / native select만 상호작용 요소로 두고 장식 화살표는 숨깁니다.\n- Related components: `field`, `label`, `input`\n- Dependencies: `@phosphor-icons/react`\n- States and inspection:\n  - `default` [fixture]: Inspect the current value and decorative caret. / 현재 선택값과 장식 화살표를 확인합니다.\n  - `focus-visible` [interactive]: Open the native list by keyboard and inspect focus. / 키보드로 선택 목록을 열고 초점선을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `disabled` [fixture]: Confirm selection is blocked while the value remains readable. / 선택이 막히고 값은 읽을 수 있는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `name` | `string` | No | The name used for form submission. / 폼 제출에 쓰는 이름입니다. |\n| `children` | `ReactNode` | No | Native option and optgroup elements. / native option과 optgroup입니다. |\n\n### Usage shape\n\n```tsx\n<NativeSelect name=\"category\">\n  <option value=\"general\">General</option>\n</NativeSelect>\n```\n\n## Pagination (`pagination`)\n\n- Maturity: **candidate**\n- Category: **navigation**\n- Purpose: Navigates a collection from one connected page rail. / 연결된 레일에서 컬렉션의 이전, 다음, 특정 페이지로 이동합니다.\n- Use: Use it when a collection has multiple URL-addressable pages. / 목록이 URL로 구분된 여러 페이지를 가질 때 씁니다.\n- Avoid: Do not use it for slides or in-page tabs. / 슬라이드나 현재 화면 안의 탭 전환에는 쓰지 않습니다.\n- Accessibility: Uses a named nav, real links, aria-current, and disabled boundaries. / 이름 있는 nav, 실제 링크, aria-current와 비활성 경계를 제공합니다.\n- Related components: `data-table`, `breadcrumb`, `text-link`\n- Dependencies: `@phosphor-icons/react`\n- States and inspection:\n  - `default` [fixture]: Confirm previous and next are real destination links. / 이전과 다음이 실제 목적지 링크인지 확인합니다.\n  - `current` [fixture]: Confirm the current page uses aria-current and the blue surface. / 현재 페이지가 aria-current와 파란 면으로 전달되는지 확인합니다.\n  - `boundary` [fixture]: Confirm disabled boundary directions expose no destination. / 첫 페이지와 마지막 페이지의 비활성 방향이 목적지를 노출하지 않는지 확인합니다.\n  - `collapsed` [fixture]: Collapse long ranges while preserving the current position. / 긴 범위는 축약하되 현재 위치는 유지합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `isCurrent` | `boolean` | No | Marks the current page link. / 현재 페이지 링크를 표시합니다. |\n| `disabled` | `boolean` | No | Keeps a boundary visible without navigation. / 방향 경계를 보이되 이동은 막습니다. |\n| `label` | `string` | Yes | Names a direction or ellipsis accessibly. / 방향이나 축약 표시의 접근 가능한 이름입니다. |\n\n### Usage shape\n\n```tsx\n<Pagination aria-label=\"Document pages\">\n  <PaginationContent>\n    <PaginationItem>\n      <PaginationLink href=\"?page=2\" isCurrent>2</PaginationLink>\n    </PaginationItem>\n  </PaginationContent>\n</Pagination>\n```\n\n## Panel (`panel`)\n\n- Maturity: **candidate**\n- Category: **structure**\n- Purpose: Structures related information and actions within one clear boundary. / 관련된 정보와 동작을 하나의 명확한 경계 안에 구성합니다.\n- Use: Use it when a settings group or summary module needs a genuine independent boundary. / 설정 묶음, 요약 모듈처럼 콘텐츠의 독립된 경계가 실제로 필요할 때 씁니다.\n- Avoid: Do not wrap every section or list row, and do not nest Panels inside Panels. / 모든 섹션과 목록 행을 감싸거나 Panel 안에 Panel을 중첩하지 않습니다.\n- Accessibility: Name independent regions with aria-label or aria-labelledby and keep heading levels consistent with the document. / 독립된 영역이면 aria-label 또는 aria-labelledby로 이름을 붙이고 제목 단계는 문서 구조에 맞춥니다.\n- Related components: `separator`, `button`, `status-label`\n- States and inspection:\n  - `default` [fixture]: Confirm the Paper surface and one-pixel boundary separate the module from surrounding content. / Paper 면과 1px 경계가 주변 콘텐츠와 구분되는지 확인합니다.\n  - `subtle` [fixture]: Confirm the quiet blue surface does not compete with the content. / 옅은 파란 면이 내용보다 먼저 튀지 않는지 확인합니다.\n  - `inverse` [fixture]: Confirm title, description, and status retain sufficient contrast on Ink. / Ink 면에서 제목, 설명, 상태의 대비를 확인합니다.\n  - `action` [fixture]: Confirm the title and action stack naturally into one column on narrow screens. / 좁은 화면에서 제목과 동작이 한 열로 자연스럽게 쌓이는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `tone` | `\"default\" \\| \"subtle\" \\| \"inverse\"` | No | The surface tone chosen for the surrounding context and information hierarchy. / 주변 표면과 정보 위계에 맞는 면 색입니다. |\n| `aria-label / aria-labelledby` | `string` | No | An accessible name used when the Panel is exposed as an independent region. / 독립된 영역으로 노출할 때 쓰는 접근 가능한 이름입니다. |\n| `children` | `ReactNode` | No | Composable Panel parts such as Header, Content, and Footer. / Header, Content, Footer 등 조합할 Panel 부분입니다. |\n| `PanelTitle as` | `\"h2\" \\| \"h3\" \\| \"h4\"` | No | The heading level that matches the surrounding document. Defaults to h3. / 주변 문서 구조에 맞는 제목 단계입니다. 기본값은 h3입니다. |\n\n### Usage shape\n\n```tsx\n<Panel aria-labelledby=\"settings-title\" tone=\"subtle\">\n  <PanelHeader>\n    <PanelTitle id=\"settings-title\">Notification settings</PanelTitle>\n    <PanelDescription>Choose which updates to receive.</PanelDescription>\n  </PanelHeader>\n  <PanelContent>...</PanelContent>\n</Panel>\n```\n\n## Popover (`popover`)\n\n- Maturity: **candidate**\n- Category: **overlay**\n- Purpose: Opens compact information or controls beside the current context. / 현재 맥락 옆에 짧은 정보나 조작을 펼칩니다.\n- Use: Use it for supporting tasks such as filters or compact settings. / 필터나 짧은 설정처럼 페이지 이동이 필요 없는 보조 작업에 씁니다.\n- Avoid: Use Dialog, Alert Dialog, or Dropdown Menu for long forms, confirmations, or command lists. / 긴 폼, 중요한 확인, 단순 명령 목록에는 각각 Dialog, Alert Dialog, Dropdown Menu를 씁니다.\n- Accessibility: Names the supporting surface and preserves Escape dismissal and focus restoration. / 제목과 설명으로 보조 화면의 목적을 알리고 Escape와 초점 복귀를 유지합니다.\n- Related components: `dropdown-menu`, `dialog`, `tooltip`\n- Dependencies: `radix-ui`\n- States and inspection:\n  - `closed` [fixture]: Confirm the trigger name predicts the content it opens. / 트리거 이름만으로 펼쳐질 내용을 예상할 수 있는지 확인합니다.\n  - `open` [interactive]: Inspect viewport collision and keyboard movement. / 화면 가장자리 충돌과 키보드 이동을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `open` | `boolean` | No | The controlled open state. / 제어되는 열림 상태입니다. |\n| `sideOffset` | `number` | No | The distance between trigger and surface. / 트리거와 표면 사이 간격입니다. |\n| `align` | `\"start\" \\| \"center\" \\| \"end\"` | No | Alignment relative to the trigger. / 트리거 기준 정렬입니다. |\n\n### Usage shape\n\n```tsx\n<Popover>\n  <PopoverTrigger>Filters</PopoverTrigger>\n  <PopoverContent>\n    <PopoverTitle>Filters</PopoverTitle>\n    <PopoverDescription>Narrow results.</PopoverDescription>\n  </PopoverContent>\n</Popover>\n```\n\n## Progress (`progress`)\n\n- Maturity: **candidate**\n- Category: **feedback**\n- Purpose: Shows measurable completion or an indeterminate connection state. / 측정 가능한 작업의 진행률이나 연결 중 상태를 보여줍니다.\n- Use: Use it for uploads, processing, or synchronization that takes time. / 업로드, 처리, 동기화처럼 시간이 걸리는 작업의 상태에 씁니다.\n- Avoid: Do not use it for instant actions or final success status. / 즉시 끝나는 동작이나 최종 성공 상태를 표시하는 데 쓰지 않습니다.\n- Accessibility: Connects native progress with a visible label and never invents a numeric value. / native progress와 보이는 label을 연결하고 알 수 없는 값을 임의로 만들지 않습니다.\n- Related components: `spinner`, `skeleton`, `status-label`\n- States and inspection:\n  - `determinate` [fixture]: Confirm current value, maximum, and displayed percentage agree. / 현재 값, 최대값과 표시 백분율이 일치하는지 확인합니다.\n  - `indeterminate` [fixture]: Confirm pending progress is communicated without a false number. / 숫자 없이 진행 중 상태만 전달하는지 확인합니다.\n  - `reduced-motion` [environment]: Confirm a Primary Blue segment remains visible without motion. / 움직임 없이도 Primary Blue 구간으로 상태가 보이는지 확인합니다. Inspection: Change the relevant system or browser setting to inspect this state. / 운영체제나 브라우저 설정을 바꾼 뒤 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `label` | `string` | Yes | The visible name of the task in progress. / 진행 중인 작업의 보이는 이름입니다. |\n| `value` | `number` | No | The current value; omit it for indeterminate progress. / 현재 진행값이며 생략하면 indeterminate 상태입니다. |\n| `max` | `number` | No | The maximum value that represents completion. / 완료를 나타내는 최대값입니다. |\n| `showValue` | `boolean` | No | Shows the calculated percentage as text. / 계산된 백분율을 문구로 표시합니다. |\n\n### Usage shape\n\n```tsx\n<Progress label=\"Upload\" value={50} max={200} showValue />\n```\n\n## Radio Group (`radio-group`)\n\n- Maturity: **candidate**\n- Category: **selection**\n- Purpose: Selects exactly one value from a named group. / 한 그룹에서 하나의 값만 고릅니다.\n- Use: Use it when a short list of options should stay visible for comparison. / 선택지가 적고 모두 한눈에 비교되어야 할 때 씁니다.\n- Avoid: Use Native Select when space is tight or the list is long. / 공간이 좁거나 선택지가 많으면 Native Select를 씁니다.\n- Accessibility: Keeps a named native radio set and communicates selection with square outer and inner indicators. / fieldset과 보이는 legend, native radio를 유지하며 선택은 바깥 사각형과 안쪽 사각형으로 함께 표시합니다.\n- Related components: `checkbox`, `native-select`\n- States and inspection:\n  - `default` [fixture]: Inspect the legend and every option name. / legend와 모든 선택지 이름을 확인합니다.\n  - `selected` [fixture]: Confirm only one option is selected at a time. / 한 번에 하나만 선택되는지 확인합니다.\n  - `controlled` [interactive]: Confirm external value and change callback stay aligned. / 외부 value와 변경 콜백이 일치하는지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `disabled` [fixture]: Inspect per-option and whole-group disabled states. / 개별 선택지와 전체 그룹 비활성 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `legend` | `ReactNode` | Yes | The visible name of the option group. / 선택지 그룹의 보이는 이름입니다. |\n| `name` | `string` | Yes | The form name shared by all radio inputs. / 모든 radio가 공유하는 폼 이름입니다. |\n| `options` | `readonly RadioOption[]` | Yes | Options containing value, label, description, and disabled state. / 값, 이름, 설명, 비활성 상태를 담은 선택지입니다. |\n| `onValueChange` | `(value: string) => void` | No | Called when the selected value changes. / 선택값이 바뀔 때 호출합니다. |\n\n### Usage shape\n\n```tsx\n<RadioGroup legend=\"Language\" name=\"locale\" options={options} />\n```\n\n## Segmented Control (`segmented-control`)\n\n- Maturity: **candidate**\n- Category: **selection**\n- Purpose: Selects one value from two or more short options. / 둘 이상의 짧은 선택지 중 하나를 고릅니다.\n- Use: Use it to switch short peer values such as locale, view, or status. / 언어, 보기 방식, 상태처럼 같은 수준의 짧은 값을 즉시 전환할 때 씁니다.\n- Avoid: Use Radio Group or Select for verbose or numerous options. / 긴 설명이 필요하거나 선택지가 많으면 Radio Group이나 Select를 씁니다.\n- Accessibility: Provides radiogroup and radio semantics, aria-checked, and arrow-key roving focus. / radiogroup과 radio 의미, aria-checked, 방향키 로빙 초점을 제공합니다.\n- Related components: `radio-group`, `tabs`\n- Dependencies: `motion`\n- States and inspection:\n  - `default` [fixture]: Confirm the named group and all options read as one control. / 이름 있는 그룹과 모든 선택지가 한 구조로 읽히는지 확인합니다.\n  - `three-options` [fixture]: Confirm the selected surface fits three unequal labels. / 폭이 다른 세 선택지에서도 선택 면이 정확히 맞는지 확인합니다.\n  - `focus-visible` [interactive]: Confirm arrow keys move focus and value to the next enabled option. / 방향키가 다음 활성 선택지로 초점과 값을 함께 옮기는지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `selected` [fixture]: Confirm the selected surface and aria-checked change together. / 선택 면과 aria-checked가 함께 바뀌는지 확인합니다.\n  - `disabled` [fixture]: Confirm pointer and keyboard navigation skip disabled options. / 비활성 선택지를 클릭과 방향키가 건너뛰는지 확인합니다.\n  - `reduced-motion` [environment]: Keep selection immediately clear under reduced motion. / 동작 줄이기에서도 선택 상태는 즉시 분명해야 합니다. Inspection: Change the relevant system or browser setting to inspect this state. / 운영체제나 브라우저 설정을 바꾼 뒤 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `label` | `string` | Yes | The accessible name for the option group. / 선택지 그룹의 접근성 이름입니다. |\n| `value` | `Value` | Yes | The currently selected value. / 현재 선택한 값입니다. |\n| `options` | `readonly SegmentedControlOption<Value>[]` | Yes | Two or more options with values, labels, content, and optional disabled state. / 값, 이름, 화면 내용, 비활성 상태를 담은 둘 이상의 선택지입니다. |\n| `onValueChange` | `(value: Value) => void` | Yes | Called when the selected value changes. / 선택값이 바뀔 때 호출합니다. |\n\n### Usage shape\n\n```tsx\n<SegmentedControl\n  label=\"View\"\n  value={view}\n  options={options}\n  onValueChange={setView}\n/>\n```\n\n## Select (`select`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: Navigates a longer option list by keyboard or pointer. / 긴 선택 목록을 키보드와 포인터로 탐색합니다.\n- Use: Use it when options need richer states and controlled popup placement. / native select보다 정교한 항목 상태와 팝업 배치가 필요할 때 씁니다.\n- Avoid: Use Native Select for short lists or when the platform picker is preferable. / 선택지가 짧거나 모바일 native 선택 경험이 더 적합하면 Native Select를 씁니다.\n- Accessibility: Provide a label and preserve arrow selection, disabled options, Escape dismissal, and focus return. / 레이블을 연결하고 방향키 선택, 비활성 항목, Escape 닫기와 초점 복귀를 유지합니다.\n- Related components: `field`, `native-select`, `dropdown-menu`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n- States and inspection:\n  - `default` [fixture]: Confirm the current value and opening affordance are both visible. / 현재 값과 목록 열기 단서가 함께 보이는지 확인합니다.\n  - `open` [interactive]: Inspect trigger-width sizing and viewport collision handling. / 목록 너비와 화면 충돌 처리가 자연스러운지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `disabled` [fixture]: Confirm disabled options remain readable and are skipped by navigation. / 비활성 항목을 건너뛰면서도 읽을 수 있는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `value` | `string` | No | The controlled current value. / 제어되는 현재 값입니다. |\n| `defaultValue` | `string` | No | The uncontrolled initial value. / 비제어 초기 값입니다. |\n| `onValueChange` | `(value: string) => void` | No | Called when selection changes. / 선택이 바뀔 때 호출됩니다. |\n\n### Usage shape\n\n```tsx\n<Select defaultValue=\"ko\">\n  <SelectTrigger aria-label=\"Language\"><SelectValue /></SelectTrigger>\n  <SelectContent>\n    <SelectItem value=\"ko\">한국어</SelectItem>\n  </SelectContent>\n</Select>\n```\n\n## Separator (`separator`)\n\n- Maturity: **candidate**\n- Category: **structure**\n- Purpose: Creates a visual or semantic boundary between content. / 콘텐츠 사이의 시각적 또는 의미적 경계를 만듭니다.\n- Use: Use it when spacing alone cannot distinguish rows or sections. / 간격만으로 관계를 구분하기 어려운 행과 구간 사이에 씁니다.\n- Avoid: Do not box every element or repeat rules as decoration. / 모든 요소를 선으로 둘러싸거나 의미 없는 장식으로 반복하지 않습니다.\n- Accessibility: Hide it by default and expose a separator only when the boundary carries meaning. / 기본은 장식으로 숨기고 구분 자체가 의미일 때만 separator로 노출합니다.\n- Related components: `empty-state`\n- States and inspection:\n  - `decorative` [fixture]: Confirm the one-pixel rule is hidden from assistive technology. / 보조 기술에서 숨겨진 1px 선인지 확인합니다.\n  - `horizontal` [fixture]: Confirm a meaningful horizontal boundary renders as hr. / 의미 있는 가로 경계가 hr로 노출되는지 확인합니다.\n  - `vertical` [fixture]: Confirm vertical orientation is exposed semantically. / 세로 경계의 orientation이 전달되는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `decorative` | `boolean` | No | Defaults to true and hides the rule from assistive technology. / 기본값 true이며 보조 기술에서 숨깁니다. |\n| `orientation` | `\"horizontal\" \\| \"vertical\"` | No | The separator direction. / 선의 방향입니다. |\n\n### Usage shape\n\n```tsx\n<Separator decorative={false} />\n```\n\n## Side Panel (`side-panel`)\n\n- Maturity: **candidate**\n- Category: **overlay**\n- Purpose: Opens a larger workspace from a viewport edge without leaving the page. / 페이지 맥락을 유지한 채 가장자리에서 넓은 작업 공간을 엽니다.\n- Use: Use it for settings, details, or editing that need more room than a Popover. / 설정, 상세 정보, 편집처럼 Popover보다 넓은 보조 작업에 씁니다.\n- Avoid: Do not confine a primary page flow or complex multi-step task to a panel. / 핵심 페이지 흐름이나 여러 단계 작업을 패널에 가두지 않습니다.\n- Accessibility: Preserves Dialog title, description, focus trap, Escape dismissal, and focus restoration. / Dialog의 제목, 설명, 초점 가두기, Escape 닫기와 초점 복귀를 유지합니다.\n- Related components: `dialog`, `popover`, `panel`\n- Dependencies: `@phosphor-icons/react`, `radix-ui`\n- States and inspection:\n  - `closed` [fixture]: Confirm the trigger clearly names the supporting task. / 트리거가 보조 작업임을 분명히 하는지 확인합니다.\n  - `open` [interactive]: Inspect the page boundary, internal scroll, and close action. / 본문과 패널의 경계, 내부 스크롤과 닫기 동작을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `side` | `\"top\" \\| \"right\" \\| \"bottom\" \\| \"left\"` | No | The viewport edge the panel enters from. / 패널이 들어오는 화면 가장자리입니다. |\n| `closeLabel` | `string` | Yes | The accessible name for the close icon. / 닫기 아이콘의 접근 가능한 이름입니다. |\n| `open` | `boolean` | No | The controlled open state. / 제어되는 열림 상태입니다. |\n\n### Usage shape\n\n```tsx\n<SidePanel>\n  <SidePanelTrigger>Settings</SidePanelTrigger>\n  <SidePanelContent closeLabel=\"Close\">\n    <SidePanelTitle>Settings</SidePanelTitle>\n    <SidePanelDescription>Manage the workspace.</SidePanelDescription>\n  </SidePanelContent>\n</SidePanel>\n```\n\n## Skeleton (`skeleton`)\n\n- Maturity: **candidate**\n- Category: **feedback**\n- Purpose: Reserves content structure while data is loading. / 콘텐츠 구조가 불러와지는 동안 자리를 유지합니다.\n- Use: Use it for brief loading when the final layout shape is known. / 최종 레이아웃의 크기를 알고 짧게 기다릴 때 씁니다.\n- Avoid: Do not replace progress feedback or an empty state with a skeleton. / 오래 걸리는 작업의 진행률이나 빈 상태를 대신하지 않습니다.\n- Accessibility: Always hide it from assistive technology and announce loading separately. / 보조 기술에서는 항상 숨기고 별도 상태 문구로 로딩을 알립니다.\n- Related components: `empty-state`\n- States and inspection:\n  - `loading` [fixture]: Confirm the placeholder matches the final content shape. / 최종 콘텐츠와 비슷한 크기로 배치되는지 확인합니다.\n  - `reduced-motion` [environment]: Confirm it remains static when reduced motion is requested. / 동작 줄이기에서 정적인 면으로 남는지 확인합니다. Inspection: Change the relevant system or browser setting to inspect this state. / 운영체제나 브라우저 설정을 바꾼 뒤 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `className` | `string` | No | Provides layout-specific size and placement. / 구체적인 플레이스홀더 크기와 배치에 씁니다. |\n| `style` | `CSSProperties` | No | Sets a known final size directly. / 알려진 최종 크기를 직접 지정할 때 씁니다. |\n\n### Usage shape\n\n```tsx\n<Skeleton style={{ height: 48 }} />\n```\n\n## Spinner (`spinner`)\n\n- Maturity: **candidate**\n- Category: **feedback**\n- Purpose: Signals indeterminate progress as one gap travels around a stationary square perimeter. / 고정된 사각 테두리를 따라 열린 구간이 흐르며 완료 시점을 알 수 없는 진행을 알립니다.\n- Use: Use it inside a button or compact inline task. / 버튼이나 짧은 인라인 작업에서 잠시 기다릴 때 씁니다.\n- Avoid: Use Progress for measurable work and Skeleton for page loading. / 진행률을 알 수 있거나 넓은 페이지 로딩에는 Progress나 Skeleton을 씁니다.\n- Accessibility: Provides a named status and hides the stationary square track as presentation. / 이름 있는 status를 제공하고 하나의 사각 궤적은 장식으로 숨깁니다.\n- Related components: `button`, `progress`, `skeleton`\n- States and inspection:\n  - `compact` [fixture]: Confirm the task name remains specific inside a button. / 버튼 안에서도 작업 이름이 구체적인지 확인합니다.\n  - `default` [fixture]: Confirm the square remains fixed while its gap travels around the perimeter. / 사각형은 고정된 채 열린 구간만 테두리를 따라 흐르는지 확인합니다.\n  - `reduced-motion` [environment]: Confirm one quiet gap communicates pending state without motion. / 움직임 없이도 하나의 열린 변으로 대기 상태가 보이는지 확인합니다. Inspection: Change the relevant system or browser setting to inspect this state. / 운영체제나 브라우저 설정을 바꾼 뒤 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `label` | `string` | Yes | Names the pending task. / 진행 중인 작업의 접근 가능한 이름입니다. |\n| `size` | `\"compact\" \\| \"default\" \\| \"large\"` | No | Sets the square indicator size. / 사각 표시 크기입니다. |\n\n### Usage shape\n\n```tsx\n<Spinner label=\"Saving document\" size=\"compact\" />\n```\n\n## Status Label (`status-label`)\n\n- Maturity: **candidate**\n- Category: **feedback**\n- Purpose: Shows a real entity state with a small color square and concise text. / 작은 색상 사각형과 짧은 텍스트로 실제 개체 상태를 나타냅니다.\n- Use: Use it for static document or media lifecycle metadata. / 문서나 미디어의 발행·처리 상태처럼 정적인 메타데이터에 씁니다.\n- Avoid: Do not use it as an action, filter, long explanation, or live error. / 클릭 동작, 필터, 긴 설명이나 실시간 오류를 대신하지 않습니다.\n- Accessibility: Always provide explicit status text that remains clear without color. / 색이 없어도 뜻이 분명한 텍스트를 반드시 제공합니다.\n- Related components: `alert`, `panel`, `toast`\n- States and inspection:\n  - `neutral` [fixture]: Describe a neutral state such as Draft concisely. / 초안 같은 중립 상태를 짧은 문구로 표시합니다.\n  - `info` [fixture]: Pair an in-progress state with explicit text. / 처리 중 상태를 정보 문구와 함께 표시합니다.\n  - `success` [fixture]: Name the completed state explicitly. / 완료 상태를 구체적인 텍스트로 표시합니다.\n  - `warning` [fixture]: Explain what state requires review. / 확인이 필요한 상태를 문구로 설명합니다.\n  - `error` [fixture]: Label the failed state without replacing the error explanation. / 실패 상태를 오류 원인과 혼동하지 않게 짧게 표시합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `tone` | `\"neutral\" \\| \"info\" \\| \"success\" \\| \"warning\" \\| \"error\"` | No | Sets the semantic color of the status square. / 상태 사각형의 의미 색상입니다. |\n| `variant` | `\"neutral\" \\| \"info\" \\| \"success\" \\| \"warning\" \\| \"error\"` | No | Compatibility alias retained for one release. / 한 번의 호환 기간 동안 유지되는 별칭입니다. |\n| `children` | `ReactNode` | Yes | Concise text that names the state. / 상태를 직접 설명하는 짧은 문구입니다. |\n\n### Usage shape\n\n```tsx\n<StatusLabel tone=\"success\">Published</StatusLabel>\n```\n\n## Switch (`switch`)\n\n- Maturity: **candidate**\n- Category: **selection**\n- Purpose: Turns one immediately applied setting on or off. / 즉시 적용되는 하나의 설정을 켜고 끕니다.\n- Use: Use it for a binary setting that takes effect immediately. / 변경 즉시 효력이 생기는 이진 설정에 씁니다.\n- Avoid: Use Checkbox when consent is only committed on form submission. / 폼 제출 전까지 확정되지 않는 동의에는 Checkbox를 씁니다.\n- Accessibility: Preserves native checkbox behavior and a stable label; tone applies only to the checked surface. / native checkbox 동작과 고정된 이름을 유지하며 tone은 켜진 상태에만 적용합니다.\n- Related components: `checkbox`, `segmented-control`\n- States and inspection:\n  - `off` [fixture]: Confirm the setting remains clear while off. / 꺼짐 상태에서도 설정 이름이 분명한지 확인합니다.\n  - `on` [fixture]: Confirm thumb position and native checked state change together. / thumb 위치와 native checked 상태가 함께 바뀌는지 확인합니다.\n  - `focus-visible` [interactive]: Inspect the keyboard focus outline around the track. / 트랙 바깥의 키보드 초점선을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `disabled` [fixture]: Confirm the current value stays visible but cannot change. / 현재 값은 보이지만 바꿀 수 없는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `label` | `ReactNode` | Yes | A stable visible name for the setting. / 설정의 의미를 설명하는 고정된 이름입니다. |\n| `description` | `ReactNode` | No | Supporting copy that explains the setting effect. / 설정 효과를 설명하는 보조 문구입니다. |\n| `checked` | `boolean` | No | The current state in controlled mode. / 제어 모드의 현재 상태입니다. |\n| `defaultChecked` | `boolean` | No | The initial state in uncontrolled mode. / 비제어 모드의 초기 상태입니다. |\n| `tone` | `\"primary\" \\| \"success\" \\| \"warning\" \\| \"danger\" \\| \"neutral\"` | No | The semantic tone applied only to the checked track. / 켜진 트랙에만 적용되는 의미 색상입니다. |\n\n### Usage shape\n\n```tsx\n<Switch label=\"Allow analytics\" />\n```\n\n## Table (`table`)\n\n- Maturity: **candidate**\n- Category: **content**\n- Purpose: Presents information that must be compared across native table rows and columns. / 열과 행으로 비교해야 하는 정보를 native table로 보여줍니다.\n- Use: Use it to compare the same attributes, such as status, name, or date, across records. / 상태, 이름, 날짜처럼 같은 속성을 여러 항목에서 비교할 때 씁니다.\n- Avoid: Use Item for one record's details or a list whose sequence matters more than column comparison. / 한 항목의 상세 정보나 작은 화면에서 순서만 중요한 목록에는 Item을 씁니다.\n- Accessibility: Preserves native caption, thead, tbody, and scoped header semantics. / caption, thead, tbody, th scope 등 native 표 구조를 유지합니다.\n- Related components: `data-table`, `item`, `separator`\n- States and inspection:\n  - `default` [fixture]: Confirm column headers and row values scan as one relationship. / 열 제목과 행의 대응 관계가 빠르게 읽히는지 확인합니다.\n  - `overflow` [environment]: Confirm small screens scroll horizontally without breaking table semantics. / 작은 화면에서 표 의미를 유지한 채 가로 스크롤되는지 확인합니다. Inspection: Change the relevant system or browser setting to inspect this state. / 운영체제나 브라우저 설정을 바꾼 뒤 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `aria-label` | `string` | No | Names the table when no visible caption is present. / 보이는 caption이 없을 때 표의 이름을 제공합니다. |\n| `align` | `\"start\" \\| \"center\" \\| \"end\"` | No | Aligns header and cell content. / 열 제목과 셀 내용의 정렬입니다. |\n| `scope` | `string` | No | The row or column scope described by TableHead. / TableHead가 설명하는 행이나 열 범위입니다. |\n\n### Usage shape\n\n```tsx\n<Table aria-label=\"Deployments\">\n  <TableHeader>\n    <TableRow>\n      <TableHead>Service</TableHead>\n    </TableRow>\n  </TableHeader>\n  <TableBody>\n    <TableRow>\n      <TableCell>Laf ID</TableCell>\n    </TableRow>\n  </TableBody>\n</Table>\n```\n\n## Tabs (`tabs`)\n\n- Maturity: **candidate**\n- Category: **disclosure**\n- Purpose: Switches between peer panels within one context. / 같은 맥락의 패널을 한 번에 하나씩 전환합니다.\n- Use: Use it for quickly switching between a few peer views. / 사용자가 같은 수준의 두세 보기를 빠르게 오갈 때 씁니다.\n- Avoid: Do not use it for sequential steps or independent page navigation. / 순서가 있는 단계나 서로 독립된 페이지 이동에는 쓰지 않습니다.\n- Accessibility: Preserves tablist, tab, tabpanel relationships and arrow-key roving focus. / tablist, tab, tabpanel 관계와 방향키 로빙 초점을 유지합니다.\n- Related components: `segmented-control`, `accordion`\n- Dependencies: `radix-ui`\n- States and inspection:\n  - `default` [fixture]: Confirm the initial panel is associated with the active tab. / 첫 패널과 활성 탭이 연결되는지 확인합니다.\n  - `selected` [fixture]: Confirm the blue state rule and aria-selected change together. / 파란 상태선과 aria-selected가 함께 바뀌는지 확인합니다.\n  - `disabled` [fixture]: Confirm arrow navigation skips disabled tabs. / 비활성 탭을 방향키가 건너뛰는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `value` | `string` | No | The controlled active tab value. / 제어되는 활성 탭 값입니다. |\n| `defaultValue` | `string` | No | The uncontrolled initial tab value. / 비제어 초기 탭 값입니다. |\n| `orientation` | `\"horizontal\" \\| \"vertical\"` | No | The navigation orientation. / 탭의 탐색 방향입니다. |\n\n### Usage shape\n\n```tsx\n<Tabs defaultValue=\"overview\">\n  <TabsList aria-label=\"Views\">\n    <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n  </TabsList>\n  <TabsContent value=\"overview\">Content</TabsContent>\n</Tabs>\n```\n\n## Text Link (`text-link`)\n\n- Maturity: **stable**\n- Category: **navigation**\n- Purpose: A reusable link that pairs text with an arrow toward the next destination. / 텍스트와 화살표로 다음 목적지를 알립니다.\n- Use: Use it at the end of a section or row for lightweight onward navigation. / 구간 끝이나 목록 행에서 다음 페이지를 가볍게 안내할 때 씁니다.\n- Avoid: Do not use it for primary submission actions or icon-only controls. / 주요 제출 동작이나 아이콘만 있는 컨트롤에는 쓰지 않습니다.\n- Accessibility: The link text must identify its destination; treat the arrow as decorative. / 링크 텍스트만 읽어도 목적지를 알 수 있어야 하며 화살표는 장식으로 처리합니다.\n- Related components: `button-link`\n- Dependencies: `@phosphor-icons/react`\n- States and inspection:\n  - `default` [fixture]: Inspect the real link's destination text, underline, and decorative arrow. / 실제 링크의 목적지 텍스트, 밑줄, 장식 화살표를 함께 확인합니다.\n  - `hover` [interactive]: Hover the real link and inspect its Blue transition and arrow movement. / 실제 링크에 포인터를 올려 Blue 전환과 화살표 이동을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `focus-visible` [interactive]: Tab to the real link and inspect its outside focus outline. / Tab으로 실제 링크에 초점을 옮겨 외부 focus outline을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `visited` [interactive]: Open the real link and return to inspect the deep-blue visited state without losing its destination meaning. / 실제 링크를 연 뒤 돌아와 deep blue 방문 상태가 목적지 의미를 유지하는지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `href` | `string` | Yes | The internal or external destination. / 이동할 내부 또는 외부 주소입니다. |\n| `children` | `ReactNode` | Yes | Text that identifies the destination. / 목적지를 설명하는 텍스트입니다. |\n\n### Usage shape\n\n```tsx\n<TextLink href=\"/design/components\">Components</TextLink>\n```\n\n## Textarea (`textarea`)\n\n- Maturity: **candidate**\n- Category: **form**\n- Purpose: Accepts longer multiline text. / 여러 줄의 긴 텍스트를 입력받습니다.\n- Use: Use it for values that need line breaks, such as inquiries or summaries. / 문의 내용이나 문서 요약처럼 줄바꿈이 필요한 값에 씁니다.\n- Avoid: Do not use it as a code editor or for single-line values. / 코드 편집기나 한 줄 값에는 쓰지 않습니다.\n- Accessibility: Associate a visible label and expose length guidance as a description when needed. / 보이는 레이블을 연결하고 필요하면 글자 수 안내를 설명으로 제공합니다.\n- Related components: `field`, `label`, `input`\n- States and inspection:\n  - `default` [fixture]: Inspect the 132px minimum height and vertical resize. / 132px 최소 높이와 세로 크기 조절을 확인합니다.\n  - `focus-visible` [interactive]: Confirm focus and width remain stable with long content. / 긴 글을 입력해도 초점선과 너비가 유지되는지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `invalid` [fixture]: Confirm error copy is associated with the entered content. / 오류 문구가 입력 내용과 함께 읽히는지 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `rows` | `number` | No | The initial visible row count. / 초기 표시 줄 수입니다. |\n| `name` | `string` | No | The name used for form submission. / 폼 제출에 쓰는 이름입니다. |\n\n### Usage shape\n\n```tsx\n<Textarea name=\"message\" rows={6} />\n```\n\n## Toast (`toast`)\n\n- Maturity: **candidate**\n- Category: **feedback**\n- Purpose: Reports a brief result through one application-wide queue. / 현재 작업을 막지 않고 짧은 결과를 전역 큐로 알립니다.\n- Use: Use it for brief save, upload, or undo outcomes. / 저장, 업로드, 되돌리기처럼 짧은 결과와 선택 동작에 씁니다.\n- Avoid: Use Alert or Alert Dialog for persistent errors or required decisions. / 지속되는 오류나 반드시 결정해야 하는 내용에는 Alert나 Alert Dialog를 씁니다.\n- Accessibility: Announces routine results as status, errors as alert, and localizes dismissal. / 일반 결과는 status, 오류는 alert로 알리고 번역된 닫기 이름을 제공합니다.\n- Related components: `alert`, `status-label`, `spinner`\n- Dependencies: `radix-ui`\n- States and inspection:\n  - `success` [interactive]: Describe the completed outcome in one sentence. / 완료 결과를 한 문장으로 설명합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `error` [interactive]: Keep errors visible longer and recovery copy concise. / 오류는 더 오래 표시하고 복구 설명은 짧게 유지합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `action` [interactive]: Offer one supporting action such as Undo. / 되돌리기 같은 한 가지 보조 동작만 제공합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `queued` [interactive]: Queue notifications beyond the three visible items. / 세 개를 넘는 알림은 앞선 알림이 닫힐 때까지 대기합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `persistent` [interactive]: Use duration zero only for deliberate persistence. / duration 0은 사용자가 직접 닫을 때까지 유지합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `show` | `(options: ToastOptions) => string` | Yes | Shows a toast or updates a matching stable ID. / 알림을 표시하거나 같은 ID를 갱신합니다. |\n| `duration` | `number` | No | Sets auto-dismiss time; zero persists. / 자동 닫기 시간이며 0이면 유지됩니다. |\n| `tone` | `\"neutral\" \\| \"info\" \\| \"success\" \\| \"warning\" \\| \"error\"` | No | Sets the result tone. / 알림 결과의 의미입니다. |\n| `action` | `{ label: string; onClick: () => void }` | No | Provides one optional action. / 한 가지 선택 동작입니다. |\n\n### Usage shape\n\n```tsx\nconst toast = useToast();\ntoast.success(\"Saved\", { description: \"Changes are live.\" })\n```\n\n## Tooltip (`tooltip`)\n\n- Maturity: **candidate**\n- Category: **overlay**\n- Purpose: Provides a short supporting description on hover and focus. / 짧은 보조 설명을 hover와 focus에 제공합니다.\n- Use: Use it to clarify controls whose visible name, such as an icon, is insufficient. / 아이콘처럼 보이는 이름만으로 뜻이 부족한 컨트롤을 보완할 때 씁니다.\n- Avoid: Do not rely on it for essential information, long copy, or touch-only actions. / 필수 정보, 긴 설명, 터치만으로 접근해야 하는 행동에 의존하지 않습니다.\n- Accessibility: Opens on keyboard focus as well as hover and is associated as the trigger description. / hover뿐 아니라 keyboard focus에서도 열리고 트리거 설명으로 연결됩니다.\n- Related components: `button`\n- Dependencies: `radix-ui`\n- States and inspection:\n  - `closed` [fixture]: Confirm the trigger keeps an accessible name without the tooltip. / 툴팁 없이도 트리거 이름이 남는지 확인합니다.\n  - `open` [interactive]: Confirm concise copy stays in the viewport without obscuring the trigger. / 짧은 문장이 화면 안에 배치되고 트리거를 가리지 않는지 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n\n### Props\n\n| Name | Type | Required | Description |\n| --- | --- | --- | --- |\n| `delayDuration` | `number` | No | Provider delay before opening on hover, in milliseconds. / Provider가 hover 열림 지연을 밀리초로 정합니다. |\n| `side` | `\"top\" \\| \"right\" \\| \"bottom\" \\| \"left\"` | No | The preferred placement side. / 우선 배치 방향입니다. |\n| `sideOffset` | `number` | No | The distance from the trigger. / 트리거와의 간격입니다. |\n\n### Usage shape\n\n```tsx\n<TooltipProvider>\n  <Tooltip>\n    <TooltipTrigger aria-label=\"Status\">●</TooltipTrigger>\n    <TooltipContent>Operational</TooltipContent>\n  </Tooltip>\n</TooltipProvider>\n```\n",
      "patterns": "# Patterns\n\nComposition and responsive rules for LafLabs Web Design 2026.10.3.\n\n## Collection row (`collection-row`)\n\nA full-width row separated by space and one-pixel rules. / 여백과 1px 선으로 반복 항목을 나누는 전체 폭 행입니다.\n\n- Keep rules and spacing between items instead of wrapping each item in a card. / 카드로 감싸지 않고 항목 사이의 선과 간격을 유지합니다.\n- Align name, description, and status or action to shared columns. / 이름, 설명, 상태나 동작의 열을 같은 기준선에 맞춥니다.\n- Do not animate padding on hover. / hover에서 padding을 움직이지 않습니다.\n- Related components: `button`, `separator`, `status-label`, `text-link`\n\n## Contrast band (`contrast-band`)\n\nA restrained Ink surface divides the flow of the light public theme. / 밝은 공개 화면 안에서 Ink 면을 제한적으로 사용해 흐름을 나눕니다.\n\n- Use a dark band only for a clear content shift, such as the company statement. / 어두운 구간은 회사 소개처럼 분명한 내용 전환에만 씁니다.\n- Use white for primary text and Blue Light for short highlights. / 기본 텍스트는 흰색, 짧은 강조는 Blue Light를 사용합니다.\n- Do not restore legacy Page Navy as the default surface for new public pages. / legacy인 Page Navy를 새 공개 화면의 기본 배경으로 되살리지 않습니다.\n- Related components: `logo`, `button-link`, `text-link`\n\n## Document surface (`document-surface`)\n\nA shared shell and reading rhythm connect document indices and detail pages. / 목록과 읽기 화면은 같은 shell과 본문 리듬을 유지합니다.\n\n- Keep body measure, heading levels, dates, and metadata placement consistent. / 본문 폭, 제목 단계, 날짜와 메타데이터 위치를 문서마다 바꾸지 않습니다.\n- Use Code Block for multiline code and distinguish it from inline identifiers. / 코드는 Code Block으로 표시하고 inline 식별자와 구분합니다.\n- Use direct links between document indices and reading surfaces. / 목록과 본문 사이의 이동은 직접적인 링크로 제공합니다.\n- Related components: `field`, `code-block`, `panel`, `separator`, `text-link`\n\n## Editorial heading (`editorial-heading`)\n\nA short heading and only the necessary copy establish a section's purpose. / 짧은 제목과 필요한 설명만으로 구간의 목적을 밝힙니다.\n\n- Do not stack an eyebrow, number, and subtitle by default. / 보조 라벨, 번호, 부제를 습관처럼 겹치지 않습니다.\n- Constrain heading and description measures separately to clarify hierarchy. / 제목과 설명의 폭을 따로 제한해 위계를 분명히 합니다.\n- Add a Text Link only when the section needs an onward destination. / 다음 목적지가 필요할 때만 Text Link를 붙입니다.\n- Related components: `text-link`\n\n## Responsive collapse (`responsive-collapse`)\n\nDesktop relationships become a one-column reading order on small screens. / 넓은 화면의 관계를 작은 화면에서 한 열의 읽기 순서로 바꿉니다.\n\n- Stack complex grids at 1080px and simplify navigation and actions at 720px. / 1080px에서 복잡한 grid를 쌓고 720px에서 탐색과 동작을 정리합니다.\n- Reorder the same content for reading instead of shrinking a desktop diagram. / 데스크톱 도식을 축소하지 말고 같은 내용을 읽기 순서로 다시 배치합니다.\n- Keep a 44px target area on small screens. / 작은 화면의 동작 영역은 44px를 유지합니다.\n- Related components: `button`, `button-group`, `field`, `segmented-control`\n\n## Selected work (`selected-work`)\n\nAn editorial module pairing a real image with verified project copy. / 실제 이미지와 확인된 설명을 한 편집 모듈에 묶습니다.\n\n- Use real images from public and never fabricate a product screen. / public에 있는 실제 이미지만 사용하며 가짜 화면은 만들지 않습니다.\n- Show product status and destinations only when current data provides them. / 제품 상태와 목적지는 현재 데이터에 있을 때만 표시합니다.\n- Provide previous and next actions as named, keyboard-operable buttons. / 이전과 다음 동작은 이름 있는 button으로 만들고 키보드 조작을 지원합니다.\n- Related components: `button`, `segmented-control`, `text-link`\n\n## Site chrome (`site-chrome`)\n\nThe existing Site Header and Footer frame every public surface. / 기존 Site Header와 Footer가 모든 공개 화면을 감쌉니다.\n\n- Do not add a second fixed navbar inside a page. / 페이지 안에 두 번째 고정 내비게이션을 만들지 않습니다.\n- Keep logo, locale, search, and document navigation in their established chrome positions. / 로고, 언어 선택, 검색, 문서 이동은 기존 공통 영역에 둡니다.\n- Place page-local navigation inside the content shell. / 현재 페이지의 로컬 탐색은 콘텐츠 shell 안에 둡니다.\n- Related components: `logo`, `segmented-control`, `button`, `text-link`\n\n## System states (`system-states`)\n\nLoading, empty, and error states share one visual and verbal grammar. / loading, empty, error 상태를 같은 화면 문법으로 설명합니다.\n\n- Name the state and the next available action in short copy. / 상태와 다음 동작을 짧은 문장으로 알립니다.\n- Provide a retry action for errors when recovery is available. / error에는 가능한 경우 retry 동작을 제공합니다.\n- Do not fill empty states with invented example data. / empty 상태를 임의의 예시 데이터로 채우지 않습니다.\n- Related components: `alert`, `button`, `empty-state`, `panel`, `skeleton`, `status-label`, `text-link`\n\n# Recipes\n\nUse a published Recipe before assembling a recurring documented task. Preserve the declared component semantics, state behavior, and task order instead of inventing a replacement abstraction.\n\n## Collection state surface (`collection-state-surface`)\n\nExplains loading, results, empty, and error states consistently in one collection surface. / 하나의 목록 영역에서 loading, 결과, empty, error 상태를 일관되게 설명합니다.\n\n- Category: **system-state**\n- Components: `panel`, `table`, `item`, `pagination`, `skeleton`, `empty-state`, `alert`, `status-label`, `button`\n- Related Patterns: `collection-row`, `system-states`, `responsive-collapse`\n- Use: Use when a table or list waits for asynchronous data and has multiple outcomes. / 표나 목록이 비동기 데이터를 기다리고 여러 결과 상태를 가질 때 사용합니다.\n- Avoid: Do not use for immediate static content or one form-submission result. / 즉시 표시되는 정적 콘텐츠나 단일 폼 제출 결과에는 사용하지 않습니다.\n- Accessibility: Name the state and next action in text without announcing loading or errors twice. / 상태 제목과 다음 동작을 텍스트로 제공하고 loading과 error를 중복 발표하지 않습니다.\n- Anatomy:\n  1. Collection name and scope / 컬렉션 이름과 범위\n  2. Current state body / 현재 상태의 본문\n  3. State-specific next action / 상태별 다음 동작\n  4. Pagination when results exist / 결과가 있을 때의 페이지 이동\n- States and inspection:\n  - `loading` [fixture]: Reserve space with a Skeleton matching the final collection structure. / 최종 목록 구조와 같은 Skeleton으로 공간을 유지합니다.\n  - `populated` [fixture]: Shows comparable columns, explicit status, and pagination. / 실제 비교 가능한 열과 상태, 페이지 이동을 표시합니다.\n  - `empty` [fixture]: Explains why the collection is empty and the first available action without fake results. / 빈 이유와 가능한 첫 행동을 설명하고 가짜 결과를 만들지 않습니다.\n  - `error` [fixture]: Keeps the error and recoverable retry action inside the collection context. / 오류와 복구 가능한 재시도 동작을 목록 맥락 안에 둡니다.\n- Responsive behavior:\n  - On small screens, keep essential comparisons and reflow the rest into Item rows. / 작은 화면에서는 비교에 필요한 열만 유지하고 나머지는 Item 행으로 재배치합니다.\n  - Never hide the state title or retry action behind horizontal overflow. / 상태 제목과 재시도 동작은 가로 overflow 밖으로 숨기지 않습니다.\n- Source paths: `components/design-system/recipes/collection-state-surface-demo.tsx`\n\n### Usage shape\n\n```tsx\nimport {\n  Item,\n  ItemActions,\n  ItemContent,\n  ItemTitle,\n} from \"@/components/ui/item\"\nimport {\n  Pagination,\n  PaginationContent,\n  PaginationItem,\n  PaginationLink,\n} from \"@/components/ui/pagination\"\nimport { Panel, PanelContent, PanelHeader, PanelTitle } from \"@/components/ui/panel\"\nimport { StatusLabel } from \"@/components/ui/status-label\"\nimport { Table, TableBody, TableCell, TableRow } from \"@/components/ui/table\"\n\n<Panel aria-label=\"populated document collection\">\n  <PanelHeader>\n    <PanelTitle>Documents</PanelTitle>\n  </PanelHeader>\n  <PanelContent>\n    <Table>\n      <TableBody>\n        <TableRow>\n          <TableCell>Operations policy</TableCell>\n          <TableCell>\n            <StatusLabel tone=\"success\">Published</StatusLabel>\n          </TableCell>\n        </TableRow>\n      </TableBody>\n    </Table>\n    <Item>\n      <ItemContent>\n        <ItemTitle>Operations policy</ItemTitle>\n      </ItemContent>\n      <ItemActions>\n        <StatusLabel tone=\"success\">Published</StatusLabel>\n      </ItemActions>\n    </Item>\n    <Pagination aria-label=\"Document pages\">\n      <PaginationContent>\n        <PaginationItem>\n          <PaginationLink href=\"#\" isCurrent>1</PaginationLink>\n        </PaginationItem>\n      </PaginationContent>\n    </Pagination>\n  </PanelContent>\n</Panel>\n```\n\n## Document publishing toolbar (`document-publishing-toolbar`)\n\nCombines document status, saving, and publishing into one predictable workflow. / 문서 상태와 저장·발행 동작을 하나의 예측 가능한 작업 흐름으로 묶습니다.\n\n- Category: **action**\n- Components: `button-group`, `button`, `dropdown-menu`, `status-label`\n- Related Patterns: `document-surface`, `responsive-collapse`\n- Use: Use for document work with a clear order and priority, such as saving and publishing. / 초안 저장과 발행처럼 순서와 우선순위가 분명한 문서 작업에 사용합니다.\n- Avoid: Do not use for unrelated actions or a form with one simple submit action. / 서로 관계없는 동작이나 한 개의 단순 제출 버튼에는 사용하지 않습니다.\n- Accessibility: Expose status in text and preserve keyboard order across save, publish, and more options. / 상태는 텍스트로 표시하고 저장, 발행, 추가 옵션의 키보드 순서를 유지합니다.\n- Anatomy:\n  1. Current document status / 현재 문서 상태\n  2. Secondary save action / 보조 저장 동작\n  3. Primary publish action / 주요 발행 동작\n  4. Additional publishing options / 추가 발행 옵션\n- States and inspection:\n  - `draft` [fixture]: Shows draft status with available save and publish actions. / 초안 상태와 사용할 수 있는 저장·발행 동작을 함께 보여줍니다.\n  - `publish-options` [interactive]: Additional publishing options open without leaving the toolbar context. / 추가 발행 옵션은 현재 도구 모음의 맥락을 유지한 채 열립니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `publishing` [fixture]: Publishing prevents duplicate activation and communicates progress in text. / 발행 중에는 중복 실행을 막고 진행 상태를 텍스트로 알립니다.\n- Responsive behavior:\n  - On small screens, place status above a full-width action group. / 작은 화면에서는 상태를 동작 위에 두고 버튼 그룹을 전체 폭으로 배치합니다.\n  - Keep save, publish, and more-options order at every viewport size. / 저장, 발행, 추가 옵션의 순서는 화면 크기와 관계없이 유지합니다.\n- Source paths: `components/design-system/recipes/document-publishing-toolbar-demo.tsx`\n\n### Usage shape\n\n```tsx\nimport { Button } from \"@/components/ui/button\"\nimport { ButtonGroup, ButtonGroupSeparator } from \"@/components/ui/button-group\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport { StatusLabel } from \"@/components/ui/status-label\"\n\n<div>\n  <StatusLabel tone=\"neutral\">Draft</StatusLabel>\n  <DropdownMenu>\n    <ButtonGroup label=\"Document publishing\">\n      <Button variant=\"secondary\">Save draft</Button>\n      <Button>Publish document</Button>\n      <ButtonGroupSeparator />\n      <DropdownMenuTrigger asChild>\n        <Button aria-label=\"Open publishing options\" size=\"icon\">...</Button>\n      </DropdownMenuTrigger>\n    </ButtonGroup>\n    <DropdownMenuContent align=\"end\">\n      <DropdownMenuItem>Schedule publication</DropdownMenuItem>\n      <DropdownMenuItem>Copy preview link</DropdownMenuItem>\n    </DropdownMenuContent>\n  </DropdownMenu>\n</div>\n```\n\n## Document settings form (`document-settings-form`)\n\nConnects document metadata and publishing settings in one meaningful form structure. / 문서 메타데이터와 공개 설정을 하나의 의미 있는 폼 구조로 연결합니다.\n\n- Category: **form**\n- Components: `field`, `input`, `native-select`, `checkbox`, `switch`, `alert`\n- Related Patterns: `document-surface`, `responsive-collapse`\n- Use: Use when editing related fields and immediately applied settings as one task. / 여러 관련 필드와 즉시 적용 설정을 한 작업으로 편집할 때 사용합니다.\n- Avoid: Do not group unrelated settings or use it as a read-only summary. / 서로 관계없는 설정을 한 Panel에 모으거나 읽기 전용 요약을 표시할 때는 사용하지 않습니다.\n- Accessibility: Name the task with fieldset and legend, and connect all guidance and errors to their fields. / fieldset과 legend로 작업을 이름 붙이고 모든 안내와 오류를 해당 필드에 연결합니다.\n- Anatomy:\n  1. Settings group legend / 설정 그룹 legend\n  2. Document identity fields / 문서 식별 정보\n  3. Publishing and pinning settings / 공개와 고정 설정\n  4. Save-state feedback / 저장 상태 피드백\n- States and inspection:\n  - `default` [fixture]: Editable default document settings. / 편집 가능한 기본 문서 설정입니다.\n  - `invalid` [fixture]: Only the affected field shows an invalid state and specific guidance. / 문제가 있는 필드만 오류 상태와 구체적인 안내를 표시합니다.\n  - `disabled` [fixture]: Clearly disables settings unavailable because of permission or document state. / 권한이나 문서 상태로 편집할 수 없는 설정을 명확히 비활성화합니다.\n  - `saving` [fixture]: Saving prevents duplicate submission and communicates current progress. / 저장 중에는 중복 제출을 막고 현재 진행 상태를 알립니다.\n- Responsive behavior:\n  - On small screens, collapse horizontal fields into one label-then-input column. / 작은 화면에서는 가로 필드를 label 다음 입력 순서의 한 열로 바꿉니다.\n  - Keep descriptions and errors immediately below their related input. / 설명과 오류는 관련 입력 바로 아래에 남깁니다.\n- Source paths: `components/design-system/recipes/document-settings-form-demo.tsx`\n\n### Usage shape\n\n```tsx\nimport { Checkbox } from \"@/components/ui/checkbox\"\nimport {\n  Field,\n  FieldGroup,\n  FieldLabel,\n  FieldLegend,\n  FieldSet,\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport { NativeSelect } from \"@/components/ui/native-select\"\nimport { Switch } from \"@/components/ui/switch\"\n\n<FieldSet>\n  <FieldLegend>Document settings</FieldLegend>\n  <FieldGroup>\n    <Field>\n      <FieldLabel>Title</FieldLabel>\n      <Input />\n    </Field>\n    <Field>\n      <FieldLabel>Category</FieldLabel>\n      <NativeSelect defaultValue=\"notice\">\n        <option value=\"notice\">Notice</option>\n        <option value=\"disclosure\">Disclosure</option>\n      </NativeSelect>\n    </Field>\n    <Checkbox label=\"Pin document\" />\n    <Switch label=\"Publish immediately\" />\n  </FieldGroup>\n</FieldSet>\n```\n\n## Search and filter field (`search-filter-field`)\n\nCombines a query and structured filters into one named discovery task. / 검색어 입력과 구조화된 필터를 하나의 이름 있는 탐색 작업으로 구성합니다.\n\n- Category: **form**\n- Components: `field`, `input-group`, `combobox`, `alert`, `button`\n- Related Patterns: `collection-row`, `responsive-collapse`\n- Use: Use to search a document or record collection and narrow it with a small filter set. / 문서나 레코드 목록을 검색하고 제한된 필터로 범위를 좁힐 때 사용합니다.\n- Avoid: Do not use for a form field that selects one fixed value without search. / 검색 없이 하나의 고정 값을 고르는 폼 필드에는 사용하지 않습니다.\n- Accessibility: Connect label, description, and error to the query while preserving popup keyboard navigation. / 검색 label, 설명, 오류를 입력과 연결하고 필터 popup의 키보드 탐색을 유지합니다.\n- Anatomy:\n  1. Search field label / 검색 필드 label\n  2. Query input / 검색어 입력\n  3. Filter selection / 필터 선택\n  4. Clear action and field feedback / 지우기 동작과 필드 피드백\n- States and inspection:\n  - `default` [fixture]: The default discovery state with an empty query and filters. / 검색과 필터가 비어 있는 기본 탐색 상태입니다.\n  - `filters-open` [interactive]: Open the filter popup directly to inspect search and keyboard movement. / 필터 popup을 직접 열어 검색과 키보드 이동을 확인합니다. Inspection: Use the preview control to inspect this state. / 미리보기 컨트롤을 직접 조작해 이 상태를 확인합니다.\n  - `empty` [fixture]: When no result matches, retain the query and explain the next action. / 일치하는 결과가 없을 때 검색 조건을 유지하고 다음 행동을 안내합니다.\n  - `invalid` [fixture]: Explain an unsupported query through an error connected to the input. / 지원하지 않는 검색 값은 입력과 연결된 오류로 설명합니다.\n- Responsive behavior:\n  - On small screens, move filters below the query as a full-width row. / 작은 화면에서는 필터를 검색 입력 아래의 전체 폭 행으로 옮깁니다.\n  - Keep the label and error associated with the same input after reflow. / label과 오류는 재배치 뒤에도 같은 입력을 설명합니다.\n- Source paths: `components/design-system/recipes/search-filter-field-demo.tsx`\n\n### Usage shape\n\n```tsx\nimport { Alert, AlertAction } from \"@/components/ui/alert\"\nimport { Button } from \"@/components/ui/button\"\nimport { Combobox } from \"@/components/ui/combobox\"\nimport { Field, FieldDescription, FieldLabel } from \"@/components/ui/field\"\nimport { InputGroup, InputGroupInput } from \"@/components/ui/input-group\"\n\nconst statusOptions = [\n  { value: \"all\", label: \"All statuses\" },\n  { value: \"draft\", label: \"Draft\" },\n  { value: \"published\", label: \"Published\" },\n]\n\n<div>\n  <Field>\n    <FieldLabel>Search documents</FieldLabel>\n    <FieldDescription>Search titles and content.</FieldDescription>\n    <InputGroup><InputGroupInput type=\"search\" /></InputGroup>\n  </Field>\n  <Field>\n    <FieldLabel>Filter by document status</FieldLabel>\n    <Combobox\n      defaultValue=\"all\"\n      emptyText=\"No matching status.\"\n      options={statusOptions}\n    />\n  </Field>\n  <Alert title=\"No documents match this search.\">\n    Clear the query or adjust the status filter.\n      <AlertAction>\n        <Button variant=\"secondary\">Clear search</Button>\n      </AlertAction>\n    </Alert>\n  </div>\n```\n",
      "tokens": {
        "name": "LafLabs Web Design",
        "version": "2026.10.3",
        "updatedAt": "2026-10-07",
        "canonicalPath": "/design",
        "locales": [
          "ko",
          "en"
        ],
        "tokens": [
          {
            "id": "color.blue-grey",
            "group": "color",
            "value": "#8ba7d9",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 보조 글자와 unavailable 상태에 쓰던 색입니다.",
              "en": "Legacy supporting copy and unavailable-state color."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.blue-light",
            "group": "color",
            "value": "#60a5fa",
            "cssVariable": null,
            "purpose": {
              "ko": "어두운 대비 구간에서 짧은 강조에 씁니다.",
              "en": "Short highlights inside dark contrast bands."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.blue-pale",
            "group": "color",
            "value": "#dbeafe",
            "cssVariable": null,
            "purpose": {
              "ko": "큰 비활성 마크와 파란 면의 보조 텍스트에 씁니다.",
              "en": "Large passive marks and supporting text on blue surfaces."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.border-blue",
            "group": "color",
            "value": "#263d68",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 기본 1px 선 색입니다.",
              "en": "Legacy one-pixel rule color from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.border-blue-strong",
            "group": "color",
            "value": "#385a91",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 강조 선과 outline 버튼에 쓰던 색입니다.",
              "en": "Legacy emphasized rule and outline-action border color."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.button-ink",
            "group": "color",
            "value": "#0a0e18",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 밝은 문의 버튼 글자색입니다.",
              "en": "Legacy text color for the light contact action."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.error",
            "group": "color",
            "value": "#ef4444",
            "cssVariable": "--error",
            "purpose": {
              "ko": "오류와 위험 상태에만 씁니다.",
              "en": "Reserved for error and danger status."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.error-deep",
            "group": "color",
            "value": "#b91c1c",
            "cssVariable": "--error-deep",
            "purpose": {
              "ko": "흰색 전경이 필요한 파괴적 동작의 배경색입니다.",
              "en": "High-contrast background for destructive actions with a white foreground."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.info",
            "group": "color",
            "value": "#0ea5e9",
            "cssVariable": "--info",
            "purpose": {
              "ko": "정보 상태에만 씁니다.",
              "en": "Reserved for informational status."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.ink",
            "group": "color",
            "value": "#0f172a",
            "cssVariable": "--ink",
            "purpose": {
              "ko": "기본 텍스트와 선, 어두운 대비 구간에 씁니다.",
              "en": "The default text, rule, and dark contrast-band color."
            },
            "contrast": {
              "ko": "Paper 위에서는 텍스트와 선에 쓰고 넓은 면에서는 흰색을 올립니다.",
              "en": "Use it for text and rules on Paper, or pair an Ink surface with white."
            },
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.inverse-navy",
            "group": "color",
            "value": "#071022",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 문의 구간 바탕색입니다.",
              "en": "Legacy contact-section surface from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.line",
            "group": "color",
            "value": "#cbd5e1",
            "cssVariable": "--line",
            "purpose": {
              "ko": "눈에 덜 띄는 구분선과 비활성 외곽선에 씁니다.",
              "en": "Quiet dividers and inactive outlines."
            },
            "contrast": {
              "ko": "정보를 색이나 선만으로 구분하지 않습니다.",
              "en": "Never rely on color or a rule alone to convey information."
            },
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.mask-black",
            "group": "color",
            "value": "#000",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 기술 목록 마스크의 불투명 지점이며 화면 색으로 쓰지 않습니다.",
              "en": "Legacy opaque mask stop, not a visible surface color."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.muted",
            "group": "color",
            "value": "#64748b",
            "cssVariable": "--muted",
            "purpose": {
              "ko": "보조 설명과 덜 중요한 메타데이터에 씁니다.",
              "en": "Supporting copy and lower-priority metadata."
            },
            "contrast": {
              "ko": "작은 글자나 어두운 바탕에는 사용하지 않습니다.",
              "en": "Do not use it for small text or on dark surfaces."
            },
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.off-white",
            "group": "color",
            "value": "#f4f7fb",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 기본 글자와 밝은 컨트롤 색입니다.",
              "en": "Legacy text and light-control color from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.page-navy",
            "group": "color",
            "value": "#0b1328",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 기본 바탕색입니다.",
              "en": "Legacy default page surface from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.paper",
            "group": "color",
            "value": "#f8fafc",
            "cssVariable": "--paper",
            "purpose": {
              "ko": "페이지와 기본 컨트롤의 바탕색입니다.",
              "en": "The default page and control surface."
            },
            "contrast": {
              "ko": "본문은 Ink, 보조 설명은 Muted를 사용합니다.",
              "en": "Use Ink for body copy and Muted for supporting copy."
            },
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.primary",
            "group": "color",
            "value": "#2563eb",
            "cssVariable": "--blue",
            "purpose": {
              "ko": "주요 동작과 선택 상태, 구조를 표시하는 기본 강조색입니다.",
              "en": "The primary accent for key actions, selected states, and structure."
            },
            "contrast": {
              "ko": "넓은 파란 면에는 흰색을 쓰고 작은 글자에는 대비를 다시 확인합니다.",
              "en": "Use white on broad blue surfaces and recheck contrast for small text."
            },
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.primary-deep",
            "group": "color",
            "value": "#1e40af",
            "cssVariable": "--deep",
            "purpose": {
              "ko": "Primary Blue 동작의 hover와 pressed 상태에 씁니다.",
              "en": "The hover and pressed color for Primary Blue actions."
            },
            "contrast": {
              "ko": "흰색 텍스트와 함께 사용합니다.",
              "en": "Pair it with white text."
            },
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.pure-white",
            "group": "color",
            "value": "#fff",
            "cssVariable": "--pure-white",
            "purpose": {
              "ko": "Ink, Primary Blue, Error Deep 위의 전경색입니다.",
              "en": "Foreground color on Ink, Primary Blue, and Error Deep surfaces."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.raised-navy",
            "group": "color",
            "value": "#101c35",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면에서 기본 배경보다 밝게 띄운 요소에 쓰던 색입니다.",
              "en": "Legacy raised dark detail from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.route-blue",
            "group": "color",
            "value": "#165dff",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 채운 버튼과 구조 강조에 쓰던 색입니다.",
              "en": "Legacy fill and structural accent from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.route-blue-deep",
            "group": "color",
            "value": "#0f4bd8",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 주요 버튼 hover 색입니다.",
              "en": "Legacy primary-button hover color from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.route-blue-soft",
            "group": "color",
            "value": "#112b5d",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면에서 눈에 덜 띄는 활성 배경입니다.",
              "en": "Legacy quiet active surface from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.route-endpoint",
            "group": "color",
            "value": "#5e8fe8",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 경로 끝점 선 색입니다.",
              "en": "Legacy route-endpoint stroke color."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.route-line",
            "group": "color",
            "value": "#8fb6ff",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면의 경로와 focus 표시 색입니다.",
              "en": "Legacy route, metadata, and focus color."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.slate-detail",
            "group": "color",
            "value": "#475569",
            "cssVariable": null,
            "purpose": {
              "ko": "밝은 바탕의 작은 편집 정보에 씁니다.",
              "en": "Compact editorial detail on light surfaces."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.slate-soft",
            "group": "color",
            "value": "#94a3b8",
            "cssVariable": null,
            "purpose": {
              "ko": "어두운 대비 구간의 메타데이터에 씁니다.",
              "en": "Metadata on dark contrast bands."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.subtle-navy",
            "group": "color",
            "value": "#0e1931",
            "cssVariable": null,
            "purpose": {
              "ko": "이전 route 화면에서 번갈아 배치한 구간의 바탕색입니다.",
              "en": "Legacy alternating section surface from the route-era interface."
            },
            "contrast": null,
            "legacy": true,
            "specimen": null
          },
          {
            "id": "color.success",
            "group": "color",
            "value": "#10b981",
            "cssVariable": "--success",
            "purpose": {
              "ko": "완료와 성공 상태에만 씁니다.",
              "en": "Reserved for successful status."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "color.warning",
            "group": "color",
            "value": "#f59e0b",
            "cssVariable": "--warning",
            "purpose": {
              "ko": "주의가 필요한 상태에만 씁니다.",
              "en": "Reserved for warning status."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "layout.breakpoint-mobile",
            "group": "layout",
            "value": "720px",
            "cssVariable": null,
            "purpose": {
              "ko": "탐색과 다단 구성을 한 열로 바꾸는 작은 화면 기준입니다.",
              "en": "The small-screen breakpoint for collapsed navigation and one-column layout."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "layout.breakpoint-stack",
            "group": "layout",
            "value": "1080px",
            "cssVariable": null,
            "purpose": {
              "ko": "복잡한 데스크톱 구성을 쌓기 시작하는 기준입니다.",
              "en": "The breakpoint where complex desktop arrangements begin to stack."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "layout.compact-control",
            "group": "layout",
            "value": "34px",
            "cssVariable": null,
            "purpose": {
              "ko": "데스크톱의 언어 선택과 아이콘 Button에 쓰는 시각 크기입니다.",
              "en": "The desktop visual size for language and icon controls."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "layout.gutter",
            "group": "layout",
            "value": "max(32px, calc((100vw - 1280px) / 2))",
            "cssVariable": "--gutter",
            "purpose": {
              "ko": "전체 폭 구간의 반응형 양쪽 여백입니다.",
              "en": "Responsive inline space for full-width sections."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "layout.shell",
            "group": "layout",
            "value": "min(1280px, calc(100% - 64px))",
            "cssVariable": "--shell",
            "purpose": {
              "ko": "현재 공개 화면의 최대 콘텐츠 폭과 양쪽 여백을 정합니다.",
              "en": "The current public-shell maximum width and inline space."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "motion.reduced",
            "group": "motion",
            "value": "0ms",
            "cssVariable": null,
            "purpose": {
              "ko": "reduced motion 환경에서는 상태 전환을 즉시 끝냅니다.",
              "en": "State transitions complete immediately when reduced motion is requested."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "motion.segmented-control",
            "group": "motion",
            "value": "spring(stiffness: 520, damping: 38)",
            "cssVariable": null,
            "purpose": {
              "ko": "Segmented Control의 선택 표시가 이동할 때 쓰는 공통 spring입니다.",
              "en": "The shared spring for the Segmented Control selection surface."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "shape.radius",
            "group": "shape",
            "value": "0px",
            "cssVariable": null,
            "purpose": {
              "ko": "컨트롤, 면, 표시 요소의 기본 모서리 값입니다.",
              "en": "The default corner radius for controls, surfaces, and indicators."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "shape.rule",
            "group": "shape",
            "value": "1px",
            "cssVariable": null,
            "purpose": {
              "ko": "구간과 목록, 컨트롤을 나누는 기본 선 두께입니다.",
              "en": "The default rule width for sections, rows, and controls."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "spacing.section-vertical",
            "group": "spacing",
            "value": "80px–150px",
            "cssVariable": null,
            "purpose": {
              "ko": "콘텐츠 양과 화면 폭에 따라 구간 위아래 여백을 조절합니다.",
              "en": "Responsive vertical section space, adjusted to content and viewport width."
            },
            "contrast": null,
            "legacy": false,
            "specimen": null
          },
          {
            "id": "typography.body-default",
            "group": "typography",
            "value": "16px",
            "cssVariable": null,
            "purpose": {
              "ko": "기본 본문 크기입니다. 문맥에 따라 14px에서 17px 사이를 사용합니다.",
              "en": "Default body size, with contextual sizes ranging from 14px to 17px."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "16px",
              "fontWeight": 400,
              "lineHeight": 1.7,
              "letterSpacing": "0em"
            }
          },
          {
            "id": "typography.compact-title",
            "group": "typography",
            "value": "22px",
            "cssVariable": null,
            "purpose": {
              "ko": "작은 목록과 저장소 제목에 씁니다. weight 700입니다.",
              "en": "Compact list and repository titles at weight 700."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "22px",
              "fontWeight": 700,
              "lineHeight": 1.2,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.company-statement",
            "group": "typography",
            "value": "clamp(52px, 5.6vw, 72px)",
            "cssVariable": null,
            "purpose": {
              "ko": "어두운 회사 소개 구간에 씁니다. weight 700, line-height 1.04, tracking -0.04em입니다.",
              "en": "Dark-band company statement at weight 700, line-height 1.04, and -0.04em tracking."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(52px, 5.6vw, 72px)",
              "fontWeight": 700,
              "lineHeight": 1.04,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.family-mono",
            "group": "typography",
            "value": "Geist Mono, monospace",
            "cssVariable": null,
            "purpose": {
              "ko": "상태, 인덱스, 기술 메타데이터에만 씁니다.",
              "en": "Reserved for status, indices, and technical metadata."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "mono",
              "fontSize": "11px",
              "fontWeight": 600,
              "lineHeight": 1.45,
              "letterSpacing": "0em"
            }
          },
          {
            "id": "typography.family-sans",
            "group": "typography",
            "value": "Geist Sans, Pretendard, sans-serif",
            "cssVariable": null,
            "purpose": {
              "ko": "제목과 본문에 쓰는 기본 글꼴 묶음입니다.",
              "en": "The default family stack for headings and body copy."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "16px",
              "fontWeight": 400,
              "lineHeight": 1.5,
              "letterSpacing": "0em"
            }
          },
          {
            "id": "typography.hero-field-mark",
            "group": "typography",
            "value": "clamp(116px, 14vw, 210px)",
            "cssVariable": null,
            "purpose": {
              "ko": "홈페이지 hero 영역의 큰 필드 마크에만 씁니다. weight 850, line-height 0.75입니다.",
              "en": "The large homepage hero field mark only, at weight 850 and line-height 0.75."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(116px, 14vw, 210px)",
              "fontWeight": 850,
              "lineHeight": 0.75,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.homepage-hero",
            "group": "typography",
            "value": "clamp(64px, 6.2vw, 80px)",
            "cssVariable": null,
            "purpose": {
              "ko": "홈페이지 핵심 문장에 씁니다. weight 780, line-height 0.98, tracking -0.04em입니다.",
              "en": "Homepage proposition at weight 780, line-height 0.98, and -0.04em tracking."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(64px, 6.2vw, 80px)",
              "fontWeight": 780,
              "lineHeight": 0.98,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.method-mark",
            "group": "typography",
            "value": "clamp(88px, 10.5vw, 154px)",
            "cssVariable": null,
            "purpose": {
              "ko": "ASK, BUILD, RUN 그래픽 문자에만 씁니다. weight 850, line-height 0.75입니다.",
              "en": "Graphic ASK, BUILD, and RUN marks only, at weight 850 and line-height 0.75."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(88px, 10.5vw, 154px)",
              "fontWeight": 850,
              "lineHeight": 0.75,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.mobile-company",
            "group": "typography",
            "value": "clamp(36px, 10.8vw, 44px)",
            "cssVariable": null,
            "purpose": {
              "ko": "작은 화면의 회사 소개 문장에 씁니다.",
              "en": "Company statements on small screens."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(36px, 10.8vw, 44px)",
              "fontWeight": 700,
              "lineHeight": 1.04,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.mobile-homepage-hero",
            "group": "typography",
            "value": "clamp(40px, 11.6vw, 48px)",
            "cssVariable": null,
            "purpose": {
              "ko": "작은 화면의 홈페이지 핵심 문장에 씁니다.",
              "en": "The homepage proposition on small screens."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(40px, 11.6vw, 48px)",
              "fontWeight": 780,
              "lineHeight": 0.98,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.mobile-method-mark",
            "group": "typography",
            "value": "clamp(94px, 33vw, 136px)",
            "cssVariable": null,
            "purpose": {
              "ko": "작은 화면의 ASK, BUILD, RUN 마크에 씁니다.",
              "en": "ASK, BUILD, and RUN marks on small screens."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(94px, 33vw, 136px)",
              "fontWeight": 850,
              "lineHeight": 0.75,
              "letterSpacing": "-0.08em"
            }
          },
          {
            "id": "typography.mobile-search-input",
            "group": "typography",
            "value": "clamp(30px, 9vw, 38px)",
            "cssVariable": null,
            "purpose": {
              "ko": "작은 화면의 검색 입력에 씁니다.",
              "en": "Search input on small screens."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(30px, 9vw, 38px)",
              "fontWeight": 760,
              "lineHeight": 1,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.mobile-search-result",
            "group": "typography",
            "value": "clamp(18px, 5.6vw, 22px)",
            "cssVariable": null,
            "purpose": {
              "ko": "작은 화면의 검색 결과 제목에 씁니다.",
              "en": "Search-result headings on small screens."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(18px, 5.6vw, 22px)",
              "fontWeight": 720,
              "lineHeight": 1.12,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.mobile-section",
            "group": "typography",
            "value": "clamp(32px, 9.6vw, 40px)",
            "cssVariable": null,
            "purpose": {
              "ko": "작은 화면의 주요 구간 제목에 씁니다.",
              "en": "Major section headings on small screens."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(32px, 9.6vw, 40px)",
              "fontWeight": 720,
              "lineHeight": 1.06,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.mono-label",
            "group": "typography",
            "value": "10–11px",
            "cssVariable": null,
            "purpose": {
              "ko": "인덱스, 메타데이터, 상태, 짧은 내비게이션 label에 씁니다.",
              "en": "Indices, metadata, states, and compact navigation labels."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "mono",
              "fontSize": "clamp(10px, 0.8vw, 11px)",
              "fontWeight": 600,
              "lineHeight": 1.45,
              "letterSpacing": "0em"
            }
          },
          {
            "id": "typography.panel-title",
            "group": "typography",
            "value": "clamp(27px, 2.5vw, 36px)",
            "cssVariable": null,
            "purpose": {
              "ko": "경계가 있는 모듈의 제목에 씁니다. weight 710, line-height 1.08입니다.",
              "en": "Titles inside bounded modules at weight 710 and line-height 1.08."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(27px, 2.5vw, 36px)",
              "fontWeight": 710,
              "lineHeight": 1.08,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.search-input",
            "group": "typography",
            "value": "clamp(42px, 4.5vw, 64px)",
            "cssVariable": null,
            "purpose": {
              "ko": "검색 overlay 입력에 씁니다. weight 760, line-height 1입니다.",
              "en": "Search-overlay input at weight 760 and line-height 1."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(42px, 4.5vw, 64px)",
              "fontWeight": 760,
              "lineHeight": 1,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.search-result",
            "group": "typography",
            "value": "clamp(20px, 1.8vw, 26px)",
            "cssVariable": null,
            "purpose": {
              "ko": "검색 결과 제목에 씁니다. weight 720, line-height 1.12입니다.",
              "en": "Search-result headings at weight 720 and line-height 1.12."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(20px, 1.8vw, 26px)",
              "fontWeight": 720,
              "lineHeight": 1.12,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.section-heading",
            "group": "typography",
            "value": "clamp(44px, 4.5vw, 60px)",
            "cssVariable": null,
            "purpose": {
              "ko": "주요 구간 제목에 씁니다. weight 720, line-height 1.06, tracking -0.04em입니다.",
              "en": "Major section headings at weight 720, line-height 1.06, and -0.04em tracking."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(44px, 4.5vw, 60px)",
              "fontWeight": 720,
              "lineHeight": 1.06,
              "letterSpacing": "-0.04em"
            }
          },
          {
            "id": "typography.work-title",
            "group": "typography",
            "value": "clamp(32px, 3.4vw, 44px)",
            "cssVariable": null,
            "purpose": {
              "ko": "선택한 작업의 제목에 씁니다. weight 720, line-height 1입니다.",
              "en": "Selected-work titles at weight 720 and line-height 1."
            },
            "contrast": null,
            "legacy": false,
            "specimen": {
              "fontFamily": "sans",
              "fontSize": "clamp(32px, 3.4vw, 44px)",
              "fontWeight": 720,
              "lineHeight": 1,
              "letterSpacing": "-0.04em"
            }
          }
        ]
      }
    }
  }
}
