{
  "package": "@whyhotel/ui-core-components",
  "description": "Placemakr product design-system React component library — accessible, token-driven UI components that render against the Placemakr theme in @whyhotel/ui-core-theme.",
  "source": "src/components",
  "components": [
    {
      "name": "Accordion",
      "description": "Accordion — a set of stacked sections that each expand or collapse in place to reveal their content. Use it to condense long, scannable content (FAQs, policy details, optional settings) so people see the headings first and open only what they need. It stays in the page flow rather than floating over other content — reach for a Dialog when the content must interrupt the user. Set `allowMultiple` when several sections may be open at once. Triggers are real buttons with `aria-expanded`, and each content region is labelled by its trigger, so it is keyboard- and screen-reader-accessible by default.",
      "slots": [
        "root",
        "item",
        "title",
        "content"
      ],
      "variants": [
        {
          "name": "open",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "open",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root container.",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly AccordionItem[]",
          "required": false,
          "description": "Sections to render.",
          "source": "interface"
        },
        {
          "name": "defaultOpen",
          "type": "number",
          "required": false,
          "description": "Index open on mount; `-1` for all closed.",
          "source": "interface"
        },
        {
          "name": "allowMultiple",
          "type": "boolean",
          "required": false,
          "description": "Allow several sections open at once.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Accordion />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Alert",
      "description": "Alert — a static, inline status message that stays on the page to explain a condition or outcome (a warning, a confirmation, an error to resolve). Use it for information tied to a region of the page that the user should notice but that does not demand an immediate modal decision; for transient confirmations that fade on their own, use a Toast instead. Pick the `tone` to match intent — `info`, `success`, `warning`, `danger`, or `brand` — and pass `onDismiss` when the alert should be dismissible. The `danger` tone announces assertively to assistive tech; the others announce politely.",
      "slots": [],
      "variants": [
        {
          "name": "tone",
          "options": [
            "info",
            "success",
            "warning",
            "danger",
            "brand"
          ],
          "type": "enum",
          "default": "info"
        }
      ],
      "props": [
        {
          "name": "tone",
          "type": "'info' | 'success' | 'warning' | 'danger' | 'brand'",
          "required": false,
          "default": "info",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "icon",
          "type": "React.ReactNode",
          "required": false,
          "description": "Leading icon node the caller supplies.",
          "source": "interface"
        },
        {
          "name": "title",
          "type": "React.ReactNode",
          "required": false,
          "description": "Emphasised first line.",
          "source": "interface"
        },
        {
          "name": "action",
          "type": "React.ReactNode",
          "required": false,
          "description": "Trailing action node — usually a ghost or secondary Button.",
          "source": "interface"
        },
        {
          "name": "onDismiss",
          "type": "() => void",
          "required": false,
          "description": "Renders a dismiss control that calls this handler.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Body message.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Alert tone=\"info\">label</Alert>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Avatar",
      "description": "Avatar — a small square or circular chip that stands in for a person or entity with a photo or their initials (a guest, a teammate, a property). Use it in lists, headers, and comment rows to make ownership scannable at a glance. Pass `src` for a photo, or set `placeholder` with initials `children` when there is no image; pick a `shape` and `size` to match the surface, and add `status` to show online or offline presence. It is display only — wrap it in a Button or link when it needs to be actionable.",
      "slots": [
        "root",
        "figure"
      ],
      "variants": [
        {
          "name": "status",
          "options": [
            "online",
            "offline"
          ],
          "type": "enum"
        },
        {
          "name": "shape",
          "options": [
            "circle",
            "square",
            "rounded"
          ],
          "type": "enum",
          "default": "circle"
        },
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "placeholder",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "status",
          "type": "'online' | 'offline'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "shape",
          "type": "'circle' | 'square' | 'rounded'",
          "required": false,
          "default": "circle",
          "source": "variant"
        },
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "placeholder",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "src",
          "type": "string",
          "required": false,
          "description": "Photo source; when set the avatar renders an `<img>`.",
          "source": "interface"
        },
        {
          "name": "alt",
          "type": "string",
          "required": false,
          "description": "Alt text for the photo — describe the person, not \"avatar\".",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Stand-in content (usually initials) shown when there is no `src`.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Avatar shape=\"circle\" size=\"md\">label</Avatar>",
        "<Avatar src=\"/guests/jordan.jpg\" alt=\"jordan diaz\" />",
        "<Avatar placeholder size=\"lg\">JD</Avatar>"
      ],
      "dos": [
        "Give photos meaningful `alt` text so screen readers announce who it is."
      ],
      "donts": [
        "Put long text in a placeholder — keep it to one or two initials."
      ]
    },
    {
      "name": "Badge",
      "description": "Badge — a small inline label that tags an element with a short status or count (e.g. \"checked in\", \"3 new\"). Use it beside a title, table cell, or list item to surface state at a glance; keep the text to a word or two. Choose a `tone` to signal meaning and a `size` to match the surrounding type, and add `dot` for a leading status dot. It is decorative labelling, not an interactive control — use a Button for actions.",
      "slots": [],
      "variants": [
        {
          "name": "tone",
          "options": [
            "neutral",
            "brand",
            "info",
            "success",
            "warning",
            "danger"
          ],
          "type": "enum",
          "default": "neutral"
        },
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "outline",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "tone",
          "type": "'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'danger'",
          "required": false,
          "default": "neutral",
          "source": "variant"
        },
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "outline",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "dot",
          "type": "boolean",
          "required": false,
          "description": "Leading status dot instead of an icon.",
          "source": "interface"
        },
        {
          "name": "icon",
          "type": "React.ReactNode",
          "required": false,
          "description": "Leading icon node the caller supplies (the shared Icon primitive is out of slice scope).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Short status label.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Badge tone=\"neutral\" size=\"md\">label</Badge>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Breadcrumbs",
      "description": "Breadcrumbs — a compact trail showing where a page sits in the hierarchy and a one-tap way back up it. Feed it `items` from root to current; each crumb with an `href` renders as a link, and the last crumb renders as plain text marked `aria-current=\"page\"` so it reads as the place you are. Use it on deep pages (a reservation inside a stay inside a property) to keep orientation cheap; skip it on top-level screens where there is nowhere to go up. Pick a `size` to match the surrounding type, and pass an `icon` on a crumb for a leading glyph. The root is a labelled `<nav>` so assistive tech announces it as the breadcrumb.",
      "slots": [
        "root",
        "list",
        "item"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md"
          ],
          "type": "enum",
          "default": "sm"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md'",
          "required": false,
          "default": "sm",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly BreadcrumbItem[]",
          "required": false,
          "description": "Crumbs in order, root first; the last one is the current page.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Breadcrumbs size=\"sm\" />",
        "<Breadcrumbs\n  items={[\n    {label: 'home', href: '/'},\n    {label: 'stays', href: '/stays'},\n    {label: 'folio'}\n  ]}\n/>"
      ],
      "dos": [
        "Make the last crumb the current page and leave it without an `href`."
      ],
      "donts": [
        "Use Breadcrumbs for primary navigation — reach for a menu or tabs instead."
      ]
    },
    {
      "name": "Button",
      "description": "Button — the primary way a person triggers an action: submit a form, confirm a choice, or move to the next step. Use `variant` to signal importance — `primary` for the main action on a view, `secondary` for supporting actions, `accent` for an alternative emphasis in the brand accent color, `ghost` for low-emphasis or tertiary actions, and `danger` for destructive ones. Size with `sm`/`md`/`lg`, and set `fullWidth` when the button should span its container (common on mobile and in narrow forms). Keep one primary button per view so the main action stays obvious.",
      "slots": [],
      "variants": [
        {
          "name": "variant",
          "options": [
            "primary",
            "secondary",
            "accent",
            "ghost",
            "danger"
          ],
          "type": "enum",
          "default": "primary"
        },
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "fullWidth",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "variant",
          "type": "'primary' | 'secondary' | 'accent' | 'ghost' | 'danger'",
          "required": false,
          "default": "primary",
          "source": "variant"
        },
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "fullWidth",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "iconLeft",
          "type": "React.ReactNode",
          "required": false,
          "description": "Node rendered before the label (replaced by a spinner while `loading`).",
          "source": "interface"
        },
        {
          "name": "iconRight",
          "type": "React.ReactNode",
          "required": false,
          "description": "Node rendered after the label.",
          "source": "interface"
        },
        {
          "name": "loading",
          "type": "boolean",
          "required": false,
          "description": "Shows a spinner and disables the button.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Label — lowercase, verb-first (\"send request\"), per the brand voice.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Button variant=\"primary\" size=\"md\">label</Button>",
        "<Button variant=\"primary\" size=\"md\">continue to keys</Button>"
      ],
      "dos": [
        "use lowercase, verb-first labels (\"send request\"), per the brand voice"
      ],
      "donts": [
        "hard-code colors — retint via the theme or the `style` override channel"
      ]
    },
    {
      "name": "Card",
      "description": "Card — a container that groups related content and actions into a single surface, optionally with a header and footer. Use it to break a page into scannable units — a reservation, a room, a summary — where each unit has its own title, body, and actions. Choose `border` elevation for flat, dense layouts and `shadow` to lift a card off the page; set `interactive` when the whole card is clickable. Adjust `padding` and `tone` to fit the surrounding density and hierarchy.",
      "slots": [
        "base",
        "header",
        "body",
        "footer"
      ],
      "variants": [
        {
          "name": "elevation",
          "options": [
            "border",
            "shadow"
          ],
          "type": "enum",
          "default": "border"
        },
        {
          "name": "padding",
          "options": [
            "none",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "tone",
          "options": [
            "default",
            "sunken",
            "accent"
          ],
          "type": "enum",
          "default": "default"
        },
        {
          "name": "interactive",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "elevation",
          "type": "'border' | 'shadow'",
          "required": false,
          "default": "border",
          "source": "variant"
        },
        {
          "name": "padding",
          "type": "'none' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "tone",
          "type": "'default' | 'sunken' | 'accent'",
          "required": false,
          "default": "default",
          "source": "variant"
        },
        {
          "name": "interactive",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "header",
          "type": "React.ReactNode",
          "required": false,
          "description": "Header slot — title, status, actions.",
          "source": "interface"
        },
        {
          "name": "footer",
          "type": "React.ReactNode",
          "required": false,
          "description": "Footer slot — separated by a hairline top border.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Body content.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Card elevation=\"border\" padding=\"md\" tone=\"default\">label</Card>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Carousel",
      "description": "Carousel — a horizontally (or vertically) scrolling track of equal-status slides that snap into place as a person swipes or scrolls. Reach for it to browse a set where each item stands on its own — room photos, nearby attractions, amenity cards — rather than to walk someone through ordered steps. Pass the slides as `items`; each is wrapped in a `.carousel-item`, so give every node a width utility (e.g. `w-full`, `w-64`) in its own className to set how many show at once. Use `snap` to settle slides at the start, center, or end of the viewport, and `orientation=\"vertical\"` for a scroll-down track. It scrolls with native CSS scroll-snap, so it is touch- and keyboard-scrollable with no JavaScript.",
      "slots": [
        "root",
        "item"
      ],
      "variants": [
        {
          "name": "snap",
          "options": [
            "start",
            "center",
            "end"
          ],
          "type": "enum",
          "default": "start"
        },
        {
          "name": "orientation",
          "options": [
            "horizontal",
            "vertical"
          ],
          "type": "enum",
          "default": "horizontal"
        }
      ],
      "props": [
        {
          "name": "snap",
          "type": "'start' | 'center' | 'end'",
          "required": false,
          "default": "start",
          "source": "variant"
        },
        {
          "name": "orientation",
          "type": "'horizontal' | 'vertical'",
          "required": false,
          "default": "horizontal",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root track (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly React.ReactNode[]",
          "required": false,
          "description": "Slides to render — each is wrapped in a `.carousel-item`.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Carousel snap=\"start\" orientation=\"horizontal\" />",
        "<Carousel\n  snap=\"center\"\n  items={[\n    <img key=\"1\" className=\"w-full rounded-box\" src={pool} alt=\"rooftop pool\" />,\n    <img key=\"2\" className=\"w-full rounded-box\" src={lobby} alt=\"lobby lounge\" />\n  ]}\n/>"
      ],
      "dos": [
        "give each slide a width utility (`w-full`, `w-64`) so items size predictably."
      ],
      "donts": [
        "use a Carousel for sequential steps or a primary navigation path — that is\na Steps or Tabs job; a Carousel is for browsing peers."
      ]
    },
    {
      "name": "Chat",
      "description": "Chat — a single message in a conversation: an optional avatar, a header line, the message bubble, and a footer line. Use it to build message threads (guest messaging, support chat, front-desk handoffs) one entry at a time. Set `side` to place the message — `start` for the other person on the left, `end` for the current user on the right — and add a `tone` to tint the bubble when a message needs emphasis (a confirmation in `success`, an alert in `error`). Pass `header` for the sender and time, `footer` for a receipt, and `avatar` for the speaker's image; keep the bubble content to the message itself.",
      "slots": [
        "root",
        "image",
        "header",
        "bubble",
        "footer"
      ],
      "variants": [
        {
          "name": "side",
          "options": [
            "start",
            "end"
          ],
          "type": "enum",
          "default": "start"
        },
        {
          "name": "tone",
          "options": [
            "primary",
            "secondary",
            "accent",
            "neutral",
            "info",
            "success",
            "warning",
            "error"
          ],
          "type": "enum"
        }
      ],
      "props": [
        {
          "name": "side",
          "type": "'start' | 'end'",
          "required": false,
          "default": "start",
          "source": "variant"
        },
        {
          "name": "tone",
          "type": "'primary' | 'secondary' | 'accent' | 'neutral' | 'info' | 'success' | 'warning' | 'error'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root container.",
          "source": "interface"
        },
        {
          "name": "avatar",
          "type": "React.ReactNode",
          "required": false,
          "description": "Avatar or image node shown beside the bubble.",
          "source": "interface"
        },
        {
          "name": "header",
          "type": "React.ReactNode",
          "required": false,
          "description": "Line above the bubble — usually the sender's name and a timestamp.",
          "source": "interface"
        },
        {
          "name": "footer",
          "type": "React.ReactNode",
          "required": false,
          "description": "Line below the bubble — usually a delivery or read receipt.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The message content inside the bubble.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Chat side=\"start\">label</Chat>",
        "<Chat side=\"start\" avatar={<Avatar />} header=\"front desk\" footer=\"seen\">\n  your room is ready\n</Chat>",
        "<Chat side=\"end\" tone=\"primary\">\n  thanks, on my way up\n</Chat>"
      ],
      "dos": [
        "Use `side=\"end\"` for the current user's own messages so the thread reads\nleft-to-right like a familiar chat."
      ],
      "donts": [
        "Reach for `tone` on every bubble — reserve the color roles for messages\nthat carry status; a plain bubble is the default for ordinary chat."
      ]
    },
    {
      "name": "Checkbox",
      "description": "Checkbox — a single on/off control for an independent boolean choice, such as opting into an email or accepting a policy. Use it when each option stands alone; for one-of-many choices use radio controls, and for a compact on/off setting consider a switch. Supports an `indeterminate` (mixed) state for a \"select all\" row whose children are partly selected, and a required-true mode for must-check confirmations. Pair it with a `label`, and a `description` when the choice needs a line of explanation.",
      "slots": [
        "root",
        "control",
        "label",
        "labelText",
        "description"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "invalid",
          "options": [],
          "type": "boolean"
        },
        {
          "name": "disabled",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Control size. Defaults to md."
        },
        {
          "name": "invalid",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Marks the control invalid and applies the error style."
        },
        {
          "name": "disabled",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Disables the control."
        },
        {
          "name": "checked",
          "type": "boolean",
          "required": false,
          "description": "Controlled checked state.",
          "source": "schema"
        },
        {
          "name": "indeterminate",
          "type": "boolean",
          "required": false,
          "description": "Mixed state for \"select all\" rows.",
          "source": "schema"
        },
        {
          "name": "required",
          "type": "boolean",
          "required": false,
          "description": "Requires the box to be checked (required-true).",
          "source": "schema"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root label.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "label",
          "type": "React.ReactNode",
          "required": false,
          "description": "Label beside the box.",
          "source": "interface"
        },
        {
          "name": "description",
          "type": "React.ReactNode",
          "required": false,
          "description": "Secondary line under the label.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(checked: boolean) => void",
          "required": false,
          "description": "Reports the new checked state.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Checkbox size=\"md\" />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Countdown",
      "description": "Countdown — an animated number whose digits slide when the value changes, for live counters like the seconds left on a hold, minutes until check-in, or a rooms-remaining tally. Pass a `value` from 0 to 99 and update it over time (usually on an interval) to animate; the digits inherit their scale from the surrounding font size, so wrap it in a text-size utility for a larger display. It is a display element, not a timer — drive the value yourself and keep an accessible label nearby so the count reads clearly to assistive tech.",
      "slots": [],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "value",
          "type": "number",
          "required": true,
          "description": "The number to display, 0–99. Changing it slides the digits to the new value.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Countdown />",
        "<Countdown value={59} />",
        "<span className=\"font-mono text-2xl\"><Countdown value={minutes} /></span>"
      ],
      "dos": [
        "drive `value` from your own state or interval so the digits animate as it changes."
      ],
      "donts": [
        "pass values outside 0–99 — DaisyUI clamps the display and the animation breaks."
      ]
    },
    {
      "name": "DataTable",
      "description": "DataTable — a typed, configuration-driven table for presenting rows of structured data (reservations, folios, arrivals) in aligned columns. Define columns once — header, alignment, width, and an optional custom cell renderer — and pass row data; the table handles layout, horizontal scrolling, and the empty state. Use `density=\"compact\"` for dense operational views, and provide `onRowClick` when a row should open its detail. Reach for it whenever data is naturally tabular; for a handful of key/value pairs a simple list is lighter.",
      "slots": [
        "wrapper",
        "table",
        "row"
      ],
      "variants": [
        {
          "name": "density",
          "options": [
            "default",
            "compact"
          ],
          "type": "enum",
          "default": "default"
        },
        {
          "name": "interactive",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "density",
          "type": "'default' | 'compact'",
          "required": false,
          "default": "default",
          "source": "variant",
          "description": "Row height. Compact tightens vertical padding."
        },
        {
          "name": "interactive",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the table (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "columns",
          "type": "readonly DataTableColumn<Row>[]",
          "required": false,
          "description": "Column definitions.",
          "source": "interface"
        },
        {
          "name": "rows",
          "type": "readonly Row[]",
          "required": false,
          "description": "Row data.",
          "source": "interface"
        },
        {
          "name": "onRowClick",
          "type": "(row: Row) => void",
          "required": false,
          "description": "Makes rows clickable and applies the hover affordance.",
          "source": "interface"
        },
        {
          "name": "empty",
          "type": "React.ReactNode",
          "required": false,
          "description": "Rendered instead of the table when there are no rows.",
          "source": "interface"
        },
        {
          "name": "rowKey",
          "type": "(row: Row, index: number) => React.Key",
          "required": false,
          "description": "Stable row key extractor. Falls back to the row index.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<DataTable density=\"default\" />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Dialog",
      "description": "Dialog — a modal panel that overlays the page to focus the user on a single task or decision (confirm a checkout, complete a short form) and blocks the rest of the UI until it is resolved. Use it when the interaction must interrupt the current flow; for non-blocking status, prefer an inline Alert or a Toast. It traps focus inside the panel, restores focus to the trigger on close, and dismisses on escape or a backdrop click, so keyboard and screen-reader users are handled correctly. Keep dialogs short — a title, one line of context, and a clear primary action.",
      "slots": [
        "overlay",
        "box"
      ],
      "variants": [],
      "props": [
        {
          "name": "open",
          "type": "boolean",
          "required": false,
          "description": "Controlled open state. When false, nothing is mounted.",
          "source": "interface"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the panel (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "title",
          "type": "React.ReactNode",
          "required": false,
          "description": "Panel heading.",
          "source": "interface"
        },
        {
          "name": "description",
          "type": "React.ReactNode",
          "required": false,
          "description": "One line of context or consequence, under the title.",
          "source": "interface"
        },
        {
          "name": "footer",
          "type": "React.ReactNode",
          "required": false,
          "description": "Action row — primary Button last.",
          "source": "interface"
        },
        {
          "name": "onClose",
          "type": "() => void",
          "required": false,
          "description": "Called on escape, backdrop click, or the close control.",
          "source": "interface"
        },
        {
          "name": "width",
          "type": "number",
          "required": false,
          "description": "Max panel width in px (480 default; 640 suits forms).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Panel body.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Dialog>label</Dialog>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Diff",
      "description": "Diff — a side-by-side comparison slider that stacks two panes and reveals one over the other as a person drags the handle between them. Use it to hold two versions of the same frame in place — a room before and after a refresh, a photo with and without an edit, two copy treatments — so the difference reads at a glance instead of side by side. Pass any node to `item1` and `item2`: images, text blocks, or whole layouts, as long as both fill the same box. The figure is focusable and the handle is keyboard-resizable, so the comparison works without a mouse. It is a display surface, not a control — reach for a Toggle or Tabs when you need to switch state.",
      "slots": [
        "root",
        "item1",
        "item2",
        "resizer"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root figure (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "item1",
          "type": "React.ReactNode",
          "required": true,
          "description": "The first pane — the layer clipped by the slider (typically the \"before\").",
          "source": "interface"
        },
        {
          "name": "item2",
          "type": "React.ReactNode",
          "required": true,
          "description": "The second pane — the layer revealed as the slider moves (typically the \"after\").",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Diff />",
        "<Diff\n  item1={<img src=\"/room-before.jpg\" alt=\"before refresh\" />}\n  item2={<img src=\"/room-after.jpg\" alt=\"after refresh\" />}\n/>"
      ],
      "dos": [
        "give both panes the same dimensions so the two layers line up as the slider moves."
      ],
      "donts": [
        "use it to switch app state — it compares content, it doesn't toggle settings."
      ]
    },
    {
      "name": "Divider",
      "description": "Divider — a thin rule that separates two blocks of content, optionally with a short label sitting in the gap. Use the default horizontal rule between stacked sections (a folio total above a payment form, \"or\" between sign-in options), or set `orientation=\"vertical\"` to split two side-by-side items in a flex row. Add a `tone` to tint the rule when the separation carries meaning, and use `placement` to push the label to the start or end. Keep labels lowercase and short; it is a separator, not a heading.",
      "slots": [],
      "variants": [
        {
          "name": "orientation",
          "options": [
            "horizontal",
            "vertical"
          ],
          "type": "enum",
          "default": "horizontal"
        },
        {
          "name": "placement",
          "options": [
            "start",
            "end"
          ],
          "type": "enum"
        },
        {
          "name": "tone",
          "options": [
            "brand",
            "secondary",
            "accent",
            "neutral",
            "info",
            "success",
            "warning",
            "danger"
          ],
          "type": "enum"
        }
      ],
      "props": [
        {
          "name": "orientation",
          "type": "'horizontal' | 'vertical'",
          "required": false,
          "default": "horizontal",
          "source": "variant"
        },
        {
          "name": "placement",
          "type": "'start' | 'end'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "tone",
          "type": "'brand' | 'secondary' | 'accent' | 'neutral' | 'info' | 'success' | 'warning' | 'danger'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Optional label shown in the gap — keep it to a word or two (\"or\", \"today\").",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Divider orientation=\"horizontal\">label</Divider>",
        "<Divider>or</Divider>",
        "<div className=\"flex\">\n  <span>details</span>\n  <Divider orientation=\"vertical\" />\n  <span>payment</span>\n</div>"
      ],
      "dos": [
        "<Divider placement=\"start\">today</Divider>"
      ],
      "donts": [
        "<Divider><h2>Payment</h2></Divider>  // a divider label is not a heading"
      ]
    },
    {
      "name": "Dock",
      "description": "Dock — a fixed bar of destinations pinned to the bottom of the viewport, the primary way to move between the top-level areas of a mobile-first app (stays, calendar, keys, account). Feed it an `items` array of a label and optional icon, mark the current area with `active`, and handle taps with `onSelect`. Keep it to three to five destinations so each stays a comfortable tap target, and match `size` to the surrounding density. Each destination is a real `<button>` and the active one carries `aria-current`, so it is keyboard- and screen-reader-navigable by default.",
      "slots": [
        "root",
        "item",
        "label"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg",
            "xl"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "active",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg' | 'xl'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "active",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Index of the current destination — gets `dock-active` and `aria-current`."
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root bar (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly DockItem[]",
          "required": false,
          "description": "Destinations to render, left to right.",
          "source": "interface"
        },
        {
          "name": "onSelect",
          "type": "(index: number) => void",
          "required": false,
          "description": "Called with the index when a destination is pressed.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Dock size=\"md\" />",
        "<Dock\n  active={tab}\n  onSelect={setTab}\n  items={[\n    {label: 'stays', icon: <HomeIcon />},\n    {label: 'calendar', icon: <CalendarIcon />},\n    {label: 'keys', icon: <KeyIcon />}\n  ]}\n/>"
      ],
      "dos": [
        "Keep to three to five destinations and give every one an icon and a short label."
      ],
      "donts": [
        "Reach for a Dock as a secondary toolbar — it owns the bottom of the viewport, so use Tabs for in-page section switching."
      ]
    },
    {
      "name": "Drawer",
      "description": "Drawer — a panel that slides in from the edge of the screen over the current view, dimming the main content behind an overlay. Use it for secondary navigation, filters, or a folio summary that should appear on demand without a full page change — reach for a Dialog when the task must be completed before anything else. It is uncontrolled by default: set `defaultOpen` and listen with `onOpenChange`, or pass `open` to drive it yourself. Clicking the overlay closes the panel, and the overlay carries a `close sidebar` label so it stays reachable by assistive tech. Set `placement=\"end\"` to slide it from the trailing edge.",
      "slots": [
        "root",
        "toggle",
        "content",
        "side",
        "overlay"
      ],
      "variants": [
        {
          "name": "placement",
          "options": [
            "start",
            "end"
          ],
          "type": "enum",
          "default": "start"
        }
      ],
      "props": [
        {
          "name": "placement",
          "type": "'start' | 'end'",
          "required": false,
          "default": "start",
          "source": "variant",
          "description": "Which edge the panel slides from — `end` maps to `drawer-end`."
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root container.",
          "source": "interface"
        },
        {
          "name": "side",
          "type": "React.ReactNode",
          "required": true,
          "description": "Panel content — rendered inside the sliding side region.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": true,
          "description": "Main content — stays visible beneath the overlay.",
          "source": "interface"
        },
        {
          "name": "open",
          "type": "boolean",
          "required": false,
          "description": "Controlled open state. Omit to let Drawer own it.",
          "source": "interface"
        },
        {
          "name": "defaultOpen",
          "type": "boolean",
          "required": false,
          "description": "Open state on mount when uncontrolled.",
          "source": "interface"
        },
        {
          "name": "onOpenChange",
          "type": "(open: boolean) => void",
          "required": false,
          "description": "Called with the next open state whenever it changes.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Drawer placement=\"start\">label</Drawer>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Dropdown",
      "description": "Dropdown — a button that reveals a small floating panel of actions or links beneath (or beside) it. Use it to tuck away secondary actions — a row's overflow menu, an account switcher, a \"more\" list — so the surface stays calm until someone asks for the options. It is built on the native `<details>`/`<summary>` disclosure, so it opens on click or Enter/Space, closes on Escape or an outside click, and needs no extra ARIA. Set `placement` to anchor the panel (bottom by default), `hover` to open it on pointer hover, and pass `open` only when you need to drive visibility from your own state. Fill the panel with a `menu` list of links or Buttons — keep it short and scannable.",
      "slots": [
        "root",
        "trigger",
        "content"
      ],
      "variants": [
        {
          "name": "placement",
          "options": [
            "bottom",
            "top",
            "left",
            "right",
            "end"
          ],
          "type": "enum",
          "default": "bottom"
        },
        {
          "name": "hover",
          "options": [],
          "type": "boolean"
        },
        {
          "name": "open",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "placement",
          "type": "'bottom' | 'top' | 'left' | 'right' | 'end'",
          "required": false,
          "default": "bottom",
          "source": "variant"
        },
        {
          "name": "hover",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "open",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root `<details>`.",
          "source": "interface"
        },
        {
          "name": "label",
          "type": "React.ReactNode",
          "required": true,
          "description": "Trigger content rendered inside the `<summary>` button.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": true,
          "description": "Panel content — usually a menu or list of `<li>` items.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Dropdown placement=\"bottom\">label</Dropdown>",
        "<Dropdown label=\"reservation actions\">\n  <li><a>edit dates</a></li>\n  <li><a>cancel booking</a></li>\n</Dropdown>"
      ],
      "dos": [
        "keep the panel to a short, scannable list of related actions"
      ],
      "donts": [
        "reach for a Dropdown when the choice belongs inline — use a Select for form values"
      ]
    },
    {
      "name": "Fab",
      "description": "Fab — a floating action button that pins the single most important action to the bottom-right of a view, then fans out into a speed-dial of related actions on focus or hover. Reach for it on task-focused screens (a reservation, a folio, a housekeeping board) where one action dominates — compose, add, check in — and a few supporting ones should stay one tap away without crowding the layout. Pass `icon` for the trigger glyph and `triggerLabel` for its accessible name; feed `actions` to reveal labelled buttons, and set `mainAction` when a primary affordance should slide into the trigger's place as the dial opens. The reveal is CSS-driven via `:focus-within`, so it is keyboard-reachable by default. Keep one Fab per view so the main action stays unmistakable.",
      "slots": [
        "root",
        "trigger",
        "action"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root container.",
          "source": "interface"
        },
        {
          "name": "icon",
          "type": "React.ReactNode",
          "required": true,
          "description": "Content of the main trigger — usually a single icon.",
          "source": "interface"
        },
        {
          "name": "triggerLabel",
          "type": "string",
          "required": false,
          "description": "Accessible name for the icon-only trigger (e.g. \"quick actions\").",
          "source": "interface"
        },
        {
          "name": "actions",
          "type": "readonly FabAction[]",
          "required": false,
          "description": "Actions revealed on focus/hover, stacked above the trigger.",
          "source": "interface"
        },
        {
          "name": "mainAction",
          "type": "React.ReactNode",
          "required": false,
          "description": "A primary action shown in the trigger's place while the Fab is open.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Fab />",
        "<Fab\n  icon={<PlusIcon />}\n  triggerLabel=\"quick actions\"\n  actions={[\n    {label: 'message guest', icon: <ChatIcon />, onClick: openChat},\n    {label: 'extend stay', icon: <CalendarIcon />, onClick: extendStay}\n  ]}\n/>"
      ],
      "dos": [
        "give the trigger an accessible name via `triggerLabel` when `icon` is a glyph"
      ],
      "donts": [
        "stack more than five or six actions — a speed-dial is for a short shortlist"
      ]
    },
    {
      "name": "Fieldset",
      "description": "Fieldset — a labelled wrapper that groups related fields into one section of a form, such as guest details or payment. Give it a `legend` for the section heading and an optional `label` caption to explain what the group is for, then pass the fields as children; it lays them out in a tidy vertical stack. Reach for it whenever a form has more than a handful of inputs and benefits from being read in chunks — it is structure, not a control, so it holds inputs but never carries a value of its own. Keep the legend to a short noun phrase and the caption to a single helpful line.",
      "slots": [
        "root",
        "legend",
        "label"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root fieldset (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "legend",
          "type": "React.ReactNode",
          "required": false,
          "description": "Heading for the group, rendered as the `<legend>`.",
          "source": "interface"
        },
        {
          "name": "label",
          "type": "React.ReactNode",
          "required": false,
          "description": "Muted caption line under the legend that describes the group.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The fields this fieldset groups.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Fieldset>label</Fieldset>",
        "<Fieldset legend=\"guest details\" label=\"how we reach you about your stay\">\n  <Input label=\"full name\" />\n  <Input label=\"email\" type=\"email\" />\n</Fieldset>"
      ],
      "dos": [
        "Group fields that belong together and give each Fieldset a clear legend."
      ],
      "donts": [
        "Nest a Fieldset inside another just to indent fields — use spacing instead."
      ]
    },
    {
      "name": "FileInput",
      "description": "FileInput — a field for picking one or more files from the device, such as a folio PDF, an ID scan, or a room photo. It reports the raw `FileList` through `onChange`, so the caller owns reading, previewing, and uploading. Set `accept` to constrain the file types and `multiple` to allow more than one, and mark `invalid` to show the error state when validation fails. Size with `sm`/`md`/`lg` to match the surrounding form, or use `ghost` for a borderless field on a tinted panel. Pair it with a form field for the label, help text, and error message.",
      "slots": [],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "invalid",
          "options": [],
          "type": "boolean"
        },
        {
          "name": "ghost",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Control height. Defaults to md."
        },
        {
          "name": "invalid",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Marks the field invalid and applies the error style."
        },
        {
          "name": "ghost",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Strips the border and background for a seamless, borderless field."
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the field.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(files: FileList | null) => void",
          "required": false,
          "description": "Reports the picked files, or `null` when the selection is cleared.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<FileInput size=\"md\" />",
        "<FileInput accept=\"application/pdf\" onChange={files => setFolio(files?.[0])} />"
      ],
      "dos": [
        "<FileInput accept=\"image/*\" multiple onChange={handleUpload} />"
      ],
      "donts": [
        "<FileInput onChange={e => read(e.target.files)} /> // onChange gives the FileList, not an event"
      ]
    },
    {
      "name": "Filter",
      "description": "Filter — a compact row of buttons for narrowing a list to one facet at a time: a room type, a rate plan, a reservation status. It renders as a radio group, so only one option is ever active, and a reset control appears once a choice is made to clear back to \"all\". Use it above a results list where the choices are few and worth showing at a glance; reach for a Select when the options are many or space is tight. Leave it uncontrolled to let it track its own selection, or pass `value` and `onChange` to drive it from state. Every option is a real labelled radio, so it is keyboard- and screen-reader-friendly.",
      "slots": [
        "root",
        "reset",
        "option"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root `.filter`.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "options",
          "type": "readonly FilterOption[]",
          "required": true,
          "description": "Choices to render, one radio button each.",
          "source": "interface"
        },
        {
          "name": "value",
          "type": "string",
          "required": false,
          "description": "Active value when controlled — Filter no longer keeps its own state.",
          "source": "interface"
        },
        {
          "name": "defaultValue",
          "type": "string",
          "required": false,
          "description": "Active value on mount when uncontrolled.",
          "source": "interface"
        },
        {
          "name": "name",
          "type": "string",
          "required": false,
          "description": "Shared radio-group name; defaults to a generated id.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(value: string | null) => void",
          "required": false,
          "description": "Reports the picked value, or `null` when reset clears the selection.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Filter size=\"md\" />",
        "<Filter options={[{value: 'suite', label: 'suite'}, {value: 'studio', label: 'studio'}]} defaultValue=\"suite\" />"
      ],
      "dos": [
        "keep labels short and lowercase (\"sold out\", \"available\"), per the brand voice"
      ],
      "donts": [
        "use it for multi-select — reach for a checkbox group when several facets stack"
      ]
    },
    {
      "name": "Footer",
      "description": "Footer — the page's closing landmark, holding link columns, contact details, or a copyright line at the bottom of a view. Supply the columns as children (each a `<nav>` with a `footer-title` heading and `link link-hover` links); the Footer owns the grid so the columns align and space evenly. Use `orientation=\"horizontal\"` to lay the columns in a row on wide surfaces, and `center` for a single-column, centered footer such as a copyright strip. It is a `<footer>` landmark, not a navigation bar — reach for it at the end of the page, not the top.",
      "slots": [],
      "variants": [
        {
          "name": "orientation",
          "options": [
            "vertical",
            "horizontal"
          ],
          "type": "enum",
          "default": "vertical"
        },
        {
          "name": "center",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "orientation",
          "type": "'vertical' | 'horizontal'",
          "required": false,
          "default": "vertical",
          "source": "variant"
        },
        {
          "name": "center",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The footer columns — usually `<nav>` groups of a title and links.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Footer orientation=\"vertical\">label</Footer>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Header",
      "description": "Header — a section or page heading rendered in the theme's display type roles. Use `variant` to set the visual level: `display` for a hero or page title, `headline` for a major section, `title` for a card or subsection (the default), and `subtitle` for a secondary line paired with a title. The variant also picks a sensible heading element (h1–h4); override it with `as` (h1–h6) to keep the document outline correct when the visual size and the semantic level differ.",
      "slots": [],
      "variants": [
        {
          "name": "variant",
          "options": [
            "display",
            "headline",
            "title",
            "subtitle"
          ],
          "type": "enum",
          "default": "title"
        }
      ],
      "props": [
        {
          "name": "variant",
          "type": "'display' | 'headline' | 'title' | 'subtitle'",
          "required": false,
          "default": "title",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "as",
          "type": "HeadingLevel",
          "required": false,
          "description": "Heading element to render (`h1`–`h6`). Defaults to the variant's semantic level; set it explicitly to keep the document outline correct when the visual size and the heading level differ.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Heading text.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Header variant=\"title\">label</Header>",
        "<Header variant=\"title\">Front desk overview</Header>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Hero",
      "description": "Hero — a full-width banner that opens a page with a headline, a line of copy, and a call to action, centered over a background. Use it once at the top of a landing or confirmation view to set the scene (a property photo behind a \"your stay is booked\" message); reach for a Card for anything smaller or repeated. Set `overlay` when a background image sits behind the content so the text stays legible, and set the image itself via `className` or `style` on the root. Keep the content to one idea — a heading, a sentence, one primary action.",
      "slots": [
        "root",
        "overlay",
        "content"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root — set the background image here.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the background-image and CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "overlay",
          "type": "boolean",
          "required": false,
          "description": "Render a dimming overlay behind the content — for background images.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The centered banner content (headline, copy, actions).",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Hero>label</Hero>",
        "<Hero\n  overlay\n  className=\"min-h-96\"\n  style={{backgroundImage: 'url(/lobby.jpg)'}}\n>\n  <div className=\"max-w-md text-center text-neutral-content\">\n    <h1 className=\"text-5xl font-bold\">welcome home</h1>\n    <p className=\"py-6\">your keys are ready at the front desk.</p>\n    <Button>check in</Button>\n  </div>\n</Hero>"
      ],
      "dos": [
        "pair `overlay` with a background image so the copy keeps its contrast."
      ],
      "donts": [
        "stack multiple Heroes on one view — one scene-setter per page."
      ]
    },
    {
      "name": "Indicator",
      "description": "Indicator — a wrapper that pins a small badge or dot to a corner of whatever it wraps, so a count or status floats over an avatar, button, or card without shifting the layout. Use it to surface an unread count, a \"new\" flag, or a live status next to the thing it describes; pass the pinned node as `indicator` (usually a Badge) and the anchored content as `children`. Place it with the `vAlign` (top/middle/bottom) and `hAlign` (start/center/end) axes — top-end by default, the conventional notification corner. It only positions; the meaning lives in the node you pin, so keep that label short.",
      "slots": [
        "root",
        "item"
      ],
      "variants": [
        {
          "name": "vAlign",
          "options": [
            "top",
            "middle",
            "bottom"
          ],
          "type": "enum",
          "default": "top"
        },
        {
          "name": "hAlign",
          "options": [
            "start",
            "center",
            "end"
          ],
          "type": "enum",
          "default": "end"
        }
      ],
      "props": [
        {
          "name": "vAlign",
          "type": "'top' | 'middle' | 'bottom'",
          "required": false,
          "default": "top",
          "source": "variant"
        },
        {
          "name": "hAlign",
          "type": "'start' | 'center' | 'end'",
          "required": false,
          "default": "end",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root container.",
          "source": "interface"
        },
        {
          "name": "indicator",
          "type": "React.ReactNode",
          "required": false,
          "description": "The node pinned to a corner — usually a Badge with a count or status dot.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The content the indicator is anchored to.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Indicator vAlign=\"top\" hAlign=\"end\">label</Indicator>",
        "<Indicator indicator={<Badge tone=\"danger\">9+</Badge>}>\n  <Button variant=\"secondary\">inbox</Button>\n</Indicator>"
      ],
      "dos": [
        "Pin one short indicator — a count, a dot, or a word like \"new\"."
      ],
      "donts": [
        "Anchor a full sentence or an interactive control in the indicator slot; it\nfloats over content and should stay a glanceable label."
      ]
    },
    {
      "name": "Input",
      "description": "Input — a single-line text field bound to `value`/`onChange` for capturing short free-form entries such as a name, email, or phone number. Choose the `type` (email, password, number, tel, …) to get the right keyboard and native validation, and set `invalid` to show the error state when validation fails. Size with `sm`/`md`/`lg` to match the surrounding form. Pair it with a form field for the label, help text, and error message; use a Select instead when the value must come from a fixed set of options.",
      "slots": [],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "invalid",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Control height. Defaults to md."
        },
        {
          "name": "invalid",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Marks the field invalid and applies the error style."
        },
        {
          "name": "type",
          "type": "'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date'",
          "required": false,
          "description": "Native input type, narrowed to the supported set.",
          "source": "schema"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the field wrapper.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "icon",
          "type": "React.ReactNode",
          "required": false,
          "description": "Leading icon node the caller supplies.",
          "source": "interface"
        },
        {
          "name": "suffix",
          "type": "React.ReactNode",
          "required": false,
          "description": "Static trailing text, e.g. a unit or \"of 8\".",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Input size=\"md\" />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Join",
      "description": "Join — groups a set of controls into a single segmented unit, squaring the inner corners and collapsing the shared borders so a button cluster or an input + button reads as one control (think a search field with a \"go\" button, or a paginator). Set `orientation` to `vertical` to stack the segments into a column instead of the default row. Join only groups and sets direction: every child supplies its own `join-item` class, either on the raw element or through a library component's `className` passthrough. Reach for it when adjacent controls act as one; use plain spacing when they are independent.",
      "slots": [],
      "variants": [
        {
          "name": "orientation",
          "options": [
            "horizontal",
            "vertical"
          ],
          "type": "enum",
          "default": "horizontal"
        }
      ],
      "props": [
        {
          "name": "orientation",
          "type": "'horizontal' | 'vertical'",
          "required": false,
          "default": "horizontal",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The grouped items — each must carry its own `join-item` class.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Join orientation=\"horizontal\">label</Join>",
        "<Join>\n<button class=\"btn join-item\">prev</button>\n<button class=\"btn join-item\">next</button>\n</Join>"
      ],
      "dos": [
        "give every child a `join-item` class so its corners and borders collapse in"
      ],
      "donts": [
        "use Join to space unrelated controls — it is for items that act as one"
      ]
    },
    {
      "name": "Kbd",
      "description": "Kbd — an inline key cap that shows a single keyboard input inside body copy (e.g. \"press ⌘ K to search\"). Use it in help text, tooltips, and command hints to name a key or a step in a shortcut; chain several with a \"+\" between them for a combination. Pick a `size` to match the surrounding type — xs and sm sit inside dense captions, md (the default) rides normal text, lg suits a standalone hint. It is a label, not a control — use a Button for something a person can click.",
      "slots": [],
      "variants": [
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The key label — a glyph, letter, or short word (e.g. \"⌘\", \"Ctrl\", \"K\").",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Kbd size=\"md\">label</Kbd>",
        "<Kbd>K</Kbd>",
        "<span>press <Kbd>⌘</Kbd> + <Kbd>K</Kbd> to open search</span>"
      ],
      "dos": [
        "use one Kbd per key and a plain \"+\" between them to spell out a combination."
      ],
      "donts": [
        "pack a whole shortcut into one Kbd (\"Ctrl+Shift+P\") — cap one key each."
      ]
    },
    {
      "name": "Label",
      "description": "Label — a short inline text accent rendered in the theme's small type roles. Use `label` (the default) for form-field and control labels, `caption` for secondary helper text beside a value, and `eyebrow` for the uppercase kicker that sits above a heading. It renders a `<span>`, so it stays inline; for a form control's actual `<label>` element, pass it as that field's label.",
      "slots": [],
      "variants": [
        {
          "name": "variant",
          "options": [
            "label",
            "caption",
            "eyebrow"
          ],
          "type": "enum",
          "default": "label"
        }
      ],
      "props": [
        {
          "name": "variant",
          "type": "'label' | 'caption' | 'eyebrow'",
          "required": false,
          "default": "label",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Label text.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Label variant=\"label\">label</Label>",
        "<Label variant=\"eyebrow\">Reservation</Label>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Link",
      "description": "Link — an inline text anchor for navigating somewhere else, whether that's another view, an external page, or an anchor further down the page. Reach for it inside running copy where a Button would feel heavy — \"read the house rules\", \"manage your reservation\". By default it inherits the theme's Cabana color that darkens toward Midnight on hover; set a `tone` to match a feedback context (say `danger` for a cancel-and-lose-your-hold path), and set `hover` to hold the underline until someone hovers, keeping dense copy calm. It's for navigation, not actions — use a Button to submit, save, or trigger something.",
      "slots": [],
      "variants": [
        {
          "name": "tone",
          "options": [
            "brand",
            "secondary",
            "accent",
            "neutral",
            "success",
            "info",
            "warning",
            "danger"
          ],
          "type": "enum"
        },
        {
          "name": "hover",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "tone",
          "type": "'brand' | 'secondary' | 'accent' | 'neutral' | 'success' | 'info' | 'warning' | 'danger'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "hover",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "href",
          "type": "string",
          "required": false,
          "description": "Destination the link points to — the anchor's `href`.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The link text (or nodes) a person clicks.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Link>label</Link>",
        "<Link href=\"/reservations\">manage your reservation</Link>",
        "<Link href=\"/help\" tone=\"accent\" hover>\n  read the house rules\n</Link>"
      ],
      "dos": [
        "Write the link text to describe its destination, so it makes sense on its own."
      ],
      "donts": [
        "Use a Link to trigger an action like submit or delete — reach for a Button."
      ]
    },
    {
      "name": "List",
      "description": "List — a vertical stack of rows that each pair optional media with a title, an optional subtitle, and optional trailing actions. Reach for it to lay out scannable records — reservations, room assignments, folio line items, teammates — where every row shares the same shape. Feed it a `items` array and it renders a divided `<ul>`; the title column grows to fill the width while media and actions hug their content. It is display, not navigation — wrap a row's title or an action in a link or Button when a row should be interactive.",
      "slots": [
        "root",
        "row",
        "media",
        "content",
        "title",
        "subtitle",
        "actions"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root `<ul>` (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly ListItem[]",
          "required": false,
          "description": "Rows to render, in order.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<List />",
        "<List\n  items={[\n    {media: <Avatar />, title: 'ada lovelace', subtitle: 'room 214'},\n    {media: <Avatar />, title: 'alan turing', subtitle: 'room 215'}\n  ]}\n/>"
      ],
      "dos": [
        "give every row the same cells so the columns line up down the list."
      ],
      "donts": [
        "use List for a menu of links — reach for a nav list or Menu instead."
      ]
    },
    {
      "name": "Loading",
      "description": "Loading — an inline, self-animating indicator that signals a short, indefinite wait (fetching a folio, confirming a reservation). Drop it wherever content is pending; pick a `variant` for the shape, a `size` to match the surrounding type, and an optional `tone` to color it — otherwise it inherits the current text color. It carries `role=\"status\"` and an `aria-label` so screen readers announce the wait; keep that label short and specific. For a wait tied to a button press, prefer the Button `loading` prop; reach for Loading when the spinner stands on its own.",
      "slots": [],
      "variants": [
        {
          "name": "variant",
          "options": [
            "spinner",
            "dots",
            "ring",
            "ball",
            "bars",
            "infinity"
          ],
          "type": "enum",
          "default": "spinner"
        },
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "tone",
          "options": [
            "neutral",
            "brand",
            "info",
            "success",
            "warning",
            "danger"
          ],
          "type": "enum"
        }
      ],
      "props": [
        {
          "name": "variant",
          "type": "'spinner' | 'dots' | 'ring' | 'ball' | 'bars' | 'infinity'",
          "required": false,
          "default": "spinner",
          "source": "variant"
        },
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "tone",
          "type": "'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'danger'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Loading variant=\"spinner\" size=\"md\" />",
        "<Loading />",
        "<Loading variant=\"dots\" size=\"lg\" tone=\"brand\" aria-label=\"checking availability\" />"
      ],
      "dos": [
        "use a specific aria-label so the wait is announced meaningfully."
      ],
      "donts": [
        "leave a Loading mounted after the content arrives — unmount it so the\nstatus stops being announced."
      ]
    },
    {
      "name": "Mask",
      "description": "Mask — clips its content to a decorative shape (squircle, circle, hexagon, star, heart, and more). Wrap a photo, avatar, or colored block to soften a grid of thumbnails or dress up a single hero image; the `shape` prop picks the silhouette and the caller sizes the mask through `className` (the clip scales to fit). Reach for `squircle` or `circle` for avatars and headshots, and the playful shapes sparingly for accents. It is pure decoration — never rely on the shape alone to convey meaning.",
      "slots": [],
      "variants": [
        {
          "name": "shape",
          "options": [
            "squircle",
            "heart",
            "hexagon",
            "hexagon2",
            "decagon",
            "pentagon",
            "diamond",
            "circle",
            "star",
            "star2",
            "triangle",
            "triangle2",
            "triangle3",
            "triangle4",
            "half1",
            "half2"
          ],
          "type": "enum",
          "default": "squircle"
        }
      ],
      "props": [
        {
          "name": "shape",
          "type": "'squircle' | 'heart' | 'hexagon' | 'hexagon2' | 'decagon' | 'pentagon' | 'diamond' | 'circle' | 'star' | 'star2' | 'triangle' | 'triangle2' | 'triangle3' | 'triangle4' | 'half1' | 'half2'",
          "required": false,
          "default": "squircle",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root — size the mask here (e.g. `size-16`).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The content to clip: an `<img>`, an avatar, or a colored block.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Mask shape=\"squircle\">label</Mask>",
        "<Mask shape=\"squircle\" className=\"size-16\">\n  <img src=\"/guest.jpg\" alt=\"guest avatar\" />\n</Mask>"
      ],
      "dos": [
        "wrap an `<img>` or a sized block and let `className` set the dimensions."
      ],
      "donts": [
        "use a mask to hint at status or state — pair it with a label instead."
      ]
    },
    {
      "name": "Menu",
      "description": "Menu — a vertical (or horizontal) list of navigation rows: links, section titles, and parents that reveal a nested submenu. Feed it an `items` tree and it renders the DaisyUI markup for you, marking the current row with `active`, dimming unavailable rows with `disabled`, and grouping rows under a `title` heading. Use it for sidebars, account navs, and folio sections; pick an `orientation` and `size` to fit the surface. Submenus are native `<details>` disclosures, so they expand and collapse by keyboard and pointer without extra wiring. Keep labels short and verb- or noun-first (check in, room keys, folio).",
      "slots": [
        "root",
        "title"
      ],
      "variants": [
        {
          "name": "orientation",
          "options": [
            "vertical",
            "horizontal"
          ],
          "type": "enum",
          "default": "vertical"
        },
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        }
      ],
      "props": [
        {
          "name": "orientation",
          "type": "'vertical' | 'horizontal'",
          "required": false,
          "default": "vertical",
          "source": "variant"
        },
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root list (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly MenuItem[]",
          "required": false,
          "description": "The rows to render, nested via each row's own `items`.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Menu orientation=\"vertical\" size=\"md\" />",
        "<Menu\n  items={[\n    {title: true, label: 'stay'},\n    {label: 'reservation', href: '#', active: true},\n    {\n      label: 'folio',\n      items: [\n        {label: 'charges', href: '#'},\n        {label: 'payments', href: '#'}\n      ]\n    },\n    {label: 'archived', href: '#', disabled: true}\n  ]}\n/>"
      ],
      "dos": [
        "keep one row `active` so people always know where they are."
      ],
      "donts": [
        "use Menu for a set of actions — reach for Button or Dropdown instead."
      ]
    },
    {
      "name": "MockupBrowser",
      "description": "MockupBrowser — a decorative browser frame that wraps a screenshot or live preview in familiar window chrome, complete with a toolbar and address field. Use it in docs, marketing, and onboarding to show what a page looks like in a real browser without a real browser. Pass a `url` to label the address bar (e.g. a booking or check-in link) and put the page itself in `children`. It is a frame, not a viewport — it renders whatever you give it and adds no behavior.",
      "slots": [
        "root",
        "toolbar",
        "address"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root frame (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "url",
          "type": "string",
          "required": false,
          "description": "Address shown in the toolbar field. Omit to render a chrome-only frame.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The page content displayed inside the frame.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<MockupBrowser>label</MockupBrowser>",
        "<MockupBrowser url=\"https://placemakr.com\">\n  <div className=\"flex justify-center p-8\">welcome to your stay</div>\n</MockupBrowser>"
      ],
      "dos": [
        "wrap a screenshot or a small live preview to show it in context."
      ],
      "donts": [
        "use it as an actual browser or iframe — it renders content, nothing more."
      ]
    },
    {
      "name": "MockupCode",
      "description": "MockupCode — a terminal-style frame that shows a short block of commands or code, complete with the window chrome and a gutter for per-line prefixes. Use it in docs and onboarding to demonstrate a command someone runs (`$ yarn install`) or the output they should expect; pass a `prefix` per line for the `$`/`>` markers and a `className` like `text-warning` to tint a status line. It is illustrative, not interactive — reach for a real code editor or copyable snippet when people need to run the commands themselves.",
      "slots": [
        "root",
        "line",
        "code"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root frame.",
          "source": "interface"
        },
        {
          "name": "lines",
          "type": "readonly CodeLine[]",
          "required": false,
          "description": "Lines to render, top to bottom.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<MockupCode />",
        "<MockupCode\n  lines={[\n    {prefix: '$', content: 'yarn add daisyui'},\n    {prefix: '>', content: 'installing…', className: 'text-warning'},\n    {prefix: '>', content: 'done', className: 'text-success'}\n  ]}\n/>"
      ],
      "dos": [
        "Keep each line short and give status lines a semantic text class so the\noutcome reads at a glance."
      ],
      "donts": [
        "Use it as an editable input — it only displays; wire a real control when\npeople must type or copy."
      ]
    },
    {
      "name": "MockupPhone",
      "description": "MockupPhone — a phone-shaped device frame that wraps a preview so a screen looks like it is running on a handset. Use it in marketing pages, onboarding tours, or a styleguide to show a mobile flow in context — a booking confirmation, the room keys screen, a folio — without hand-drawing a bezel. Drop any content in as `children`: a screenshot `<img>`, an embedded page, or live components; the frame clips it to the rounded display and adds the camera notch. It is pure chrome, not an interactive control, so it carries no color axis — the screen supplies all the color.",
      "slots": [
        "root",
        "camera",
        "display"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the phone frame (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Screen content rendered inside the phone display (a screenshot, an image, or live UI).",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<MockupPhone>label</MockupPhone>",
        "<MockupPhone><img src=\"/booking.png\" alt=\"booking confirmation\" /></MockupPhone>"
      ],
      "dos": [
        "fill the display edge to edge so the content reaches the rounded corners"
      ],
      "donts": [
        "hard-code the frame color — the device chrome is themed; retint via the theme"
      ]
    },
    {
      "name": "MockupWindow",
      "description": "MockupWindow — a browser/app window frame for showing a screenshot or a live UI preview in context, complete with the title-bar dots. Use it in docs, onboarding, or marketing surfaces to present a screen as if captured in its own window — for example framing the guest check-in flow or a folio summary. Drop the content in as `children` and shape the inner panel (centering, height, padding) with `contentClassName`. It is a static frame, not an interactive window — the dots are decorative, so use real controls for anything a person needs to act on.",
      "slots": [
        "root",
        "content"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the window frame (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "contentClassName",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the inner content panel — set layout, height, or padding here.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "What the window frames — a screenshot, UI preview, or any node.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<MockupWindow>label</MockupWindow>",
        "<MockupWindow contentClassName=\"grid place-content-center h-40\">\n  welcome to your stay\n</MockupWindow>"
      ],
      "dos": [
        "frame a screenshot or live UI preview to show a screen in context."
      ],
      "donts": [
        "rely on the title dots as controls — they are decorative, not buttons."
      ]
    },
    {
      "name": "Navbar",
      "description": "Navbar — the horizontal bar across the top of a view that holds the brand, the primary navigation, and account or page actions. Fill any of three regions — `start`, `center`, `end` — and the bar spaces them apart; a region stays out of the DOM until you give it content, so a brand-plus-actions bar needs only `start` and `end`. It renders as a labelled navigation landmark, so drop links, a Button, or a Dropdown straight in. Keep it to one per view and reserve the `center` slot for a title or the main links, not a second row of actions.",
      "slots": [
        "root",
        "start",
        "center",
        "end"
      ],
      "variants": [],
      "props": [
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "start",
          "type": "React.ReactNode",
          "required": false,
          "description": "Leading region — brand, logo, or a menu toggle. Aligned to the start edge.",
          "source": "interface"
        },
        {
          "name": "center",
          "type": "React.ReactNode",
          "required": false,
          "description": "Middle region — a title or primary links. Sized to its content.",
          "source": "interface"
        },
        {
          "name": "end",
          "type": "React.ReactNode",
          "required": false,
          "description": "Trailing region — actions, search, or the account menu. Aligned to the end edge.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Navbar />",
        "<Navbar\n  start={<span className=\"text-lg font-semibold\">Placemakr</span>}\n  end={<Button size=\"sm\">check in</Button>}\n/>"
      ],
      "dos": [
        "Reserve a single Navbar for the top of a view and let empty regions stay unset."
      ],
      "donts": [
        "Stack two Navbars or cram actions into `center` — use `start`/`end` for those."
      ]
    },
    {
      "name": "Pagination",
      "description": "Pagination — lets a person move through a long, paged list (search results, a reservations table, an activity log) one page at a time. It renders a joined row of page buttons: the first and last page always show, a window sits around the current page, and `…` fills any gap so the control stays compact at scale. It is controlled — pass the current `page` and update it from `onPageChange` — and `siblingCount` widens the window around the current page. Size with `sm`/`md`/`lg` to match the surrounding density. The active page is marked with `aria-current=\"page\"` and the whole row is a labelled navigation landmark, so it is screen-reader-accessible by default.",
      "slots": [
        "root",
        "item"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root join container.",
          "source": "interface"
        },
        {
          "name": "count",
          "type": "number",
          "required": true,
          "description": "Total number of pages.",
          "source": "interface"
        },
        {
          "name": "page",
          "type": "number",
          "required": true,
          "description": "The current page, 1-based.",
          "source": "interface"
        },
        {
          "name": "onPageChange",
          "type": "(page: number) => void",
          "required": false,
          "description": "Called with the requested page when a page button is pressed.",
          "source": "interface"
        },
        {
          "name": "siblingCount",
          "type": "number",
          "required": false,
          "description": "Pages to show on each side of the current page before an ellipsis.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Pagination size=\"md\" />",
        "<Pagination count={12} page={page} onPageChange={setPage} />"
      ],
      "dos": [
        "keep Pagination controlled — drive `page` from state and update it in `onPageChange`"
      ],
      "donts": [
        "hard-code colors — retint the active page via the theme or the `style` override channel"
      ]
    },
    {
      "name": "Progress",
      "description": "Progress — a slim horizontal bar that shows how far along a task is, from an upload to a multi-step check-in flow. Give it a `value` from 0 to `max` (100 by default) to fill the track; omit `value` for an indeterminate bar that animates while the amount of work is still unknown. Choose a `tone` to match the context — primary for a neutral task, success when it is nearly done, warning or danger to flag trouble. It is a status display, not a control — pair it with nearby text for the exact numbers.",
      "slots": [],
      "variants": [
        {
          "name": "tone",
          "options": [
            "primary",
            "secondary",
            "accent",
            "info",
            "success",
            "warning",
            "danger"
          ],
          "type": "enum",
          "default": "primary"
        }
      ],
      "props": [
        {
          "name": "tone",
          "type": "'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'danger'",
          "required": false,
          "default": "primary",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "value",
          "type": "number",
          "required": false,
          "description": "How far along the task is, from 0 to `max`. Omit it for an indeterminate bar that animates while the amount of work is still unknown.",
          "source": "interface"
        },
        {
          "name": "max",
          "type": "number",
          "required": false,
          "description": "The value that represents a full bar. Defaults to 100.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Progress tone=\"primary\" />",
        "<Progress value={70} />",
        "<Progress tone=\"success\" value={100} />",
        "<Progress aria-label=\"loading availability\" />"
      ],
      "dos": [
        "give an indeterminate bar an `aria-label` so its purpose is announced."
      ],
      "donts": [
        "use Progress for a value a person can drag — reach for Range instead."
      ]
    },
    {
      "name": "RadialProgress",
      "description": "RadialProgress — a circular gauge that shows how far along a value is, from 0 to 100 (e.g. profile completeness, an upload, nights checked in). Pass `value` and it fills the ring and prints the percentage in the center; supply `children` to label it with something else, and `size`/`thickness` to fit the surface. Choose a `tone` to signal meaning — the ring paints with the theme color, so no colors are hard-coded. It reports progress as an ARIA `progressbar`; it is a display, not a control — use a slider for input.",
      "slots": [],
      "variants": [
        {
          "name": "tone",
          "options": [
            "brand",
            "info",
            "success",
            "warning",
            "danger"
          ],
          "type": "enum",
          "default": "brand"
        }
      ],
      "props": [
        {
          "name": "tone",
          "type": "'brand' | 'info' | 'success' | 'warning' | 'danger'",
          "required": false,
          "default": "brand",
          "source": "variant"
        },
        {
          "name": "value",
          "type": "number",
          "required": true,
          "description": "Completion from 0 to 100 — drives the `--value` custom property and the ring fill.",
          "source": "interface"
        },
        {
          "name": "size",
          "type": "string",
          "required": false,
          "description": "Overall diameter as a CSS length (e.g. `'6rem'`) → the `--size` custom property.",
          "source": "interface"
        },
        {
          "name": "thickness",
          "type": "string",
          "required": false,
          "description": "Ring thickness as a CSS length (e.g. `'4px'`) → the `--thickness` custom property.",
          "source": "interface"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Center label; defaults to `${value}%` when omitted.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<RadialProgress tone=\"brand\">label</RadialProgress>",
        "<RadialProgress value={70} />",
        "<RadialProgress value={40} tone=\"success\" size=\"6rem\" thickness=\"4px\">\n  40%\n</RadialProgress>"
      ],
      "dos": [
        "Keep `value` between 0 and 100 and let the center label read as a percentage."
      ],
      "donts": [
        "Use it for indeterminate work with no known percentage — use a spinner instead."
      ]
    },
    {
      "name": "Radio",
      "description": "Radio — a single control for a one-of-many choice, such as picking a rate plan or a room type. Use it when exactly one option in a set may be selected; for an independent on/off choice use a checkbox, and for a compact setting consider a switch. Radios are grouped by sharing the native `name` prop across the set, so selecting one clears the rest. Pair each with a `label`, and a `description` when the option needs a line of explanation.",
      "slots": [
        "root",
        "control",
        "label",
        "labelText",
        "description"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "tone",
          "options": [
            "primary",
            "secondary",
            "accent",
            "neutral",
            "info",
            "success",
            "warning",
            "error"
          ],
          "type": "enum",
          "default": "primary"
        },
        {
          "name": "invalid",
          "options": [],
          "type": "boolean"
        },
        {
          "name": "disabled",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Control size. Defaults to md."
        },
        {
          "name": "tone",
          "type": "'primary' | 'secondary' | 'accent' | 'neutral' | 'info' | 'success' | 'warning' | 'error'",
          "required": false,
          "default": "primary",
          "source": "variant",
          "description": "Color role for the control. Defaults to primary."
        },
        {
          "name": "invalid",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Marks the control invalid and applies the error style."
        },
        {
          "name": "disabled",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Disables the control."
        },
        {
          "name": "checked",
          "type": "boolean",
          "required": false,
          "description": "Controlled checked state.",
          "source": "schema"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root label.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "label",
          "type": "React.ReactNode",
          "required": false,
          "description": "Label beside the control.",
          "source": "interface"
        },
        {
          "name": "description",
          "type": "React.ReactNode",
          "required": false,
          "description": "Secondary line under the label.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(checked: boolean) => void",
          "required": false,
          "description": "Reports the new checked state.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Radio size=\"md\" tone=\"primary\" />",
        "<Radio name=\"bed\" value=\"king\" label=\"king\" defaultChecked />\n<Radio name=\"bed\" value=\"queen\" label=\"queen\" />"
      ],
      "dos": [
        "Give every radio in a group the same `name` so they behave as one set."
      ],
      "donts": [
        "Use a radio for a standalone yes/no — reach for a checkbox or toggle."
      ]
    },
    {
      "name": "Range",
      "description": "Range — a slider for picking a single number from a continuous span, such as a price ceiling, a party size, or a number of nights. Set `min`/`max`/`step` to bound and quantize the values, and read the choice through `onChange`, which hands back a plain number. Size with `xs`/`sm`/`md`/`lg` to match the surrounding form, and give it a `tone` to tint the filled track and thumb with a color role. Reach for a Range when the exact figure matters less than the sense of more-or-less; use an Input of type number when a person needs to type a precise value. Pair it with a form field for the label and a live read-out of the current value.",
      "slots": [],
      "variants": [
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "tone",
          "options": [
            "primary",
            "secondary",
            "accent",
            "success",
            "warning",
            "info",
            "error"
          ],
          "type": "enum"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Track and thumb size. Defaults to md."
        },
        {
          "name": "tone",
          "type": "'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'info' | 'error'",
          "required": false,
          "source": "variant",
          "description": "Color role for the filled track and thumb."
        },
        {
          "name": "disabled",
          "type": "boolean",
          "required": false,
          "description": "Disables the slider.",
          "source": "schema"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the slider.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(value: number) => void",
          "required": false,
          "description": "Reports the new value as a number (`event.target.valueAsNumber`).",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Range size=\"md\" />",
        "<Range min={1} max={7} defaultValue={3} onChange={setNights} />",
        "<Range tone=\"primary\" min={0} max={500} step={25} defaultValue={250} />"
      ],
      "dos": [
        "Show the current value next to the slider so the choice is legible."
      ],
      "donts": [
        "Use a Range for a value that must be exact — offer a number Input instead."
      ]
    },
    {
      "name": "Rating",
      "description": "Rating — a row of stars for capturing or showing a score, such as how a guest rated their stay. Use it for a small, bounded scale (typically five) where the shape carries the meaning at a glance; for longer or non-symbolic scales reach for a slider or a select. It is a controlled input: pass `value` and handle `onChange`, which fires the chosen number. A leading clear input lets someone reset to no rating (`0`), `half` enables half-star precision, and `shape` swaps stars for hearts when you want a favorite rather than a score. Each star is a real radio sharing one group name, so it is keyboard- and screen-reader-friendly.",
      "slots": [
        "root",
        "item"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "shape",
          "options": [
            "star",
            "heart"
          ],
          "type": "enum",
          "default": "star"
        },
        {
          "name": "half",
          "options": [],
          "type": "boolean"
        },
        {
          "name": "disabled",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Star size. Defaults to md."
        },
        {
          "name": "shape",
          "type": "'star' | 'heart'",
          "required": false,
          "default": "star",
          "source": "variant",
          "description": "Item mask shape. Defaults to star."
        },
        {
          "name": "half",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Allows half-star selection in 0.5 steps."
        },
        {
          "name": "disabled",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Disables the control and dims it."
        },
        {
          "name": "value",
          "type": "number",
          "required": false,
          "description": "Controlled rating value; 0 clears the selection.",
          "source": "schema"
        },
        {
          "name": "max",
          "type": "number",
          "required": false,
          "description": "Number of stars to render. Defaults to 5.",
          "source": "schema"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root container.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "clearable",
          "type": "boolean",
          "required": false,
          "description": "Renders a leading input that resets the value to 0. Defaults to true.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(value: number) => void",
          "required": false,
          "description": "Reports the newly selected value.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Rating size=\"md\" shape=\"star\" />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Select",
      "description": "Select — a dropdown for choosing one value from a fixed set of options (an arrival window, a room type, a status). Use it when the options are known and mutually exclusive and there are more than a couple of them; for two or three choices consider radios, and for many searchable options a typeahead. Pass `options` as strings or `{value, label}` pairs and a `placeholder` for the empty prompt, and set `invalid` to show the error state. Pair it with a form field for the label and error surface.",
      "slots": [],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "invalid",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Control height. Defaults to md."
        },
        {
          "name": "invalid",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Marks the field invalid and applies the error style."
        },
        {
          "name": "placeholder",
          "type": "string",
          "required": false,
          "description": "Empty-value first option, e.g. \"choose a time\".",
          "source": "schema"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "options",
          "type": "readonly (string | SelectOption)[]",
          "required": false,
          "description": "Options as bare strings or `{value, label}` pairs.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Custom `<option>` children instead of (or after) `options`.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Select size=\"md\">label</Select>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Skeleton",
      "description": "Skeleton — a shimmering placeholder that stands in for content while it loads, so the layout holds its shape instead of jumping when data arrives. Size it with `className` (Tailwind width/height/rounded utilities) to mirror the real element it replaces — a line of text, an avatar, a card — and set `shape=\"circle\"` for round placeholders. Render one per incoming element and swap it for the real content once loaded; it is purely decorative, marked `aria-busy` so assistive tech announces the pending state rather than reading an empty box.",
      "slots": [],
      "variants": [
        {
          "name": "shape",
          "options": [
            "rect",
            "circle"
          ],
          "type": "enum",
          "default": "rect"
        }
      ],
      "props": [
        {
          "name": "shape",
          "type": "'rect' | 'circle'",
          "required": false,
          "default": "rect",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root — size the placeholder here (`h-32 w-full`, `size-12`, `rounded-lg`).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Optional content to reserve space around; a Skeleton is usually empty.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Skeleton shape=\"rect\">label</Skeleton>",
        "<Skeleton className=\"h-32 w-full\" />",
        "<Skeleton shape=\"circle\" className=\"size-16\" />"
      ],
      "dos": [
        "Match the Skeleton's size to the content it replaces so nothing shifts on load."
      ],
      "donts": [
        "Leave a Skeleton on screen after the data resolves — always swap it for the real element."
      ]
    },
    {
      "name": "Stack",
      "description": "Stack — a layout container that lays its children in one cell so they overlap, front to back, with the ones behind peeking out. Use it to imply a pile or a count without a real list: a shuffle of key cards, a run of notification toasts, a couple of stacked receipts on a folio. The first child sits on top; give `placement` an edge (top, bottom, start, end) to choose which way the layers behind fan out. It is decorative arrangement, not a carousel — reach for a proper list or Carousel when the layers need to be read or navigated.",
      "slots": [],
      "variants": [
        {
          "name": "placement",
          "options": [
            "top",
            "bottom",
            "start",
            "end"
          ],
          "type": "enum"
        }
      ],
      "props": [
        {
          "name": "placement",
          "type": "'top' | 'bottom' | 'start' | 'end'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The overlapping layers, front-most first.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Stack>label</Stack>",
        "<Stack>\n  <div className=\"card bg-primary text-primary-content p-4\">room 412</div>\n  <div className=\"card bg-secondary text-secondary-content p-4\">room 413</div>\n  <div className=\"card bg-accent text-accent-content p-4\">room 414</div>\n</Stack>"
      ],
      "dos": [
        "use it for a small pile of like items where the depth is the message."
      ],
      "donts": [
        "use it to overlap unrelated content — that is a job for absolute layout."
      ]
    },
    {
      "name": "Stat",
      "description": "Stat — a compact group of headline metrics, each a title, a big value, and an optional supporting line. Use it to surface the numbers that matter at a glance — occupancy, revenue, nights booked — across the top of a dashboard or summary. Pass `orientation=\"vertical\"` to stack the blocks in a narrow column instead of flowing them across. Hang an icon or badge off `figure` to give a metric a visual anchor. Keep titles short and lowercase, and let the value do the talking.",
      "slots": [
        "root",
        "item",
        "figure",
        "title",
        "value",
        "desc"
      ],
      "variants": [
        {
          "name": "orientation",
          "options": [
            "horizontal",
            "vertical"
          ],
          "type": "enum",
          "default": "horizontal"
        }
      ],
      "props": [
        {
          "name": "orientation",
          "type": "'horizontal' | 'vertical'",
          "required": false,
          "default": "horizontal",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root container.",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly StatItem[]",
          "required": false,
          "description": "Metric blocks to render.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Stat orientation=\"horizontal\" />",
        "<Stat\n  items={[\n    {title: 'occupancy', value: '92%', desc: '4% more than last week'},\n    {title: 'nights booked', value: '1,204', desc: 'since check-in opened'}\n  ]}\n/>"
      ],
      "dos": [
        "keep titles to a couple of words so the value stays the focal point."
      ],
      "donts": [
        "crowd a single group with more than four or five metrics — split them."
      ]
    },
    {
      "name": "Status",
      "description": "Status — a tiny inline dot that signals the live state of a nearby thing (e.g. a room is available, a guest is checked in, a sync is running). Use it beside a label, avatar, or list row to surface state at a glance without taking up space. Choose a `tone` to carry the meaning and a `size` to match the type around it. It is a decorative indicator with no text of its own, so always give it an `aria-label`; for an action use a Button, and for a labelled tag use a Badge.",
      "slots": [],
      "variants": [
        {
          "name": "tone",
          "options": [
            "neutral",
            "brand",
            "secondary",
            "accent",
            "info",
            "success",
            "warning",
            "danger"
          ],
          "type": "enum",
          "default": "neutral"
        },
        {
          "name": "size",
          "options": [
            "xs",
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        }
      ],
      "props": [
        {
          "name": "tone",
          "type": "'neutral' | 'brand' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'danger'",
          "required": false,
          "default": "neutral",
          "source": "variant"
        },
        {
          "name": "size",
          "type": "'xs' | 'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Status tone=\"neutral\" size=\"md\" />",
        "<Status tone=\"success\" aria-label=\"room is available\" />",
        "<Status tone=\"warning\" size=\"lg\" aria-label=\"cleaning in progress\" />"
      ],
      "dos": [
        "pair every Status with an aria-label so its meaning reaches assistive tech."
      ],
      "donts": [
        "stretch a Status to convey a count or a word — reach for a Badge instead."
      ]
    },
    {
      "name": "Steps",
      "description": "Steps — an ordered tracker that shows where someone is in a multi-part flow and how much is left, laid out as numbered nodes joined by connectors. Reach for it on a checkout, onboarding, or check-in wizard so people can see the whole path at a glance. Pass `items` for the sequence and `current` to mark the active step — every step up to and including it takes the `tone` color, the rest stay muted. Set `orientation` to `vertical` for a stacked layout in narrow columns, and give an item an `icon` to replace its auto number with a glyph. It is a status display, not a set of controls — use Tabs or a Button when a person needs to move between steps directly.",
      "slots": [
        "root",
        "item"
      ],
      "variants": [
        {
          "name": "orientation",
          "options": [
            "horizontal",
            "vertical"
          ],
          "type": "enum",
          "default": "horizontal"
        },
        {
          "name": "tone",
          "options": [
            "primary",
            "secondary",
            "accent",
            "info",
            "success",
            "warning",
            "error"
          ],
          "type": "enum"
        }
      ],
      "props": [
        {
          "name": "orientation",
          "type": "'horizontal' | 'vertical'",
          "required": false,
          "default": "horizontal",
          "source": "variant"
        },
        {
          "name": "tone",
          "type": "'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly StepItem[]",
          "required": false,
          "description": "Ordered steps to render.",
          "source": "interface"
        },
        {
          "name": "current",
          "type": "number",
          "required": false,
          "description": "0-based index of the active step; steps with index ≤ current get the tone color.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Steps orientation=\"horizontal\" />",
        "<Steps\n  current={1}\n  items={[\n    {label: 'reserve'},\n    {label: 'check in'},\n    {label: 'room keys'}\n  ]}\n/>"
      ],
      "dos": [
        "Keep labels to a word or two so the horizontal track stays readable."
      ],
      "donts": [
        "Use Steps to navigate between screens — it reports progress, it does not control it."
      ]
    },
    {
      "name": "Swap",
      "description": "Swap — a single control that flips between two faces in place, such as play/pause, menu/close, or a lights-on/lights-off setting. Use it when one tap moves between two mirrored states and you want the transition to read as motion rather than a jump; for a labelled on/off form setting reach for a toggle instead. Choose the `effect` axis to spin the faces (`rotate`, the default) or turn them over (`flip`). It drives a real hidden checkbox, so it toggles on click and by keyboard and reports back through `onChange`. Keep the two faces the same size so nothing shifts as they trade places.",
      "slots": [
        "root",
        "on",
        "off",
        "indeterminate"
      ],
      "variants": [
        {
          "name": "effect",
          "options": [
            "rotate",
            "flip"
          ],
          "type": "enum",
          "default": "rotate"
        }
      ],
      "props": [
        {
          "name": "effect",
          "type": "'rotate' | 'flip'",
          "required": false,
          "default": "rotate",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root label.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "on",
          "type": "React.ReactNode",
          "required": true,
          "description": "Face shown when active.",
          "source": "interface"
        },
        {
          "name": "off",
          "type": "React.ReactNode",
          "required": true,
          "description": "Face shown when inactive.",
          "source": "interface"
        },
        {
          "name": "active",
          "type": "boolean",
          "required": false,
          "description": "Controlled active state; pair with `onChange`.",
          "source": "interface"
        },
        {
          "name": "defaultActive",
          "type": "boolean",
          "required": false,
          "description": "Uncontrolled initial active state.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(active: boolean) => void",
          "required": false,
          "description": "Reports the new active state on toggle.",
          "source": "interface"
        },
        {
          "name": "indeterminate",
          "type": "React.ReactNode",
          "required": false,
          "description": "Optional third face shown while the checkbox is indeterminate.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Swap effect=\"rotate\" />",
        "<Swap on=\"ON\" off=\"OFF\" defaultActive />",
        "<Swap\n  effect=\"flip\"\n  active={open}\n  onChange={setOpen}\n  on={<CloseIcon />}\n  off={<MenuIcon />}\n/>"
      ],
      "dos": [
        "Keep both faces the same footprint so the toggle stays put as it swaps."
      ],
      "donts": [
        "Reach for Swap to collect a form value — use a toggle or checkbox."
      ]
    },
    {
      "name": "Tabs",
      "description": "Tabs — a horizontal set of views that share a region, where selecting a tab swaps the panel below it. Use tabs to divide related content into a few peer sections the user moves between (arrivals / departures / in-house) without leaving the page; don't use them for sequential steps — use a stepper — or for primary navigation. Choose the `underline` variant for in-page section switching and `pill` for a more contained, toolbar-like grouping. Left/Right and Home/End move focus and selection between enabled tabs, following the ARIA tablist pattern.",
      "slots": [
        "list",
        "tab",
        "panel"
      ],
      "variants": [
        {
          "name": "variant",
          "options": [
            "underline",
            "pill"
          ],
          "type": "enum",
          "default": "underline"
        }
      ],
      "props": [
        {
          "name": "variant",
          "type": "'underline' | 'pill'",
          "required": false,
          "default": "underline",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the tablist container.",
          "source": "interface"
        },
        {
          "name": "tabs",
          "type": "readonly TabItem[]",
          "required": false,
          "description": "The tabs to render.",
          "source": "interface"
        },
        {
          "name": "selected",
          "type": "string",
          "required": false,
          "description": "Controlled active tab id.",
          "source": "interface"
        },
        {
          "name": "defaultSelected",
          "type": "string",
          "required": false,
          "description": "Initial active tab id when uncontrolled.",
          "source": "interface"
        },
        {
          "name": "onSelect",
          "type": "(id: string) => void",
          "required": false,
          "description": "Called with the newly selected tab id.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Tabs variant=\"underline\" />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Textarea",
      "description": "Textarea — a multi-line text field bound to `value`/`onChange` for capturing longer free-form entries such as a guest note, special request, or feedback. Set `rows` to size the visible height, and set `invalid` to show the error state when validation fails. Size with `sm`/`md`/`lg` to match the surrounding form. Pair it with a form field for the label, help text, and error message; use an Input instead when a single line is enough.",
      "slots": [],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "invalid",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Control height. Defaults to md."
        },
        {
          "name": "invalid",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Marks the field invalid and applies the error style."
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the field.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Textarea size=\"md\" />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "TextBlock",
      "description": "TextBlock — a paragraph of body copy rendered in the theme's body type roles. Use it for readable running text — descriptions, help text, empty-state explanations. `regular` is the default; `small` steps the size down for dense or secondary passages. It renders a `<p>`, so use one TextBlock per paragraph rather than stacking line breaks.",
      "slots": [],
      "variants": [
        {
          "name": "variant",
          "options": [
            "regular",
            "small"
          ],
          "type": "enum",
          "default": "regular"
        }
      ],
      "props": [
        {
          "name": "variant",
          "type": "'regular' | 'small'",
          "required": false,
          "default": "regular",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Paragraph content.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<TextBlock variant=\"regular\">label</TextBlock>",
        "<TextBlock variant=\"regular\">Guest arriving at 3:00pm.</TextBlock>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Timeline",
      "description": "Timeline — an ordered track of events connected by a running line, each with an icon on the line and detail to one or both sides. Use it to show a sequence in time (a reservation's lifecycle, a stay's check-in to check-out, a delivery's status) so people can follow what happened and what comes next. Feed it an `items` array: each event supplies a `start` label, a `middle` marker, and an `end` detail, and the connectors between events are drawn for you. Set `orientation` to run it horizontally, `compact` to keep every event on one side, and clear an item's `boxed` flag when its detail should sit inline instead of in a card. It is read-only structure, not a control — reach for Steps when a person is moving through a process.",
      "slots": [
        "root",
        "item",
        "start",
        "middle",
        "end"
      ],
      "variants": [
        {
          "name": "orientation",
          "options": [
            "vertical",
            "horizontal"
          ],
          "type": "enum",
          "default": "vertical"
        },
        {
          "name": "compact",
          "options": [],
          "type": "boolean"
        },
        {
          "name": "boxed",
          "options": [],
          "type": "boolean",
          "default": "true"
        }
      ],
      "props": [
        {
          "name": "orientation",
          "type": "'vertical' | 'horizontal'",
          "required": false,
          "default": "vertical",
          "source": "variant",
          "description": "Run the track down the page or across it; defaults to `vertical`."
        },
        {
          "name": "compact",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Collapse each event to one side of the connector."
        },
        {
          "name": "boxed",
          "type": "boolean",
          "required": false,
          "default": "true",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "items",
          "type": "readonly TimelineItem[]",
          "required": false,
          "description": "Ordered events to render along the track.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Timeline orientation=\"vertical\" boxed />"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Toast",
      "description": "Toast — a brief, self-dismissing notification that confirms the result of an action (\"request sent\", \"changes saved\") without interrupting what the user is doing. Use it for transient, low-stakes feedback that does not need acknowledgement; for information that must persist on the page use an Alert, and for a decision that must block the flow use a Dialog. Set the `tone` to match the outcome and keep the message to one short line, optionally with a single inline action such as undo.",
      "slots": [],
      "variants": [
        {
          "name": "tone",
          "options": [
            "info",
            "success",
            "warning",
            "danger",
            "brand"
          ],
          "type": "enum",
          "default": "success"
        }
      ],
      "props": [
        {
          "name": "tone",
          "type": "'info' | 'success' | 'warning' | 'danger' | 'brand'",
          "required": false,
          "default": "success",
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "message",
          "type": "React.ReactNode",
          "required": false,
          "description": "One short past-tense line: \"request sent to the front desk\".",
          "source": "interface"
        },
        {
          "name": "action",
          "type": "React.ReactNode",
          "required": false,
          "description": "Optional inline action — usually a ghost Button (e.g. undo).",
          "source": "interface"
        },
        {
          "name": "onDismiss",
          "type": "() => void",
          "required": false,
          "description": "Renders a dismiss control that calls this handler.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "Body, when richer than `message`.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Toast tone=\"success\">label</Toast>"
      ],
      "dos": [],
      "donts": []
    },
    {
      "name": "Toggle",
      "description": "Toggle — a switch for a setting that takes effect immediately, such as turning on housekeeping alerts or opting into text updates. Reach for it when the choice is a self-contained on/off with an obvious default; for choosing among options use radio controls, and for a boolean that only applies once a form is submitted prefer a checkbox. Tint the checked track with `tone` to match the surrounding context, and pair it with a `label`, adding a `description` when the setting needs a line of explanation.",
      "slots": [
        "root",
        "control",
        "label",
        "labelText",
        "description"
      ],
      "variants": [
        {
          "name": "size",
          "options": [
            "sm",
            "md",
            "lg"
          ],
          "type": "enum",
          "default": "md"
        },
        {
          "name": "tone",
          "options": [
            "primary",
            "secondary",
            "accent",
            "success",
            "warning",
            "info",
            "error"
          ],
          "type": "enum",
          "default": "primary"
        },
        {
          "name": "disabled",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "size",
          "type": "'sm' | 'md' | 'lg'",
          "required": false,
          "default": "md",
          "source": "variant",
          "description": "Control size. Defaults to md."
        },
        {
          "name": "tone",
          "type": "'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'info' | 'error'",
          "required": false,
          "default": "primary",
          "source": "variant",
          "description": "Color role for the checked track. Defaults to primary."
        },
        {
          "name": "disabled",
          "type": "boolean",
          "required": false,
          "source": "variant",
          "description": "Disables the control."
        },
        {
          "name": "checked",
          "type": "boolean",
          "required": false,
          "description": "Controlled on/off state.",
          "source": "schema"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root label.",
          "source": "interface"
        },
        {
          "name": "style",
          "type": "React.CSSProperties",
          "required": false,
          "description": "Inline style — the CSS-variable override channel.",
          "source": "interface"
        },
        {
          "name": "label",
          "type": "React.ReactNode",
          "required": false,
          "description": "Label beside the switch.",
          "source": "interface"
        },
        {
          "name": "description",
          "type": "React.ReactNode",
          "required": false,
          "description": "Secondary line under the label.",
          "source": "interface"
        },
        {
          "name": "onChange",
          "type": "(checked: boolean) => void",
          "required": false,
          "description": "Reports the new on/off state.",
          "source": "interface"
        }
      ],
      "schemaValidated": true,
      "examples": [
        "<Toggle size=\"md\" tone=\"primary\" />",
        "<Toggle label=\"Housekeeping alerts\" defaultChecked />",
        "<Toggle\n  tone=\"success\"\n  label=\"Text me room updates\"\n  description=\"We'll text when your room is ready.\"\n  onChange={on => setSmsOptIn(on)}\n/>"
      ],
      "dos": [
        "Use a Toggle for settings that apply the moment they change."
      ],
      "donts": [
        "Use a Toggle inside a form where the value only matters on submit — use a Checkbox."
      ]
    },
    {
      "name": "Tooltip",
      "description": "Tooltip — a small hover/focus hint that explains the trigger it wraps (e.g. a terse icon button, a truncated folio line, a status badge). Wrap the trigger as `children` and pass the hint as `tip`; a string tip rides the `data-tip` attribute, while a richer node renders in a `.tooltip-content` bubble. Move it with `placement`, colour it with `tone` to echo the surface it annotates, and set `open` to pin it visible for a walkthrough or a screenshot. Keep tips to a phrase — they supplement the UI, they are not where the real content lives.",
      "slots": [],
      "variants": [
        {
          "name": "placement",
          "options": [
            "top",
            "bottom",
            "left",
            "right"
          ],
          "type": "enum",
          "default": "top"
        },
        {
          "name": "tone",
          "options": [
            "brand",
            "secondary",
            "accent",
            "info",
            "success",
            "warning",
            "danger"
          ],
          "type": "enum"
        },
        {
          "name": "open",
          "options": [],
          "type": "boolean"
        }
      ],
      "props": [
        {
          "name": "placement",
          "type": "'top' | 'bottom' | 'left' | 'right'",
          "required": false,
          "default": "top",
          "source": "variant"
        },
        {
          "name": "tone",
          "type": "'brand' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'danger'",
          "required": false,
          "source": "variant"
        },
        {
          "name": "open",
          "type": "boolean",
          "required": false,
          "source": "variant"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Extra classes merged onto the root (tailwind-variants resolves conflicts).",
          "source": "interface"
        },
        {
          "name": "tip",
          "type": "React.ReactNode",
          "required": true,
          "description": "The hint shown on hover or focus. A plain string renders through the CSS `data-tip` attribute; any richer node (formatted text, key/value rows) is rendered into a `.tooltip-content` bubble instead.",
          "source": "interface"
        },
        {
          "name": "children",
          "type": "React.ReactNode",
          "required": false,
          "description": "The trigger the tip describes — typically a button, link, or icon.",
          "source": "interface"
        }
      ],
      "schemaValidated": false,
      "examples": [
        "<Tooltip placement=\"top\">label</Tooltip>",
        "<Tooltip tip=\"checked in 3:00 PM\">\n  <button className=\"btn\">details</button>\n</Tooltip>",
        "<Tooltip placement=\"right\" tone=\"brand\" tip=\"room keys are ready\">\n  <button className=\"btn btn-primary\">continue</button>\n</Tooltip>"
      ],
      "dos": [
        "Keep the tip to a short phrase that adds context the trigger cannot show\non its own."
      ],
      "donts": [
        "Put essential content or actions inside a tip — it is hidden until hover\nand never reachable on touch."
      ]
    }
  ]
}
